归并排序链表的实现——学习笔记

归并排序是效率非常高的一种排序方式,和快速排序一样用了分治的思想。分治法的精髓在于将一个复杂问题分割成为多个简单的子问题,然后将子问题逐个解决,最终合并在一起以后就是复杂问题的解了。

这篇文章主要讲归并排序链表的实现方式,如果想了解数组的归并排序,可移步这里

归并排序的思想其实挺简单的,简而言之就是将数列分割成子序列,先对子序列进行排序,再将排好序的子序列合并成一个完整的数列。具体例子如下:

                       [3   7   6   4   8   9   2   1] 
                           /                  \
分割                 [3  7  6  4]          [8  9  2  1]
                     /          \          /        \
分割              [3   7]   [6   4]      [8   9]   [2   1]
                 /     \    /     \     /     \   /     \
分割            [3]    [7] [6]    [4]  [8]    [9] [2]    [1]
                 \     /   \     /     \     /    \     /
合并              [3   7]   [4   6]      [8   9]   [1   2]
                     \        /             \        /
合并                 [3  4  6  7]          [1  2  8  9]
                          \                     /
合并                   [1   2   3   4   6   7   8   9]

分割时从数列中间开始,将数列分成两部分,然后对分割后的序列继续进行分割直到分割不能再分为止。然后对已经排好序的子序列进行合并,重新产生一个排序好的数列。

用链表进行归并排序和数组排序略有不同,但是思想还是一样的。唯一的难点在于如何找到链表的中间点,这里就要运用到了一个额外的技巧——快慢指针。快慢指针常常用于判断链表中是否有环,简单来说就是有两个指针,快指针每次走两个节点,慢指针每次走一个节点,当快指针走到链表尽头时,慢指针才走到了链表的一半,此时就是我们想要的中间节点。

看代码:

//链表结构单位
struct Node{
    int val;
    Node* next;
};

//node -- 链表表头
Node* MergeSort(Node* node){
    //先判断链表长度是否大于1,小于1时无须排序
    if(node!=NULL&&node->next!=NULL){
        //运用快慢指针,找到链表的中间节点
        Node *fast=node->next;
        Node *slow=node;
        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
        }

        //将链表分成两部分进行分割
        Node *p1=MergeSort(slow->next);
        slow->next=NULL;                 //这儿很重要,仔细想想为什么
        Node *p2=MergeSort(node);

        //对两条子链进行归并
        Node *p0=(Node *)malloc(sizeof(Node));
        Node *p=p0;
        while(p1!=NULL&&p2!=NULL){
            if(p1->val<p2->val){
                p->next=p1;
                p1=p1->next;
            }else{
                p->next=p2;
                p2=p2->next;
            }
            p=p->next;
        }

        if(p1!=NULL){
            p->next=p1;
        }

        if(p2!=NULL){
            p->next=p2;
        }

        p=p0->next;
        free(p0);
        return p;
    }

    return node;
}

猜你喜欢

转载自blog.csdn.net/jjwwwww/article/details/82056488
今日推荐