链表的快速排序笔记,画图分析对学习很有帮助

纸上谈来终觉浅,绝知此事要躬行

先说这两天的反思,有点急于求成了,想着多做几道题,由于这几天已经做了不少题,觉得分析画图的时候可以快一点,结构就导致我在这道题上困了一天没有走出来,后来在老师的指导下才打通任督二脉,由此我也得出一个结论:

一定要画图分析!!!一定要画图分析!!!一定要画图分析!!!

重要的事情说三遍!!!

原题链接:https://leetcode.cn/problems/sort-list/

PS:给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

先来谈一下我对这道题的理解

没进行一次范围比较就将该范围的值进行一次排序,而后下一次的大范围比较每组数据的值都是相对有序的,那么在进行一个值的插入即可,直到排序完。

如果数据的个数没有2^N次幂个,那也是能排序的,因为这一段数据保持着该范围内的相对有序,再做一个尾部特殊处理,把他链接至上一个尾部,再参与比较,举个栗子:

可见,2在单独的范围类,保持着相对有序,所以对尾部进行一个排序+链接即可

先上草稿图,如果能够能看懂就更好了,整个循环全都在这张草稿上

struct ListNode* sortList(struct ListNode* head){
    int num = 0;//链表总长度
    //int node = 0;//表示范围的终止节点
    int endK = 0;//表示每一个范围的个数
    struct ListNode* dummy = (struct ListNode*)malloc(sizeof(struct ListNode));
    dummy->val = 0;
    dummy->next = head;
    //这里弄一个带哨兵位的,排序会更加方便
    struct ListNode* cur = head;//定义一个变量,指向链表首地址,用来判断该链表的长度为多少
    while (cur)
    {
        cur = cur->next;
        ++num;
    }//算出链表的总长度
    //printf("n:%d\n", num);

    for (int step = 1; step < num; step *= 2)//表示在一个单独小范围内,头结点与尾节点可以偏移几个单位,同时也表示了该范围有多少的数据
    {
        cur = dummy;//重定向让cur指向链表首地址让cur每次指向链表的首地址
        for (int node = 1; node + step <= num; node = node + 2 * step)//下一次范围的头节点,每一次会便宜step*2个单位,直到走到末尾
        {
            struct ListNode* begin = cur->next;//定义一个begin和end指针,begin指向该范围的左边界,end指向该范围内的右边界
            struct ListNode* end = begin;

            for (endK = 0; endK < step; endK++)
                end = end->next;//要让end偏移step个单位才会指向右边界
            int begin_Left = 0, end_Left = 0;//表示begin指针移动了几次,即进行了几次数值交换
            while ((begin_Left < step) && (end_Left < step) && (begin && end))
            {//当begin_Left 或者 end_Left的值等于step的时候,说明此时要么小的数全部排了,要么就是大的数全部排了,当排完还剩下一部分数据再链接在当前数据的尾部,当begin与end分别有一个为空时,也就是说此时此刻指针走到整个链表的右边界了,就需要停止
                if (begin->val <= end->val)
                {如果begin->val的值小于end->val,那么就让cur->next指向begin,并且要立即让cur走到begin这个位置上来,然后再让begin走到下一个位置去,然后让begin_left++。如果此时begin->next==NULL,那么进入上一层的while循环就会退出,并且链接end剩余的数
                    cur->next = begin;
                    cur = begin;
                    begin = begin->next;
                    begin_Left++;
                }
                else
                {//与上同理
                    cur->next = end;
                    cur = end;
                    end = end->next;
                    end_Left++;
                }
            }
//当上一级循环退出只有二种情况,begin走到范围尽头了,end走到范围尽头了。也就是begin或者end走了step步,或者是走到NULL这个位置了
            while (begin_Left < step && begin)
            {
                cur->next = begin;
                cur = begin;
                begin = begin->next;
                begin_Left++;
            }
            while (end_Left < step && end)
            {
                cur->next = end;
                cur = end;
                end = end->next;
                end_Left++;
            }
            cur->next = end;这一步就是让cur指向下一个小范围的首节点
        }
    }
    return dummy->next;

}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值