思想
将两个有序的队列合并成一个大的有序的序列,反复操作,直到合并成一个有序的队列。
思路
一个大的无序队列,采用分治法进行排序。先将无序队列一分为二再一分为二,层层递归到只有两个数时,进行排序,然后再依次返回,在返回的时候,再次对两个有序子序列进行合并,然后层层递归合并,到最后只有一个有序的队列完毕。
此处盗图二张:
图片来源:
图解排序算法(四)之归并排序
实现
static void merge_conquer(int arry[], int left, int mid, int right, int *temp)
{
int l = left;
int r = mid + 1;
int i = 0;
for (i = 0; i < right; i++)
printf("%d ", arry[i]);
printf("\n%s, left = %d,right=%d\n",__func__,left, right);
i = 0;
while(l <= mid && r <= right) {
if (arry[l] <= arry[r]) {
temp[i++] = arry[l++];
} else {
temp[i++] = arry[r++];
}
}
while(l <= mid) {
temp[i++] = arry[l++];
}
while(r <= right) {
temp[i++] = arry[r++];
}
/*copy*/
i = 0;
while(left <= right)
arry[left++] = temp[i++];
}
static void merge_devide(int arry[], int left, int right, int *temp)
{
if (left < right) {
int mid = (left+right)/2;
merge_devide(arry, left, mid, temp); // devide left
merge_devide(arry, mid + 1, right, temp); // devide right
merge_conquer(arry, left, mid, right, temp); //conquer
}
}
/*
@function: merge_sort
@functional: merge sort
@ divide-and-conquer
*/
static void merge_sort(int arry[], int len)
{
int *temp = (int*)malloc(len*sizeof(int));
if (!temp) {
perror("malloc:");
return ;
}
merge_devide(arry, 0, len - 1, temp);
if (temp)
free(temp);
}
int main(void)
{
int arry[] = {13, 12, 5, 3, 14, 90, 0, 11, 23, 9, 15, 99, 100, 96,3};
int arry_len = sizeof(arry)/sizeof(arry[0]);
for (int i = 0; i < arry_len; i++)
printf("%d ", arry[i]);
printf("\n");
merge_sort(arry, arry_len);
for (int i = 0; i < arry_len; i++)
printf("%d ", arry[i]);
printf("\n");
return 0;
}
运行结果
./a.out
13 12 5 3 14 90 0 11 23 9 15 99 100 96 3
13
merge_conquer, left = 0,right=1
12 13 5
merge_conquer, left = 2,right=3
12 13 3
merge_conquer, left = 0,right=3
3 5 12 13 14
merge_conquer, left = 4,right=5
3 5 12 13 14 90 0
merge_conquer, left = 6,right=7
3 5 12 13 14 90 0
merge_conquer, left = 4,right=7
3 5 12 13 0 11 14
merge_conquer, left = 0,right=7
0 3 5 11 12 13 14 90 23
merge_conquer, left = 8,right=9
0 3 5 11 12 13 14 90 9 23 15
merge_conquer, left = 10,right=11
0 3 5 11 12 13 14 90 9 23 15
merge_conquer, left = 8,right=11
0 3 5 11 12 13 14 90 9 15 23 99 100
merge_conquer, left = 12,right=13
0 3 5 11 12 13 14 90 9 15 23 99 96 100
merge_conquer, left = 12,right=14
0 3 5 11 12 13 14 90 9 15 23 99 3 96
merge_conquer, left = 8,right=14
0 3 5 11 12 13 14 90 3 9 15 23 96 99
merge_conquer, left = 0,right=14
0 3 3 5 9 11 12 13 14 15 23 90 96 99 100
思考
/*copy*/
i = 0;
while(left <= right)
arry[left++] = temp[i++];
为何将临时内存的内容拷贝到原始数组中的时候,需要在合并的时候进行拷贝(也即是在函数 merge_conquer()里面完成),而不能在合并排序完成以后,最后拷贝一次即可?(从递归的角度来思考)