归并排序算法
1、算法思想
分治发自顶而下实现归并排序:
(1)分治法的三个步骤
设归并排序的当前区间是R[low..high],分治法的三个步骤是:
①分解:将当前区间一分为二,即求分裂点
②求解:递归地对两个子区间R[low..mid]和R[mid+1..high]进行归并排序;
③组合:将已排序的两个子区间R[low..mid]和R[mid+1..high]归并为一个有序的区间R[low..high]。
递归的终结条件:子区间长度为1(一个记录自然有序)。
(2)具体算法
void MergeSortDC(SeqList R,int low,int high)
{//用分治法对R[low..high]进行二路归并排序
int mid;
if(low<high){//区间长度大于1
mid=(low+high)/2; //分解
MergeSortDC(R,low,mid); //递归地对R[low..mid]排序
MergeSortDC(R,mid+1,high); //递归地对R[mid+1..high]排序
Merge(R,low,mid,high); //组合,将两个有序区归并为一个有序区
}
}//MergeSortDC
(3)算法MergeSortDC的执行过程 (略)
2、算法分析
(1)稳定性
归并排序是一种稳定的排序。
(2)存储结构
可用顺序存储结构。也易于在链表上实现。
(3)时间复杂度
对长度为n的文件,需进行 趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。
(4)空间复杂度
需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序。
注意:
若用单链表做存储结构,很容易给出就地的归并排序
1 #include <iostream>
2 #include <windows.h>
3
4 using namespace std;
5
6 void merge(int a[],int low,int mid,int high)
7 {
8 int n1,n2,k,i,j,b[100],c[100];
9 n1 = mid - low + 1;
10 n2 = high - mid;
11 //复制数组的前后部分到临时数组
12 for(i = 0;i < n1;i++)
13 b[i] = a[low+i];
14 for(i = 0;i < n2;i++)
15 c[i] = a[mid+i+1];
16 //把后面的元素设置到很大
17 b[n1] = 999999;
18 c[n2] = 999999;
19 //逐个扫描两个数组然后放到相应的位置
20 for(i = 0,j = 0,k = low;k <= high;k++)
21 {
22 if(b[i] <= c[j])
23 a[k] = b[i++];
24 else
25 a[k] = c[j++];
26 }
27 return;
28 }//end of merge
29
30 void mergeSort(int a[],int low,int high)
31 {
32 while(low < high)//区间长度大于1时才继续分解
33 {
34 int mid;
35 mid = (low+high)/2;
36 mergeSort(a,low,mid);//对前半部分进行排序
37 mergeSort(a,mid+1,high);//对后半部分进行排序
38 merge(a,low,mid,high);//合并
39 return; //开始的时候这里漏了return而错了很久
40 }
41 }
42
43 int main(int argc,char **argv)
44 {
45 int a[] = {2,1,4,5,2,6,1};
46 mergeSort(a,0,6);
47 for(int i=0;i<7;i++)
48 cout<<a[i]<<" ";
49 cout<<endl;
50 return 0;
51 }