• 利用递归实现链表的排序(归并排序)


    利用递归实现链表的排序(归并排序)

    8c47e58b6247676f3ef14e617a4686bc258cc573e36fcf67c1b0712fa7ed1699-Picture2

    利用归并排序,我们可以将时间复杂度降至O(nlogn), 并且我们是对链表进行排序,可以通过修改引用来更改节点顺序,无需像数组一样开辟而外的空间。

    利用递归实现链表的归并排序有两个环节:

    分割cut环节:

    我们可以利用fast, slow快慢双指针实现链表的分割, fast一次移动两位, slow一次移动一位,当fast移动到末尾时,slow移动到中间位置。

    利用变量为tmp = slow.next记录后链表的头节点,并将slow.next = null将前后链表断开。

    ListNode sortList(ListNode head) {
      if (head == null || head.next == null)
        return head;
      
      ListNode fast = head.next, slow = head;
      while (fast != null && fast.next != null) {
        fast = fast.next.next; // 一次移动两位
        slow = slow.next; // 一次移动一位
      }
      
      ListNode tmp = slow.next; // 记录后链表的头节点
      slow.next = null; // 将前后链表断开
      //...
    }
    

    cut递归的终止条件 base case 为当head.next == null,即链表只有一个节点。

    归并merge环节:

    使用辅助指针,将前后链表后合并为一个有序链表

    ListNode sortList(ListNode head) {
      //...
      // left 为前链表的头节点, right 为后链表的头节点, h 为辅助节点
      while (left != null && right != null) {
        if (left.val < right.val) { 
          h.next = left;
          left = left.next;
        } else {
          h.next = right;
          right = right.next;
        }
        h = h.next;
      }
      h.next = left != null ? left : right;
      //...
    }
    

    明白上面的两个环节后,就能轻松明白我们完整的算法了。

    ListNode sortList(ListNode head) {
            if (head == null || head.next ==null)
                return head;
            // cut过程
            ListNode fast = head.next, slow = head;
            while (fast != null && fast.next != null) {
                fast = fast.next.next;
                slow = slow.next;
            }
            ListNode tmp = slow.next;
            slow.next = null;
    	// merage过程
            ListNode left = sortList(head);
            ListNode right = sortList(tmp);
            ListNode h = new ListNode(0);
            ListNode res = h;
            while (left != null && right != null) {
                if (left.val < right.val) {
                    h.next = left;
                    left = left.next;
                } else {
                    h.next = right;
                    right = right.next;
                }
                h = h.next;
            }
            h.next = left != null ? left : right;
    
            return res.next;
        }
    
  • 相关阅读:
    算法导论(第三版)Exercises2.1(插入排序、线性查找、N位大数相加)
    含铝馒头可能损伤儿童的智力
    每秒3600乘以100等于36万次售票解决方案
    namespace Measure
    public interface ICloneable
    VB.net 与线程
    C#调用VP 包含素材
    C# 定时器 一个简单 并且可以直接运行的Demo
    松下 激光位移传感器 API
    在Win7系统下, 使用VS2015 打开带有日文注释程序出现乱码的解决方案
  • 原文地址:https://www.cnblogs.com/Code-CHAN/p/13629355.html
Copyright © 2020-2023  润新知