对比快速排序来理解归并排序。
有时经常讲归并排序和快速排序记混乱,因为两者都用到了分治法。其实两者的不同之处非常明显。
快速排序:“先治后分”,
void quickly_sort(int arr[], int low, int high) {
if (low < high) {
// 先治后分
int pivot = _qucikly_sort(arr, low, high); //治
quickly_sort(arr, low, pivot-1); //分
quickly_sort(arr, pivot + 1, high); //分
}
}
归并排序:“先分后治”。
void merge_sort_up2down(int a[], int start, int end) {
if(a==NULL || start >= end)
return ;
// 先分后治
int mid = (end + start)/2;
merge_sort_up2down(a, start, mid); // 分
merge_sort_up2down(a, mid+1, end); // 分
merge(a, start, mid, end); // 治
}
“分”的过程用递归实现起来分简单,主要是理解两者的“治”。
快速排序的根本处理是:如何在选定一个元素后,将这个元素放在合适的位置,使得元素左边都是小于这个元素的,右边都是大于这个元素的(挖坑填坑法):int _qucikly_sort(int arr[], int low, int high) {
int pivot = arr[low]; //挖第一个坑,把“萝卜”放进篮子
while(low<high) { //开始循环挖坑填坑
//如果low等于high,说明找坑的过程中,找到了上一次挖的坑,因此可以停止了
while(low<high && arr[high]>=pivot) //从右边往左边找填坑的元素(比pivot小的元素)。 2,4,6的过程
--high;
arr[low] = arr[high]; //将找到之后,挖出来,填到左边的坑里
while(low<high && arr[low]<=pivot) //从左边往右边找填坑的(比pivot大的元素)。3,5的过程
++low;
arr[high] = arr[low];//找到之后,填到右边的坑里
}
arr[low] = pivot; //篮子里的“萝卜”填到坑里
return low;//返回这个坑的位置,作为分而治之的中轴
}
归并排序的根本处理是:如何将两个有序的数组,合并成一个有序数组(申请一个数组,大小是两个有序数组(原数组的两个子数组)的大小之和,遍历比较两个数组的元素,按大小放进新数组,将新数组替换原数组的子数组即可):
void merge(int a[], int start, int mid, int end) {
int *tmp = (int *)malloc((end-start+1)*sizeof(int)); // tmp是汇总2个有序区的临时区域
int i = start; // 第1个有序区的索引
int j = mid + 1; // 第2个有序区的索引
int k = 0; // 临时区域的索引
while(i <= mid && j <= end) {
if (a[i] <= a[j])
tmp[k++] = a[i++];
else
tmp[k++] = a[j++];
}
while(i <= mid)
tmp[k++] = a[i++];
while(j <= end)
tmp[k++] = a[j++];
// 将排序后的元素,全部都整合到数组a中。
for (i = 0; i < k; i++)
a[start + i] = tmp[i];
free(tmp);
}
这样,都过简单的代码对比,就可以很简单的分清楚两者的关系与不同。