C语言递归实现归并排序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q1075355798/article/details/79842638

思想

将两个有序的队列合并成一个大的有序的序列,反复操作,直到合并成一个有序的队列。

思路

一个大的无序队列,采用分治法进行排序。先将无序队列一分为二再一分为二,层层递归到只有两个数时,进行排序,然后再依次返回,在返回的时候,再次对两个有序子序列进行合并,然后层层递归合并,到最后只有一个有序的队列完毕。

此处盗图二张:
这里写图片描述
这里写图片描述

图片来源:
图解排序算法(四)之归并排序

实现

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()里面完成),而不能在合并排序完成以后,最后拷贝一次即可?(从递归的角度来思考)

参考

图解排序算法(四)之归并排序

猜你喜欢

转载自blog.csdn.net/q1075355798/article/details/79842638