在程序设计中经常会用到很多下列的排序算法,这里将他们分成三类:
1. 选择排序、插入排序、冒泡排序
2. 堆排序、归并排序、快速排序
3. 计数排序、基数排序、桶排序
还有很多排序算法,可以参考算法导论中的章节。
1. 离散化
排序算法的第一个应用就是离散化。通俗的讲,“离散化”就是把无穷大的集合中若干个元素映射为有限集合以便于统计的放法,有个简单的例子:我们可以将一个数组A中的元素进行排序并去掉重复的数值,得到有序数组B,那么B数组的下标i与B[i]之间建立了映射关系。数组A中映射后的数值即为数组B的下标,而数组B的下标代表的A中的元素即为B[i]。
template<typename T> void discrete(vector<T> &arr){ sort(arr.begin(), arr.end()); erase(unique(arr.begin(), arr.end()), arr.end()); } 或者手写去重过程 template<typename T> void discrete(vector<T>& arr){ sort(arr.begin(), arr.end()); int l = 0, r = 0; for(; r < arr.size(); ){ if(l == 0 || arr[r] != arr[r - 1]) arr[l ++] = arr[r]; } erase(arr.begin() + l, arr.end()); } int query(int x){ return lower_bound(arr.begin(), arr.end(), x) - arr.begin(); }
2. 中位数
我们可以利用排序的思想找到乱序数组中的中位数。
3. 第K大的数
中位数是一种比较特殊的第K大的数,当然我们同样可以通过排序的思想进行查找
4. 逆序对
序列A中对于任意的$ile j,存在A[i]ge A[j]$,就是一个逆序对,统计一个数组中这样的数字的对数也是很有用的。
template<typename T> int merge(vector<T> &arr, int beg, int end){ if(end == beg) return 0; int l = beg, mid = beg + end >> 1; int r = mid + 1; int ans = merge(arr, l, mid) + merge(arr, mid + 1, end); vector<T> t(end - beg + 1); int idx = 0; while(l <= mid && r <= end){ if(arr[l] <= arr[r]) t[idx ++] = arr[l ++]; else t[idx ++] = arr[r ++], ans += mid - l + 1; } while(l <= mid) t[idx ++] = arr[l ++]; while(r <= end) t[idx ++] = arr[r ++]; for(int i = 0; i < t.size(); ++i) arr[l + i] = t[i]; }