!!!Attention:以下操作中的单链表均带有头结点!!!
参考怎样实现链表的归并排序
由于待处理的单链表带有头结点,因此把程序分为MergeSort和MergeSortCore两部分,其中MergeSort只是用来处理头结点的,这与写给自己看的单链表(2):进阶操作中的合并程序类似。
从MergeSortCore的伪代码可以一窥归并排序的思路:
Lnode *MergeSortCore(Lnode *head)
{
if 元素只有一个(已经有序)return;
划分为左右两段
对左段进行MergeSortCore
对右段进行MergeSortCore
//此时左段和右端已经有序
对左段和右段进行合并(MergeListCore)
}
要解决的是两个问题,一是如何分段,二是如何合并左段和右段。合并左段和右段可以用写给自己看的单链表(2):进阶操作中已经写好的MergeListCore,那么剩下的问题就是如何分段了。
分段用的是追及的思路:
使用一个slow指针和一个fast指针,让fast指针相对slow指针的移动速度是单位1。这样fast走到尽头时,slow就在“中间”位置了。
这样可以把链表分为两段:[left, slow->next) 和 [right, fast),这里的left和right均不包含头结点。right即为slow->next,在对right进行了赋值后,要注意把slow->next赋值为NULL,否则在递归MergeListCore时找不到终止点。fast其实就是NULL,所以分段的循环条件为fast != NULL
。
代码如下:
void MergeSort(Lnode *head)
{
if (head->next == NULL)
return;
head->next = MergeSortCore(head->next);
}
Lnode *MergeSortCore(Lnode *head)
{
if (head->next == NULL)
return head;
Lnode *slow, *fast;
slow = head;
fast = slow->next;
while (fast != NULL) {
fast = fast->next;
if (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
}
Lnode *righthead;
righthead = slow->next;
slow->next = NULL;
head = MergeSortCore(head);
righthead = MergeSortCore(righthead);
return MergeListCore(head, righthead);
}