力扣 148. 排序链表 归并排序(递归/非递归)+骚操作

38 篇文章 0 订阅
14 篇文章 0 订阅

https://leetcode-cn.com/problems/sort-list/
在这里插入图片描述
思路一:由于链表这种数据结构的特殊性,想要在 O ( n l g n ) O(nlgn) O(nlgn)时间复杂度下完成排序,就只能选择归并排序啦。递归版的很简单,利用快慢指针计算出链表中点,将链表一分为二然后递归下去即可。
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    //得到链表的中间节点
    ListNode* getMid(ListNode* head){
        //这一步是为了使得 当链表有偶数个元素时 返回的是第一个中间节点
        ListNode root(0);
        root.next=head;
        ListNode *slow=&root,*fast=&root;
        while(fast){
            fast=fast->next;
            if(fast){
                fast=fast->next;
                slow=slow->next;
            }
        }
        return slow;
    }

    ListNode* merge(ListNode* l,ListNode *r){
        ListNode head(0);
        ListNode *cur=&head;
        while(l&&r){
            if(l->val<=r->val)
                cur->next=l,l=l->next;
            else
                cur->next=r,r=r->next;
            cur=cur->next;
        }
        cur->next=l?l:r;
        return head.next;
    }

    ListNode* mergeSort(ListNode* head){
        if(!head->next)
            return head;
        ListNode *r=getMid(head);
        ListNode *tmp=r->next;
        //断开连接
        r->next=nullptr;
        ListNode *l=mergeSort(head);
        r=mergeSort(tmp);
        return merge(l,r);
    }

    ListNode* sortList(ListNode* head) {
        if(!head)
            return head;
        return mergeSort(head);
    }
};

思路二:现在来看看非递归版怎么写。假设我们需要进行 x x x轮循环,第一轮循环可以依次合并 2 2 2个元素,第二轮循环可以依次合并 4 4 4个元素(如下图所示)……
在这里插入图片描述
那么很容易知道 x = l o g 2 n x=log_2n x=log2n,所以总复杂度依然是 O ( n l g n ) O(nlgn) O(nlgn)。代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    //将链表head一分为二 且第一部分有n个元素 返回第二部分的头节点
    ListNode* cut(ListNode* head,int n){
        while(--n&&head){
            head=head->next;
        }
        if(!head)
            return head;
        ListNode *nxt=head->next;
        head->next=nullptr;
        return nxt;
    }
    //合并两个有序链表
    ListNode* merge(ListNode* l,ListNode* r){
        ListNode head(0);
        ListNode *cur=&head;
        while(l&&r){
            if(l->val<=r->val)
                cur->next=l,l=l->next;
            else
                cur->next=r,r=r->next;
            cur=cur->next;
        }
        cur->next=l?l:r;
        return head.next;
    }

    ListNode* sortList(ListNode* head) {
        if(!head)
            return head;
        int len=0;
        ListNode *l=head,*r,*tmp,*res;
        while(l&&++len)
            l=l->next;
        ListNode root(0);
        root.next=head;
        //每次合并2*siz个元素
        for(int siz=1;siz<len;siz<<=1){
            //从头开始
            res=&root;
            tmp=root.next;
            while(tmp){
                //l是有序链表A r是有序链表B
                l=tmp;
                r=cut(l,siz);
                //注意要断开r与后者的连接(保证r的元素个数<=siz)
                tmp=cut(r,siz);
                //合并l r 并将其串接到前一次结果之后
                res->next=merge(l,r);
                //为了保证每次都正确的串接上了 需要遍历到res的最后一个节点
                while(res->next)
                    res=res->next;
            }
        }
        return root.next;
    }
};

思路三:整一个骚操作。我们用 v e c t o r vector vector存储链表的节点,那么很容易实现出一个自定义比较函数,这样就可以愉快的使用 s o r t sort sort辣。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    static bool cmp(ListNode* l,ListNode *r){
        return l->val<r->val;
    }
    ListNode* sortList(ListNode* head) {
        if(!head)
            return head;
        vector<ListNode*> vec;
        while(head){
            vec.push_back(head);
            head=head->next;
        }
        sort(vec.begin(),vec.end(),cmp);
        int siz=vec.size();
        --siz;
        for(int i=0;i<siz;i++)
            vec[i]->next=vec[i+1];
        vec[siz]->next=nullptr;
        return vec[0];
    }
};
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值