归并排序(O(n)辅助空间)与原地递归排序(O(1)辅助空间)
2017-09-15 15:45
1821 查看
归并排序
归并排序是将一个序列划分为同样大小的两个子序列,然后对两个子序列分别进行排序,最后进行合并操作,将两个子序列合成有序的序列.在合成的过程中,一般的实现都需要开辟一块与原序列大小相同的空间,以进行合并操作,所以我们需要最大O(n)的辅助空间用于存储合并序列。下面是归并排序的过程。原地归并排序
原地递归排序的步骤与递归排序一样,都是划分成子序列然后合并子序列,但在实现合并子序列的时候使用了手摇算法实现了序列的合并,可以做到O(1)的辅助空间,但是理论上合并长度为n和m的子序列最坏的复杂度为2*n*m,所以原地归并排序实际意义并不大,但是也可以给我们进行参考。手摇算法
其实手摇算法的思想很简单,但我口才不好,只能用实际演示给你们看:假如要将序列1 2 3 4 5的4 5提到1 2 3前面
-> 1 2 3 4 5 原数组
-> 3 2 1 5 4 O(n)的时间将1 2 3翻转,4 5翻转
-> 4 5 1 2 3 O(n)的时间再将数组翻转一次
这时候我们可以看到4 5已经在1 2 3的前面了。我们可以清楚地看到每个数都被交换了2次,所以手摇算法的时间复杂度是2*(n+m)
原地归并算法的实现
我们已经知道了什么是手摇算法,这时候我们可以来演示一下怎么合并两个排好序的序列:1. 1 3 5 2 4 6 这时的l=0,m=3,r=6,[l,m)是一个序列[m,r)是一个序列,子序列都在list数组里面
2. 1 3 5 2 4 6 比较list[l]和list[m]的大小
3. 当list[l] <= list[m]的时候l++,重复2步骤,当list[l] > list[m]或者l >= m时往下走
4. 1 3 5 2 4 6 这时的l = 1,m = 3,r = 6 再次比较list[l]和list[m]的大小
5. 当list[l] > list[m]的时候m++,重复4步骤并且使用move记录重复次数,当list[l] <= list[m]或者m >= r时往下走
6. 1 3 5 2 4 6 这时的l = 1,m = 4,r = 6
7. 这时候我们可以保证[m-move,m)的序列比list[l]小,所以我么可以使用手摇算法交换[l,m-move)和[m-move,m)的顺序,然后l+=move,因为这时候3的位置在l+move处。
8. 1 2 3 5 4 6 这时候l = 2,m = 4,r = 6,我们重复2步骤继续交换,直到排好顺序。
c++代码实现归并排序和原地归并排序
template<class T> class MergeSort { public: enum Type { On,O1 //归并排序的辅助空间复杂度 }; void Sort(T *list, int size, Type t = On) { if (t == On)MergeOn(list, 0, size); else MergeO1(list, 0, size); } private: void MergeSortOn(T *list, int l,int m, int r) {//[l,m),[m,r) T *a = new T [r - l + 1]; int index = 0,mid = m,s=l; while (l < mid && m < r) { if (list[l] < list[m])a[index++] = list[l++]; else a[index++] = list[m++]; } while (l < mid)a[index++] = list[l++]; while (m < r)a[index++] = list[m++]; for (int i = s, j = 0; i < r; i++, j++)list[i] = a[j]; delete 8ce8 []a; } void MergeOn(T *list,int l,int r){//[l,r) if (l + 1 >= r)return; int m = (l + r) / 2; MergeOn(list, l, m); MergeOn(list, m, r); MergeSortOn(list, l, m, r); } void swap(T& a, T& b) { T c = a; a = b; b = c; } void reverse(T *list, int l, int r) {//[l,r) r--; while (l < r)swap(list[l++], list[r--]); } void hand(T *list, int l, int m, int r) {//手摇算法 reverse(list, l, m); reverse(list, m, r); reverse(list, l, r); } void MergeSortO1(T *list, int l, int m, int r) { while (l < m && m < r) { while (l < m && list[l] <= list[m]) l++; int move = 0; while (m < r && list[l] > list[m])move++, m++; hand(list, l, m - move, m); l += move; } } void MergeO1(T *list, int l,int r) {//[l,r) if (l + 1 >= r)return; int m = (l + r) / 2; MergeO1(list, l, m); MergeO1(list, m, r); MergeSortO1(list, l, m, r); } };
相关文章推荐
- 数组的归并排序(经典实现:使用Ο(n)的辅助空间,递归)
- 数组的归并排序(不使用辅助空间,递归)
- 排序第六章:归并排序(递归调用)
- 归并排序与原地归并排序
- STL源码分析《3》----辅助空间不足时,如何进行归并排序
- 排序——归并排序(递归实现+迭代实现 )
- 5.比较排序之归并排序(非递归)
- STL源码分析《3》----辅助空间不足时,如何进行归并排序
- 数组的归并排序(不使用辅助空间,循环)
- 归并排序(递归和非递归)和自然合并排序
- 桶排序 C# 0(1)的辅助空间,o(n)的时间复杂度进行排序,数据量有上万条。
- 某公司有几万名员工,请完成一个时间复杂度为O(n)的算法对该公司员工的年龄作排序,可使用O(1)的辅助空间
- 快速排序、归并排序的递归、非递归实现
- 排序的辅助空间问题
- 无聊写排序之 ---- 归并排序(MergeSort) 递归实现
- LintCode刷题系列:数组排序--归并排序 递归
- 题目:某公司有几万名员工,请完成一个时间复杂度为O(n)的算法对该公司员工的年龄作排序,可使用O(1)的辅助空间。
- 给定一个数组,该数组存贮R,G,B三种字符,将该数组按RGB顺序排序,不能使用辅助内存空间,且只能遍历数组一次。
- 归并排序、自然排序(递归、分治)
- RGB排序,一个字符串,里面只有三种字符R G B,所有的R都在G的前面,所有的G都在B的前面。将给定字符串按照此规律排序。要求不允许用辅助空间,复杂度控制在O(N)。