力扣148 排序链表

题目:力扣148 .排序链表

链接:https://leetcode.cn/problems/sort-list/description/
今天废了好大的劲才弄明白链表归并排序的细节,特记录下来,以方便大家参考和我后续复习查看!

方法:基于迭代思想的归并排序。

思路: ① 定义一个虚拟头结点dum, pre=dum,cur=head,dum->next=head;统计链表的长度length。
② 定义一个sublength,控制每次移动cur的次数,初始值为1。每次循环,sublength<<=1;
③ 链表切分的细节:
1)head1=cur,从链表的第一个元素出发,按照sublength(同时判断cur->next!=nullptr)寻找第一个链表的结尾。保存cur->next的下一个元素,并切断cur与之后链表元素的联系,以防产生自环。
2)让cur移动到第二个链表的第一个元素,head2=cur;按照sublength(同时判断cur->next!=nullptr和cur!=nullptr)寻找第二个链表的结尾。保存cur->next的下一个元素,并切断cur与之后链表元素的联系,以防产生自环。
3)将head1和head2送入归并排序函数进行排序,返回合并后链表的头指针tmp,并让pre->next=tmp; pre移动到tmp的末尾,为下一次的循环做准备。重复1) 、2) 、 3)。
初始状态各个指针的位置:
在这里插入图片描述
将3和2分开之后:在这里插入图片描述接下来对head1和head2排序:
在这里插入图片描述
然后cur=next,进行接下来的分割,合并,拼接到pre的后面。

完整代码:

class Solution {
          public:`
    ListNode* sortList(ListNode* head) {
       int length=0,sublength=1;
       ListNode *tmp=head;
       ListNode *tmp1;
       ListNode*tmp2;//返回两个子链表排序后,新链表的头指针
       while (tmp!=nullptr)
       {
           length++;
           tmp=tmp->next;
       }
       ListNode*dum=new ListNode(0,head);//定义一个虚拟头结点
       for(sublength=1;sublength<length;sublength<<=1)
       {
             ListNode*pre=dum,*cur=dum->next;//每次初始化pre和cur
             ListNode*head1,*head2;
             while (cur!= nullptr)
             {
                 head1=cur;//第一个链表的首结点
                 for(int i=1;i<sublength && cur->next!=nullptr;i++)
                 {
                    cur=cur->next;
                 }
                head2=cur->next;
                 cur->next=NULL;
                 cur=head2;
                 for(int i=1;i<sublength && cur!=nullptr && cur->next!=nullptr;i++) //去掉cur!=nullptr在这里报错
                 {
                    cur=cur->next;
                 }
                 ListNode* next=nullptr;//next每次要初始化为空指针
                 if(cur!=nullptr)
                 {
                    next=cur->next;
                    cur->next=nullptr;
                 }
                tmp2=merge(head1, head2);
                //将tmp2接入到已排序链表的后面
                //移动pre指针,pre的移动步数与sublength有关,为其2倍;
                pre->next=tmp2;
                while (pre->next!=nullptr) //添加尾部出错pre->next->next存在,但是pre->next->next->next=NULL。正常应该是直接对
                {
                     pre=pre->next;
                }
              cur=next; //下一组要合并链表的头指针
             }
       }   
       return dum->next;
    }
    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode* dummyHead = new ListNode(0);
        ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;
        while (temp1 != nullptr && temp2 != nullptr) {
            if (temp1->val <= temp2->val) {
                temp->next = temp1;
                temp1 = temp1->next;
            } else {
                temp->next = temp2;
                temp2 = temp2->next;
            }
            temp = temp->next;
        }
        if (temp1 != nullptr) {
            temp->next = temp1;
        } else if (temp2 != nullptr) {
            temp->next = temp2;
        }
        return dummyHead->next;
    }
    };
         

暴力思想
先遍历一遍链表,然后存储链表值到向量中(太low啦)

 //暴力排序
 class Solution {
          public:`
     vector<int> arry;
    ListNode* tmp=head;
    while (tmp)
    {
        arry.push_back(tmp->val);
        tmp=tmp->next;
    }
    sort(arry.begin(),arry.end());
    tmp=head;
    int i=0;
    while (tmp)
    {
        tmp->val=arry[i];
        i++;
        tmp=tmp->next;
    }
    return head; 
    };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值