设单链表结构为 struct ListNode {
int data ;
ListNode * link ;
};
下面的程序是以单链表为存储结构, 实现二路归并排序的算法, 要求链表不另外占用存储空间, 排序过程中不移动结点中的元素, 只改各链结点中的指针, 排序后r仍指示结果链表的第一个结点.在初始状态下, 所有待排序记录链接在一个以r为头指针的单链表中.例如,
在算法实现时,利用了一个队列做为辅助存储, 存储各有序链表构成的归并段的链头指针.初始时, 各初始归并段为只有一个结点的有序链表.队列的数据类型为Queue, 其可直接使用的相关操作有置空队列操作:makeEmpty ( );将指针x加入到队列的队尾操作:EnQueue ( ListNode * x );退出队头元素, 其值由函数返回的操作:ListNode *DlQueue ( );判队列空否的函数, 空则返回1, 不空则返回0:int IsEmpty( ).
解决方法提示:
程序首先对待排序的单链表进行一次扫描, 将它划分为若干有序的子链表, 其表头 指针存放在一个指针队列中.当队列不空时, 从队列中退出两个有序子链表, 对它们进行二路归并, 结果链表的表头指针存放到队列中.
如果队列中退出一个有序子链表后变成空队列, 则算法结束.这个有序子链表即为所求.在算法实现时有 6 处语句缺失,请阅读程序后补上.
(提示:先对待排序的单链表进行一次扫描, 将它划分为若干有序的子链表, 其表头指针存放在一个指针队列中。当队列不空时重复执行, 从队列中退出两个有序子链表, 对它们进行二路归并, 结果链表的表头指针存放到队列中。如果队列中退出一个有序子链表后变成空队列, 则算法结束。这个有序子链表即为所求。)
(1) 两路归并算法
void merge ( ListNode * ha, ListNode * hb,, ListNode *& hc ) {
ListNode *pa, *pb, *pc ;
if ( ha→data <= hb→data )
{
hc = ha;
pa = ha→link;
pb = hb;
}
else
{
hc = hb;
pb = hb→link;
pa = ha ;
}
pc = hc;
while ( pa && pb )
if (pa→data <= pb→data)
{
pc→link = pa;
pc = pa;
pa = pa→link;
}
else
{
pc→link = pb;
pc = pb;
pb = pb→link;
}
if ( pa )
pc→link = pa;
else
pc→link = pb;
}
(2) 归并排序主程序
void mergesort ( ListNode * r ) {
ListNode * s, t; Queue Q ;
if ( ! r )
return;
s = r;
Q.EnQueue( r );
while ( s ) {
t = s→link;
while ( t != 0 && s→data <= t→data )
{
s = t;
t = t→link;
}
if ( t ) {
s→link = 0; s = t;
Q.EnQueue( s );
}
}
while ( !Q.IsEmpty( ) ) {
r = Q.DlQueue( );
if ( Q.IsEmpty( ) )
break;
s = Q.DlQueue( );
merge( r, s, t );
Q.EnQueue( t );
}
}