当前位置:   article > 正文

归并排序的非递归实现

归并排序的非递归实现

一、归并排序

归并排序是一种很好的排序算法:

①时间复杂度稳定为nlogn

②排序具有稳定性

但是传统的归并排序是用递归实现的,递归就会占用大量的栈空间,我们知道,在算法竞赛中对栈空间的要求十分严格,大部分评测机的栈空间限制只有2MB,稍微差一点的可能只有1MB。

因此为了节约栈空间,我们能不能在不牺牲归并排序性能的前提下,使用非递归的方法实现归并排序呢?

二、递归版归并排序的实现

递归实现的归并排序其实就是做了两件事:

“分解”:将序列每次折半划分(递归实现)

“归并”:将划分后的序列两两合并后排序

算法实现:

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100010;
  4. int n;
  5. int a[N]; //待排序数组
  6. int t[N]; //辅助空间
  7. //归并
  8. void Merge(int a[], int t[], int l, int mid, int r)
  9. {
  10. int i = l, j = mid + 1, k = l; //三个指针
  11. while(i <= mid && j <= r)
  12. {
  13. if(a[i] <= a[j]) t[k ++] = a[i ++];
  14. else t[k ++] = a[j ++];
  15. }
  16. while(i <= mid) t[k ++] = a[i ++];
  17. while(j <= r) t[k ++] = a[j ++];
  18. for(int i = l;i <= r;i ++) a[i] = t[i];
  19. }
  20. //分解
  21. void MergeSort(int a[], int t[], int l, int r)
  22. {
  23. if(l == r) return ;
  24. int mid = l + r >> 1;
  25. MergeSort(a, t, l, mid), MergeSort(a, t, mid + 1, r); //递归分解,每次将序列分解为原来的一半
  26. Merge(a, t, l, mid, r);
  27. }
  28. int main ()
  29. {
  30. scanf("%d", &n);
  31. for(int i = 0;i < n;i ++) scanf("%d", &a[i]);
  32. MergeSort(a, t, 0, n - 1);
  33. if(n) printf("%d", a[0]);
  34. for(int i = 1;i < n;i ++) printf(" %d", a[i]);
  35. return 0;
  36. }

三、非递归版归并排序的实现

相比较于递归方法,非递归方法与之不同点就是:

在递归方法中,我们通过递归的方法递归到最底层,然后进行归并排序;而在非递归方法中,我们直接把数组分成两个数一组进行排序,然后再四个数一组进行排序,以此类推直到全部有序

举个栗子:

算法实现:

算法核心是两层循环:

第一层:循环有序序列的长度,当有序序列长度大于a[]长度,说明已经排序完成,break;

第二层:枚举a[]的开头到结尾,将长度为length的序列归并为长度为length * 2的有序列,完成归并

  1. #include <iostream>
  2. #include <math.h>
  3. using namespace std;
  4. const int N = 100010;
  5. int a[N]; //待排序序列
  6. int t[N]; //辅助空间
  7. //归并a[l ~ r - 1]和a[r ~ n]
  8. void merge(int a[], int t[], int l, int r, int n, int N)
  9. {
  10. int i = l, j = r, k = l; //三个指针
  11. while(i <= r - 1 && j <= n && i < N && j < N)
  12. if(a[i] <= a[j]) t[k ++] = a[i ++];
  13. else t[k ++] = a[j ++];
  14. while(i <= r - 1 && i < N) t[k ++] = a[i ++];
  15. while(j <= n && j < N) t[k ++] = a[j ++];
  16. for(int i = l;i <= n && i < N;i ++) a[i] = t[i]; //将有序的t[]复制回a[]
  17. }
  18. void MergeSort(int a[], int N )
  19. {
  20. int length = 1; //长度为1的序列是有序的序列
  21. while( length < N ) //循环已经排好序的子序列长度
  22. {
  23. int len = length * 2;
  24. //从序列开头到结尾,将长度为length的有序序列归并为长度为length * 2的序列
  25. for(int i = 0;i < N;i += len)
  26. {
  27. merge(a, t, i, i + length, i + len - 1, N);
  28. }
  29. length *= 2; //每次把已经排好序的序列长度乘2
  30. }
  31. }
  32. int main ()
  33. {
  34. int n;
  35. scanf("%d", &n);
  36. for(int i = 0;i < n;i ++) scanf("%d", &a[i]);
  37. MergeSort(a, n);
  38. if(n) printf("%d", a[0]);
  39. for(int i = 1;i < n;i ++) printf(" %d", a[i]);
  40. return 0;
  41. }

写在最后:

感谢您观看我的文章,如果您有更巧妙的思路和想法,或者发现本文章有些许错误的话,欢迎您在评论区批评指正~

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号