归并排序是多次将两个或两个以上的有序表合并为一个新的有序表。最简单的归并是二路归并,即将两个有序表合并为一个有序表。二路归并排序的基本思想是:将R[0..n-1]看作是n个长度为1的有序子表,然后进行两两二路归并,得到[n/2](对n/2取整数)个长度为2(最后一个子表的长度可能小于2)的有序子表;再次进行两两二路归并,得到[n/4]个长度为4(最后一个子表的长度可能小于4)的有序子表,...,直到得到一个长度为n的有序表。
/**
* 归并排序
*
* 算法:归并排序(Merge Sort)
* 输入:待排序元素的数组,待排序元素个数
* 输出:
* 原理:将待排序的表R[0..n-1]看做是n个长度为1的有序子表,将这些子表两两归并;将第一趟归并得到的子表继续两两归并;重复上述操作,直到最后得到一个长度为n的有序表
* 过程:
* 1)将待排序的表R[0..n-1]看做是n个长度为1的有序子表,将这些子表两两归并,得到的子表的长度为2(最后一个子表的长度可能不是2)
* 2)将第一趟归并得到的所有子表继续两两归并,得到的子表的长度为4(最后一个子表的长度可能不是4)
* 3) ...
* 4)重复上述操作,直到得到长度为n的有序表
* 5) ...
* 6)最终得到的R[0..n-1]中的元素递增排序
*
* 时间复杂度为O(nlog2(n)),空间复杂度为O(n),稳定的排序方法
*/
void mergeSort(RecType R[], int n)
{
//自底向上的二路归并算法
int length;
//进行log2(n)趟归并
for (length = 1; length < n; length = 2 * length)
mergePass(R, length, n);
}
/**
* 目的:对整个表进行一趟归并
* 作用:将R[0..n-1]中长度为length的有序子表,合并为长度为2length的有序子表
* 原理:在某趟归并中,设各子表长度为length(最后一个子表的长度可能小于length),则归并前R[0..n-1]中共有[n/length]个有序子表:R[0..length-1],R[length..2length-1],...,R[[n/length]*length..n-1]。其中,[n/length]表示取整数
调用Merge()函数将相邻的一对子表进行归并。
* 特殊情况:若子表个数为奇数,则最后一个子表无序归并;若子表个数为偶数,则要注意最后一个子表的区间上界是n-1,最后一个子表的长度可能小于length
* 过程:
* 1) 调用Merge()函数将所有的长度为length的相邻的一对子表归并
* 2) 判断剩余一个子表还是两个子表
* 3)若还剩两个子表,则归并这两个子表;否则,不做任何操作
*
*/
void mergePass(RecType R[], int length, int n)
{
int i;
//归并length长的两个相邻子表
for (i = 0; i + 2 * length - 1 < n; i = i + 2 * length)
{
merge(R, i, i + length - 1, i + 2 * length - 1);
}
//余下两个子表,后者长度小于length
if (i + length < n)
{
//归并这两个子表
merge(R, i, i + length - 1, n - 1);
}
}
/**
* 目的:将两个有序表R[low..mid]和R[mid+1..high]直接归并为一个有序表
* 原理:每次从两个有序表(递增)中取出一个元素进行关键字的比较,将较小者放入一个局部的暂存数组R1中,最后将各有序表中余下的部分直接复制到R1中,得到有序表R1
* 过程:
* 1) 初始化R1,用于保存合并后的有序表
* 2) 分别从两个有序表(递增)中取出第一个元素,比较它们的关键字大小,将关键字较小的元素放入R1中,并将该元素从原来的有序表中删除
* 3)继续从两个有序表中取出第一个元素进行比较,直至某一个有序表中没有任何元素可以取出来比较
* 4) ...
* 5) 将还有剩余元素的有序表中的元素全部放入R1中
* 6) 得到的R1[0..high-low]中的元素递增排序
* 7) 将R1中的元素复制回R中
* 8) 最终得到的R[low..high]中的元素递增排序
*
*/
void merge(RecType R[], int low, int mid, int high)
{
RecType *R1;
//k是R1的下标,i、j分别为两个有序表的下标
int i = low, j = mid + 1, k = 0;
//动态分配空间,长度为待合并的两个有序表的长度之和
R1 = new RecType[high - low + 1];
//R1=(RecType *)malloc((high-low+1)*sizeof(RecType));
//循环第1个有序表和第2个有序表
while (i <= mid && j <= high)
{
//取两个有序表的第一个元素进行比较
if (R[i].key <= R[j].key) //将第1有序表中的元素放入R1中
{
R1[k] = R[i];
i++;
k++;
}
else //将第2有序表中的元素放入R1中
{
R1[k] = R[j];
j++;
k++;
}
}
//将第1有序表余下部分复制到R1中
while (i <= mid)
{
R1[k] = R[i];
i++;
k++;
}
//将第2有序表余下部分复制到R1中
while (j <= high)
{
R1[k] = R[j];
j++;
k++;
}
//将R1复制回R中
for (k = 0, i = low; i <= high; k++, i++)
R[i] = R1[k];
//释放R1的空间
delete R1;
//free(R1);
}