排序总结
Posted mychen06
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序总结相关的知识,希望对你有一定的参考价值。
稳定性排序:稳定性排序是指相等的元素相对位置不会发生改变。
以下介绍一系列排序算法:以非降序排列为序;
选择排序:遍历i,求[i,n)中的最小值,与A[i]交换;
时间复杂度O(N^2)
void selection_sort(vector<int>& num) { int len = num.size() ; for(int i = 0 ; i < len ; i++) { int mini = i ; for(int j = i + 1 ; j < len ; j++) { if(A[j] < A[mini]) mini = j ; } swap(A[mini] , A[i]); } }
冒泡排序:遍历 j in[0 , n-i) , i in [1 , n - 1], 如果A[j] > A[j +1] , 就交换。这样子每一次遍历都将最大的值放到A[n-i], 最好的情况是完全有序,不需要交换。 时间复杂度为O(N^2) ;
void bubble_sort(vector<int> &num) { for(int i = 1 ; i < n ; i++) for(int j = 0 ; j < n - i ; j++) { if(nums[j] > nums[j+1]) swap(nums[j] , nums[j+1]) ; } }
插入排序:数列分为已排序和未排序两部分,每一次从未排序的元素中选择一个插入到已排序部分中;当序列完全有序时,时间复杂度为O(N) ; 最坏时间复杂度为O(N^2), 平均时间复杂度为O(N^2) ;
void insert_sort(vector<int> &num)) { int n = num.size() ; for(int i = 1; i < n ; i++) { int key = num[i] , j = i - 1; while(j >= 0 && num[j] > key) { num[j + 1] = num[j] ; j-- ; } num[j + 1] = key ; } }
计数排序:统计每个数出现的次数,从小到大计算每个数出现的前缀和,利用出现次数的前缀和,从右往左的计算每个数的排名; 时间复杂度为O(N + W) ;
void counting_sort(vector<int> &num) { int maxn = INT_MIN, minn = INT_MAX ; for(auto n : num) { maxn = max(maxn , n) ; minn = min(minn , n) ; } vector<int> cnt(maxn - minn + 1 , 0) , res(num.size() , 0); for(auto n : num) cnt[n-minn]++ ; for(int i = 0 ; i <= maxn - minn ; i++) cnt[i] += cnt[i-1] ; for(int i = n - 1 ; i >= 0 ; i--) res[--cnt[num[i]]] = num[i] ; }
快速排序:选一个基准值,找到这个基准值在数列中的正确位置,然后再递归排序两部分数组;时间复杂度为O(NlogN) - O(N^2) , 实际运行效果要比时间复杂度为O(NlogN)的排序算法运行效果要好
int partion(vector<int> &num , int low , int high) { int pivot = num[low] ; while(low < high) { while(high > low && num[high] >= pivot ) high-- ; num[low] = num[high] ; while(low < high && nums[low] <= pivot) low++ ; num[high] = num[low] ; } num[low] = pivot ; return low ; } void quickSort(vector<int> &num , int low, int high) { if(low < high) { int pivot = partion(num , low , high) ; quickSort(num , low , pivot - 1) ; quickSort(num , pivot + 1 , high) ; } }
归并排序:1.将数列划分成两部分;2.递归地分别对两个子序列进行排序。3.合并两个子序列
归并排序的核心是如何合并两个子序列。时间复杂度O(NlogN),空间复杂度O(N).
void mergeSort(vector<int>& num , int l , int r) { int mid = l + (r - l ) / 2 ; mergeSort(num , l , mid) ; mergeSort(num , mid , r) ; int i = l , p = l , q = mid ; while(i < r) { if(p >= mid || (q < r && num[q] < num[p])) t[i++] = num[q++] ; else t[i++] = num[p++] ; } for(int j = l ; j < r ; j++) num[j] = t[j] ; }
归并排序还有一种迭代版的做法:每一次将数列以2^i大小划分成组,两两合并,i<<1;
void mergeSort(vector<int> &num , int l , int r) { int cur = 0 , len = num.size() ; for(int i = 1 ; i < len ; i<<= 1) { cur = 0 ; while(cur < len) { int l = cur , r = l + i ; cur += 2 * i ; merge(num , l , r , min(r+i , len)) ; } } } void merge(vector<int> &num , int l1 , int l2 , int r2 ) { int s = l1 , p = l1 , q = l2; while(s < r2) { if(p >= l2 || (q < r2 && num[q] < num[p])) t[s++] = num[q++] ; else t[s++] = num[p++] ; } }
归并排序可以求逆序对,也就是求(i < j && a[i] > a[j])的对数;
逆序对也可以用线段树,二分搜索树,树状数组来求,平均时间复杂度为O(NlogN);
桶排序:跟计数排序类似,跟值域有关,适用于值域较大,但分布比较均匀的情况,期望时间复杂度为O(N) , 空间复杂度为O(N) ;
桶排序就是将值域分成n组(桶),根据a[i]/n决定在哪一个桶中 , 对桶中的元素进行插入排序。
排序相关的STL:
sort(begin , end , cmp)
stable_sort(begin , end , cmp) ;
部分排序:将数列的前k小哥元素置于数列的前
k个位置,后面元素不保证顺序性 partial_sort(beging , begin + k , end , cmp) ;
以上是关于排序总结的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段