导航

归并排序

Posted on 2018-08-22 11:03  困或  阅读(183)  评论(0编辑  收藏  举报

1.算法说明

  [1]归并算法,指的是将两个已经排序的序列合并成一个序列的操作。

  [2]该算法采用的是分治法思想。

2.算法代码

#include <stdlib.h>
#include <stdio.h>

#define ARRAY_LEN 8

static void print_array(int *array, int len)
{
    int i;

    for(i=0; i<len; i++){
        printf("%d ", array[i]);
    }

    printf("\n");
}

/*排序start到end的元素*/
static void merge(int array[], int start, int middle, int end)
{
    int i,j,k;
    int temp_array[ARRAY_LEN];   //temp_array的作用就是把排序好序列放到此上面,然后再拷贝给array。

    i = start;
    j = middle + 1;
    k = start;

    while(i != middle + 1 && j != end + 1){
        if(array[i] > array[j])
            temp_array[k++] = array[j++];
        else
            temp_array[k++] = array[i++];
    }

    while(i != middle + 1)
        temp_array[k++] = array[i++];

    while(j != end + 1)
        temp_array[k++] = array[j++];

    for(i=start; i<=end; i++)
        array[i] = temp_array[i];
}

static void merge_sort(int array[], int start, int end, int dir)
{
    int middle;

    if(start < end){
        middle = start + (end - start) / 2;

        merge_sort(array, start, middle, -1);
        merge_sort(array, middle + 1, end, 1);
        merge(array, start, middle, end);

        printf("merge, dir:%-2d      :", dir);
        print_array(array, 8);
    }
}

int main()
{
    int array[ARRAY_LEN] = {8,7,6,5,4,3,2,1};

    printf("start array:\n\t");
    print_array(array, ARRAY_LEN);
    printf("\n");
    
    merge_sort(array, 0, ARRAY_LEN - 1, 0);

    printf("\nend array:\n\t");
    print_array(array, ARRAY_LEN);
    printf("\n");
    return 0;
}

  [1]上面代码输出结果:

start array:
        8 7 6 5 4 3 2 1 

merge, dir:-1      :7 8 6 5 4 3 2 1 
merge, dir:1       :7 8 5 6 4 3 2 1 
merge, dir:-1      :5 6 7 8 4 3 2 1 
merge, dir:-1      :5 6 7 8 3 4 2 1 
merge, dir:1       :5 6 7 8 3 4 1 2 
merge, dir:1       :5 6 7 8 1 2 3 4 
merge, dir:0       :1 2 3 4 5 6 7 8 

end array:
        1 2 3 4 5 6 7 8 

  [2]中间的7行是每次调用merge()函数之后的结果,dir表示排序的方向,-1表示排序左侧,0表示排序整个数组,1表示排序右侧。

  [3]代码流程:

    1)首先把数组分为左右两侧,即[8,7,6,5]和[4,3,2,1],然后先排序左侧,再排序右侧。

    2)继续排序时,就是一个递归流程,即排[8,7],再排[6,5],再排[7,8]和[5,6],再排[4,3],再排[2,1],再排[3,4]和[1,2],最后排[5,6,7,8]和[1,2,3,4]。

4.总结

  [1]归并排序的流程就是,把两个有序队列合并成一个有序队列,就是merge()函数,这个函数还是很简单的。

  [2]如果要排序两个有序队列,那么只用一个merge()函数就够了。但是算法的应用是要排序一个无序数组,因此其中用到了递归,递归只是一种实现方式,当然也可以用迭代方式实现。参考下面的代码:

/*排序两个有序数组*/
static void merge_sort(int array[], int start, int end, int dir)
{
    int middle;

    if(start < end){
        middle = start + (end - start) / 2;
        merge(array, start, middle, end);
    }
}

/*
    递归排序数组,这里只分析最外层的merge_sort()
*/
static void merge_sort(int array[], int start, int end, int dir)
{
    int middle;

    if(start < end){
        middle = start + (end - start) / 2;
        
        merge_sort(array, start, middle, -1);         //这个函数返回时,表示左侧已经排序好,即此时数组是[5,6,7,8,4,3,2,1]
        merge_sort(array, middle + 1, end, 1);        //这个函数返回时,表示右侧已经排序好,即此时数组是[5,6,7,8,1,2,3,4]
        
        merge(array, start, middle, end);
    }
}

   [3]以此来分析递归的实际流程,递归会层层进入内部,之后层层调用merge()函数。这也就是说,递归的意思就是层层调用一个具体的执行函数。一般的说来,递归是调用自己,明白了递归的层层入口点,也明白了层层返回点,但是这样理解总是找不到递归的重点,因此更容易的理解是,递归是层层调用一个具体的执行函数。然后最内层调用执行函数后,array会有新的排列,次内层调用执行函数后,array又会有新的排列,最外层调用执行函数后,数组就会排序完成。