分治算法之归并排序
2016-06-09 18:13
429 查看
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
基本思想
将待排序序列R[0…n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。
综上可知:
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
我们先来考虑第二步,如何合并?
在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。为了方便描述,我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中。最后将各段中余下的部分直接复制到R2中。经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。
算法分析
归并排序算法的性能
归并排序和堆排序、快速排序的比较
(1) 若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。
(2) 若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。
(3) 若从平均情况下的排序速度考虑,应该选择快速排序。
伪代码
4.C++代码
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
基本思想
将待排序序列R[0…n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复进行下去,最后得到一个长度为n的有序序列。
综上可知:
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
我们先来考虑第二步,如何合并?
在每次合并过程中,都是对两个有序的序列段进行合并,然后排序。这两个有序序列段分别为 R[low, mid] 和 R[mid+1, high]。先将他们合并到一个局部的暂存数组R2中,带合并完成后再将R2复制回R中。为了方便描述,我们称 R[low, mid] 第一段,R[mid+1, high] 为第二段。每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中。最后将各段中余下的部分直接复制到R2中。经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。
算法分析
归并排序算法的性能
归并排序和堆排序、快速排序的比较
(1) 若从空间复杂度来考虑:首选堆排序,其次是快速排序,最后是归并排序。
(2) 若从稳定性来考虑,应选取归并排序,因为堆排序和快速排序都是不稳定的。
(3) 若从平均情况下的排序速度考虑,应该选择快速排序。
伪代码
merge_sort(A,p,q,r) n1=q-p+1 n2=r-q let L[1..n1+1]和R[1..n2+1]be new arrays for i=1 to n1 L[i]=A[p+i-1] for j=1 to n2 R[j]=A[q+j] L[n1+1]=∞ R[n2+1]=∞ i=1 j=1 for k=p to r if L[i]<<R[j] A[k]=L[i] i=i+1 else A[k]= R[j] j=j+1 merge_sort(A,p,r) if p<r q=⌊(p+r)/2⌋ merge_sort(A,p,q) merge_sort(A,q+1,r) merge(A,p,q,r)
4.C++代码
#include<iostream> using namespace std; template<typename T> void merge(T *a, int p, int q, int r) { int i, j, k=0; int n1 = q - p + 1; int n2 = r - q; T *L = new T[n1]; T *R = new T[n2]; for (i = 0; i < n1; i++) L[i] = a[p+i]; for (j = 0; j < n2; j++) R[j] = a[q + 1 + j]; i = 0; j = 0; while (i < n1 && j < n2) { if (L[i] < R[j]) { a[p + k] = L[i]; i++; } else { a[p + k] = R[j]; j++; } k++; } while (i < n1) { a[p + k] = L[i]; i++; k++; } while (j < n2) { a[p + k] = R[j]; j++; k++; } delete [] L; delete [] R; } template<typename T> void merge_sort(T *a, int p, int r) { if (p < r) { int q = (p + r) / 2; merge_sort(a, p, q); merge_sort(a, q + 1, r); merge(a, p, q, r); } } template <typename T> void printf_data(T *a, int length) { for (int i = 0; i < length; i++) { cout << a[i] << " "; } cout << endl; } int main() { int a_int[10] = { 1, 3, 6, 5, 9, 8, 4, 2, 0, 7 }; float a_float[10] = { 1.1, 1.3, 1.5, 1.6, 1.8, 1.9, 1.4, 1.2, 1.0, 1.7 }; printf_data(a_int, 10); printf_data(a_float, 10); merge_sort(a_int, 0, 9); merge_sort(a_float, 0, 9); printf_data(a_int, 10); printf_data(a_float, 10); }
相关文章推荐
- JavaScript演示排序算法
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- 用VBScript写合并文本文件的脚本
- oracle列合并的实现方法
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 使用BAT一句话命令实现快速合并JS、CSS
- SQL 合并多行记录的方法总汇
- C#实现简单合并word文档的方法
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- C#自适应合并文件的方法
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- Node.js实现JS文件合并小工具
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法