归并排序调用接口:
void MergeSort_rec(RcdSqList& L)
{// 对顺序表L作2-路归并排序(递归实现)
RcdType* R;
R = (RcdType*)malloc((L.length + 1) * sizeof(RcdType)); // 分配辅助空间
MSort_rec(L.length, L.rcd, R, 0, 1, L.length); // 对L.rcd[1.. L.length]归并排序
free(R);
}
实现归并排序功能的函数主体:
void MSort_rec(int length, RcdType R1[], RcdType R2[], int i, int s, int t)
{
// 对R1[s..t]归并排序,若i%2==1,则排序后的记录存入R2[s..t],否则存入R1[s..t]
//--------------------test code bigin----------------------------------------
printParam(length, R1, R2, i, s, t);
//--------------------test code end------------------------------------------
// 当s与t相等的时候
// 说明当前划分的区域中仅有一个元素
// 这是划分的结束条件
// 无需再次划分
if (s == t)
{
// 当当前划分的区域仅有一个元素的时候
// 需要判断R1和R2两个数组哪一个是目标数组、哪一个是辅助数组
// 由于在下面将要调用的Merge函数中
// i控制了要将哪个数组中的数据排序后放入另外一个数组
// 而在上一层的MSort_rec函数中
// i的值为i-1
// 那么就可以衍生出以下两种情况
// 第一种情况:(i - 1) % 2 == 0
// 这种情况说明在本层的MSort_rec函数执行完毕之后
// 要将R2中的数据排序,排序完成之后存储到R1中
// 那么就需要将本次划分的数据存入R2数组,使得R2数组中的数据最新
// 然后才能以R2为数据源调用Merge函数
// 第二种情况:i % 2 == 0
// 这种情况说明在本层的MSort_rec函数执行完之后
// 要将R1数组中的数据排序,排序完成之后存储在R2中
// 那么理论上就需要将本次划分的数据存入R1数组,以达到更新R1数组中的数据的目的
// 但是由于划分始终是在R1数组中进行的,因此R1数组中的数据可以不用更新
if (1 == i % 2){
R2[s] = R1[s];
}
}
else
{
// 练习1:进行归并排序的递归实现
// 将当前的序列分为两部分,以mid为分割点
int mid = (s + t) / 2;
// 对前半部分进行2-路归并排序
MSort_rec(length, R1, R2, i+1, s, mid);
// 对后半部分进行2-路归并排序
MSort_rec(length, R1, R2, i+1, mid+1, t);
// 判断要将排序之后的记录存入哪个数组
if(1 == i % 2){
Merge(R1, R2, s, mid, t);
}
else{
Merge(R2, R1, s, mid, t);
}
}
//--------------------test code bigin----------------------------------------
printParam(length, R1, R2, i, s, t);
//--------------------test code end------------------------------------------
}
void Merge(RcdType SR[], RcdType TR[], int i, int m, int n)
{ // 将相邻的有序区间SR[i..m]和SR[m+1..n]归并为有序的TR[i..n]
int k, j;
for (j = m + 1, k = i; i <= m && j <= n; ++k)
{ // 将SR中记录按关键字从小到大地复制到TR中
//练习3:如果 <= 改为 <,会对归并排序造成什么影响?
if (SR[i].key <= SR[j].key)
TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
while (i <= m) // 将剩余的 SR[i..m] 复制到TR
TR[k++] = SR[i++];
while (j <= n) // 将剩余的 SR[j..n] 复制到TR
TR[k++] = SR[j++];
}