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又会有新的排列,最外层调用执行函数后,数组就会排序完成。