归并排序算法完全遵循分治模式。直观上其操作如下:
分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列。
解决:使用归并排序递归地排序两个子序列。
合并:合并两个已排列的子序列以产生已排序的答案。
随着算法自底向上地推进,待合并的已排好序的各序列长度不断增加,最后全部合并成等于原序列长度的一个新的已排列的序列。
// 归并排序
// low, mid, high 均为数组下标
#include <stdio.h>
#include <stdlib.h>
#define length(a) ((sizeof(a))/(sizeof(a[0])))
void printArray(int* a, int length)
{
int temp;
for (temp = 0; temp < length; temp++)
{
printf("%d ", a[temp]);
}
printf("\n");
}
void mergeSort(int* a, int low, int high);
void merge(int* a, int low, int mid, int high);
int main(void)
{
int a[] = { 5,2,4,6,1,3,6 };
printf("排序前:\n");
printArray(a, length(a));
mergeSort(a, 0, length(a) - 1);
printf("排序后:\n");
printArray(a, length(a));
return 0;
}
void mergeSort(int* a, int low, int high)
{
int mid;
if (low < high)
{
mid = (low + high) / 2;
mergeSort(a, low, mid);
mergeSort(a, mid + 1, high);
merge(a, low, mid, high);
}
}
void merge(int* a, int low, int mid, int high)
{
int i, j, k;
//左半数组和右半数组的长度
int n1 = mid - low + 1;
int n2 = high - mid;
//为左半数组和右半数组开辟空间,预留多一个元素的位置存放哨兵
int* L = (int*)malloc(sizeof(int) * (n1 + 1));
int* R = (int*)malloc(sizeof(int) * (n2 + 1));
//将原数组中的元素分别放入左右数组
for (i = 0; i < n1; i++)
L[i] = a[low + i];
for (j = 0; j < n2; j++)
R[j] = a[mid + j + 1];
//在左半数组和右半数组的最后放置哨兵,这样做无需检查是否有数组为空
L[i] = 2147483647;
R[j] = 2147483647;
//将左右数组中较小的数逐渐放回原数组
i = j = 0;
for (k = low; k <= high; k++)
{
if (L[i] <= R[j])
a[k] = L[i++];
else
a[k] = R[j++];
}
free(L);
free(R);
}