基本思想
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
分而治之
可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。
合并相邻有序子序列
再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DATA_ARRAY_LENGTH 8
void merge(int *data, int *temp, int start, int middle, int end){
int i = start; //左游标
int j = middle + 1; //右游标
int k = start; //临时游标
while(i <= middle && j <= end){ //当mid的左右两端都剩数字时,任意一边放完了都会退出
if(data[i] > data[j]){ //小的往前放
temp[k++] = data[j++];
}
else{
temp[k++] = data[i++];
}
}
while(i <= middle){ //注意这一句和下面一句一次只合并会有其中一个执行
//将左变剩余元素填充到临时数组temp
temp[k++] = data[i++];
}
while(j <= end){ //将右变剩余元素填充到临时数组temp
temp[k++] = data[j++];
}
for(i = start; i <= end; i++){ //复制到原始数组data中
data[i] = temp[i];
}
return 0;
}
void merge_sort(int *data, int *temp, int start, int end){
int middle = 0;
if(start < end){
middle = start + (end - start)/2; //分组
merge_sort(data, temp, start, middle); //左边集合进行归并排序,形成有序
merge_sort(data, temp, middle+1, end); //右边边集合进行归并排序,形成有序
merge(data, temp, start, middle, end); //左右合并进行排序,最终有序
}
return 0;
}
int main() {
int data[DATA_ARRAY_LENGTH] = {8, 4, 5, 7, 1, 3, 6, 2};
int temp[DATA_ARRAY_LENGTH] = {0};
merge_sort(data, temp, 0, DATA_ARRAY_LENGTH-1);
for (int i = 0;i < DATA_ARRAY_LENGTH;i ++) {
printf("%4d", data[i]);
}
printf("\n");
}