归并排序
1 void Merge(int a[], int b[], int low, int mid, int high)
2 {
3 int k = low;
4 int begin1 = low;
5 int end1 = mid;
6 int begin2 = mid + 1;
7 int end2 = high;
8 while(begin1 <= end1 && begin2 <= end2)
9 {
10 if(a[begin1] <= a[begin2])
11 b[k++] = a[begin1++];
12 else
13 b[k++] = a[begin2++];
14 }
15 if(begin1 <= end1)
16 for(int q = begin1; q <= end1; q++)
17 b[k++] = a[q];
18 else
19 for(int q = begin2; q <= end2; q++)
20 b[k++] = a[q];
21 }
22
23 void MergePass(int a[], int b[], int seg, int size)
24 {
25 int seg_start_ind = 0;
26 while(seg_start_ind <= size - 2 * seg) //#size - 2 * seg的意思是满足可两两归并的最低临界值#%
27 {
28 Merge(a, b, seg_start_ind, seg_start_ind + seg - 1, seg_start_ind + seg * 2 - 1);
29 seg_start_ind += 2 * seg;
30 }
31 //#如果一段是正好可归并的数量而另一段则少于正好可归并的数量#%
32 if(seg_start_ind + seg < size)
33 Merge(a, b, seg_start_ind, seg_start_ind + seg - 1, size - 1);
34 else
35 for(int j = seg_start_ind; j < size; j++) //#如果只剩下一段或者更少的数量#%
36 b[j] = a[j];
37 }
38
39 void MergeSort(int a[], int size)
40 {
41 int* temp = new int[size];
42 int seg = 1;
43 while(seg < size)
44 {
45 MergePass(a, temp, seg, size);
46 seg += seg;
47 MergePass(temp, a, seg, size);
48 seg += seg;
49 }
50 }
维基百科上的一段代码,发现维基百科上面的程序不是很好理解,但是鲁棒性都特别高。
增加和很多判断语句,一般是先完成程序的基本算法即骨架,再考虑特殊的输入情况,添加对特殊情况的判别。
先看一段好理解的代码:
1 void Merge(int R[],int low,int m,int high)
2 {
3 //将两个有序的子文件R[low..m)和R[m+1..high]归并成一个有序的
4 //子文件R[low..high]
5 int i=low,j=m+1,p=0; //置初始值
6 int *R1; //R1是局部向量,若p定义为此类型指针速度更快
7 R1 = new int;
8
9 if(!R1) //申请空间失败
10 std::cout<<"Error(Insufficient memory available!)"<<std::endl;
11 while(i<=m&&j<=high) //两子文件非空时取其小者输出到R1[p]上
12 R1[p++]=(R[i]<=R[j])?R[i++]:R[j++];
13
14 while(i<=m) //若第1个子文件非空,则复制剩余记录到R1中
15 R1[p++]=R[i++];
16
17 while(j<=high) //若第2个子文件非空,则复制剩余记录到R1中
18 R1[p++]=R[j++];
19
20 for(p=0,i=low;i<=high;p++,i++)
21 R[i]=R1[p];//归并完成后将结果复制回R[low..high]
22 }
这段代码的功能是将两个有序的序列合并成一个有序的序列。(用了new的话,不用delete吗)
在这里有一句题外话,一直以为当执行三元判断运算时后面的两个操作数是都被执行的,看了这个程序才知道只执行被选中的那个。在这里是只执行R[i++]。这个特性可以使之完全胜任代替非此即彼的if-else(非此即彼)。
1 void MergeSortDC(int R[],int low,int high)
2 {
3 //用分治法对R[low..high]进行二路归并排序
4 int mid;
5 if(low<high)
6 { //区间长度大于1
7 mid=(low+high)/2; //分解
8 MergeSortDC(R,low,mid); //递归地对R[low..mid]排序
9 MergeSortDC(R,mid+1,high); //递归地对R[mid+1..high]排序
10 Merge(R,low,mid,high); //组合,将两个有序区归并为一个有序区
11 }
12 }
将数列分成两部分本别进行排序(8~9),将排好序的数列进行合并(10)。分开排序然后合并。