赞
踩
一、归并排序
归并排序是一种很好的排序算法:
①时间复杂度稳定为nlogn
②排序具有稳定性
但是传统的归并排序是用递归实现的,递归就会占用大量的栈空间,我们知道,在算法竞赛中对栈空间的要求十分严格,大部分评测机的栈空间限制只有2MB,稍微差一点的可能只有1MB。
因此为了节约栈空间,我们能不能在不牺牲归并排序性能的前提下,使用非递归的方法实现归并排序呢?
二、递归版归并排序的实现
递归实现的归并排序其实就是做了两件事:
①“分解”:将序列每次折半划分(递归实现)
②“归并”:将划分后的序列两两合并后排序
算法实现:
- #include <iostream>
-
- using namespace std;
-
- const int N = 100010;
-
- int n;
- int a[N]; //待排序数组
- int t[N]; //辅助空间
-
- //归并
- void Merge(int a[], int t[], int l, int mid, int r)
- {
- int i = l, j = mid + 1, k = l; //三个指针
- while(i <= mid && j <= r)
- {
- if(a[i] <= a[j]) t[k ++] = a[i ++];
- else t[k ++] = a[j ++];
- }
-
- while(i <= mid) t[k ++] = a[i ++];
- while(j <= r) t[k ++] = a[j ++];
- for(int i = l;i <= r;i ++) a[i] = t[i];
- }
-
- //分解
- void MergeSort(int a[], int t[], int l, int r)
- {
- if(l == r) return ;
- int mid = l + r >> 1;
- MergeSort(a, t, l, mid), MergeSort(a, t, mid + 1, r); //递归分解,每次将序列分解为原来的一半
-
- Merge(a, t, l, mid, r);
- }
-
- int main ()
- {
- scanf("%d", &n);
- for(int i = 0;i < n;i ++) scanf("%d", &a[i]);
-
- MergeSort(a, t, 0, n - 1);
-
- if(n) printf("%d", a[0]);
- for(int i = 1;i < n;i ++) printf(" %d", a[i]);
-
- return 0;
- }
三、非递归版归并排序的实现
相比较于递归方法,非递归方法与之不同点就是:
在递归方法中,我们通过递归的方法递归到最底层,然后进行归并排序;而在非递归方法中,我们直接把数组分成两个数一组进行排序,然后再四个数一组进行排序,以此类推直到全部有序。
举个栗子:
算法实现:
算法核心是两层循环:
第一层:循环有序序列的长度,当有序序列长度大于a[]长度,说明已经排序完成,break;
第二层:枚举a[]的开头到结尾,将长度为length的序列归并为长度为length * 2的有序列,完成归并
- #include <iostream>
- #include <math.h>
-
- using namespace std;
-
- const int N = 100010;
-
- int a[N]; //待排序序列
- int t[N]; //辅助空间
-
- //归并a[l ~ r - 1]和a[r ~ n]
- void merge(int a[], int t[], int l, int r, int n, int N)
- {
- int i = l, j = r, k = l; //三个指针
- while(i <= r - 1 && j <= n && i < N && j < N)
- if(a[i] <= a[j]) t[k ++] = a[i ++];
- else t[k ++] = a[j ++];
-
- while(i <= r - 1 && i < N) t[k ++] = a[i ++];
- while(j <= n && j < N) t[k ++] = a[j ++];
-
- for(int i = l;i <= n && i < N;i ++) a[i] = t[i]; //将有序的t[]复制回a[]
- }
-
- void MergeSort(int a[], int N )
- {
- int length = 1; //长度为1的序列是有序的序列
- while( length < N ) //循环已经排好序的子序列长度
- {
- int len = length * 2;
- //从序列开头到结尾,将长度为length的有序序列归并为长度为length * 2的序列
- for(int i = 0;i < N;i += len)
- {
- merge(a, t, i, i + length, i + len - 1, N);
- }
- length *= 2; //每次把已经排好序的序列长度乘2
- }
- }
-
- int main ()
- {
- int n;
- scanf("%d", &n);
- for(int i = 0;i < n;i ++) scanf("%d", &a[i]);
-
- MergeSort(a, n);
-
- if(n) printf("%d", a[0]);
- for(int i = 1;i < n;i ++) printf(" %d", a[i]);
-
- return 0;
- }
写在最后:
感谢您观看我的文章,如果您有更巧妙的思路和想法,或者发现本文章有些许错误的话,欢迎您在评论区批评指正~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。