通过一张图了解什么是归并排序
归并排序实际上运用了“分”和“治”的思想。怎样理解“分”和“治”?
分:就是将一个大的数组逐渐分解为多个最大长度不超过2的数组。
治:就是将这些小的数组依次合并排序,最后变成一个最大长度且有序的数组。
通过上面的归并排序的图解能够很自然的想到要实现这个排序需要用到递归。
首先讲怎样进行"分"的操作:
1 void mergeSort(int *nums,int low,int high){ 2 int mid = (low+high)/2; 3 if(low<high) { 4 mergeSort(nums,low,mid); 5 mergeSort(nums,mid+1,high); 6 merge(nums,low,mid,high);//关于"治"的函数 7 } 8 }
怎样理解这段代码?为了便于叙述,建立数组
7 | 2 | 5 | 3 |
执行上面的mergeSort函数:
1.第一次调用该方法,初始数据为:
1 nums[4] = {7,2,5,3}; 2 low = 0; 3 high = 3;
2.得到mid=(0+3)/2 = 1;由于low
1 mergeSort(nums,low,mid); //此时的low=0,mid=1。令此函数为A 2 mergeSort(nums,mid+1,high);//此时的miid+1=2,high=3。令此函数为B 3 merge(nums,low,mid,high);
3.执行函数A,得到mid=(0+1)/2=0;由于low
1 mergeSort(nums,low,mid); //此时的low=0,mid=0。令此函数为C 2 mergeSort(nums,mid+1,high);//此时的miid+1=1,high=1。令此函数为D 3 merge(nums,low,mid,high);//令此函数为E
4.执行函数C,得到mid=(0+0)/2=0;由于low=high,所以函数C执行完毕,返回到步骤3执行函数D。
5.执行函数D,得到mid=(1+1)/2=1;由于low=high,所以函数D执行完毕,返回到步骤3执行函数E(就到了"治"的阶段)。
6.执行完步骤5,返回到步骤2执行函数B。
7.执行函数B,得到mid= (2+3)/2=2;由于low
1 mergeSort(nums,low,mid);// 此时的low=2,mid=2。令此函数为F 2 mergeSort(nums,mid+1,high);// 此时的miid+1=3,high=3。令此函数为G 3 merge(nums,low,mid,high);// 令此函数为H
8.执行函数F,得到mid=(2+2)/2=2;由于low=high,所以函数F执行完毕,返回到步骤7执行函数G。
9.执行函数G,得到mid=(3+3)/2= 3;由于low=high,所以函数G执行完毕,返回步骤7执行函数H("治")。
10.执行完函数G,返回步骤2执行函数merge。
再讲怎样进行"治"的操作:
1 void merge(int *nums,int low,int mid,int high) { 2 int copyArray[numsSize],flag,i,j,q;//numsSize为数组的长度 3 for(q = 0;q//将原数组复制到新数组 4 copyArray[q] = nums[q]; 5 } 6 for(i = low,j = mid+1,flag=low;i<=mid && j<=high;) { 7 if(copyArray[j]<copyArray[i]){ 8 nums[flag++] = copyArray[j++]; 9 }else { 10 nums[flag++] = copyArray[i++]; 11 } 12 } 13 while(i<=mid) { 14 nums[flag++] = copyArray[i++]; 15 } 16 while(j<=high) { 17 nums[flag++] = copyArray[j++]; 18 } 19 }
在执行mergeSort函数的过程中,步骤5第一次执行了merge函数。这里着重对第一次执行merge函数做一个详细的解释。
初始数据
1 nums[4] = {7,2,5,3}; 2 copyArray[4] = {7,2,5,3}; 3 low = 0; 4 mid = 1; 5 high = 1;
执行循环
1 for(i = low,j = mid+1,flag=low;i<=mid && j<=high;) { 2 if(copyArray[j]<copyArray[i]){ 3 nums[flag++] = copyArray[j++]; 4 }else { 5 nums[flag++] = copyArray[i++]; 6 } 7 }
初始i、j、flag的值为
1 i = 0; 2 j = 1; 3 flag = 0;
因为
1 copyArray[0]>copyArray[1]//copyArray[0]=7 copyArray[1] = 2
所以有
1 nums[0] = 2; 2 flag++ = 1;//右边的值是flag++以后的值 3 j++ = 2;
因为
1 high = 1; 2 j = 2;
不满足循环条件
1 j<=high
故for循环终止。接着执行
1 while(i<=mid) { 2 nums[flag++] = copyArray[i++]; 3 } 4 while(j<=high) { 5 nums[flag++] = copyArray[j++]; 6 }
由于i<=mid,故执行第一个while循环
1 nums[1] = 7 //copyArray[0] = 7 2 i++ = 1;
因为i>mid,循环结束,merge函数调用结束。此时的数组变成
1 nums[4] = {2,7,5,3};
第二次和第三次merge函数调用过程类似。