leetcode 148. 排序链表
自顶向下归并排序
- 用快慢指针找到序列中间位置
这里要注意一个细节:始终使fast指向链表尾节点的next节点(也就是null),这样slow指向后半段链表的起点,避免出现死循环。
前半段链表[head, slow)
,后半段[slow, fast)

- 合并两个排序链表(从底层递归回顶层时,返回的链表一定是排好序的)
自顶向下归并排序
| /** |
| * Definition for singly-linked list. |
| * public class ListNode { |
| * int val; |
| * ListNode next; |
| * ListNode() {} |
| * ListNode(int val) { this.val = val; } |
| * ListNode(int val, ListNode next) { this.val = val; this.next = next; } |
| * } |
| */ |
| class Solution { |
| public ListNode sortList(ListNode head) { |
| return sort(head, null); |
| } |
| |
| public ListNode sort(ListNode head, ListNode tail) { |
| if(head == null) return null; |
| if(head.next == tail) { |
| head.next = null; |
| return head; |
| } |
| ListNode dummy = new ListNode(0, head); |
| ListNode fast, slow; |
| fast = slow = dummy; |
| while(fast != tail && fast.next != tail) { |
| slow = slow.next; |
| fast = fast.next.next; |
| } |
| if(fast != null) slow = slow.next; |
| |
| ListNode mid = slow; |
| return merge(sort(head, mid), sort(mid, tail)); |
| } |
| |
| public ListNode merge(ListNode h1, ListNode h2) { |
| if(h1 == null) return h2; |
| if(h2 == null) return h1; |
| |
| ListNode dummy = new ListNode(0); |
| ListNode res = dummy; |
| |
| while(h1 != null && h2 != null) { |
| if(h1.val <= h2.val) { |
| res.next = h1; |
| h1 = h1.next; |
| } else { |
| res.next = h2; |
| h2 = h2.next; |
| } |
| res = res.next; |
| } |
| if(h1 != null) res.next = h1; |
| else res.next = h2; |
| return dummy.next; |
| } |
| } |
自底向上排序
相当于省略自顶向下方法的递归过程,直接从底层开始向上两两合并。
最底层子链表的长度最长为1,子链表长度每合并一次,最长长度变为上一层长度的两倍
- 遍历链表长度[1, len),对于每一层:
- 找到要合并的两个子链表的表头,将子链表与原链表断开连接
这里定义ListNode cut(ListNode head, int len)
函数,截断从head开始长度为len的链表(截断的意思是将这段子链表尾链表的next设置为null),从而得到子链表的表头和表尾
- 合并两个子链表
- 更新合并链表的连接
- 循环2、3、4步

自底向上排序
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class Solution { |
| public ListNode sortList(ListNode head) { |
| if(head == null) return head; |
| int L = 0; |
| ListNode tmp = head; |
| while(tmp != null) { |
| tmp = tmp.next; |
| ++ L; |
| } |
| |
| ListNode dummy = new ListNode(0, head); |
| for(int len = 1; len < L; len <<= 1) { |
| ListNode cur = dummy.next; |
| ListNode pre = dummy; |
| while(cur != null) { |
| |
| ListNode head1 = cur; |
| ListNode head2 = cut(head1, len); |
| ListNode next = cut(head2, len); |
| cur = next; |
| pre.next = merge(head1, head2); |
| while(pre.next != null) { |
| pre = pre.next; |
| } |
| } |
| } |
| return dummy.next; |
| |
| } |
| |
| |
| public ListNode cut(ListNode head, int len) { |
| -- len; |
| while(head != null && len -- > 0) { |
| head = head.next; |
| } |
| ListNode res = null; |
| if(head != null) { |
| res = head.next; |
| head.next = null; |
| } |
| return res; |
| } |
| |
| public ListNode merge(ListNode h1, ListNode h2) { |
| if(h1 == null) return h2; |
| if(h2 == null) return h1; |
| ListNode dummy = new ListNode(0); |
| ListNode res = dummy; |
| while(h1 != null && h2 != null) { |
| if(h1.val <= h2.val) { |
| res.next = h1; |
| h1 = h1.next; |
| } else { |
| res.next = h2; |
| h2 = h2.next; |
| } |
| res = res.next; |
| } |
| if(h1 != null) res.next = h1; |
| else res.next = h2; |
| return dummy.next; |
| } |
| } |
优先队列方法
- 把链表数值全部放进优先队列中
- 依次读取队首元素构建升序链表
优先队列排序Integer
| /** |
| * Definition for singly-linked list. |
| * public class ListNode { |
| * int val; |
| * ListNode next; |
| * ListNode() {} |
| * ListNode(int val) { this.val = val; } |
| * ListNode(int val, ListNode next) { this.val = val; this.next = next; } |
| * } |
| */ |
| class Solution { |
| public ListNode sortList(ListNode head) { |
| Queue<Integer> pq = new PriorityQueue<>((o1, o2) -> { |
| return o1 - o2; |
| }); |
| |
| while(head != null) { |
| pq.offer(head.val); |
| head = head.next; |
| } |
| ListNode dummy = new ListNode(0); |
| ListNode res = dummy; |
| while(!pq.isEmpty()) { |
| int val = pq.poll(); |
| res.next = new ListNode(val); |
| res = res.next; |
| } |
| return dummy.next; |
| |
| } |
| } |
- 将链表节点放进优先队列中
- 依次读取队首链表节点,重新构建链表的连接关系
优先队列排序ListNode
| /** |
| * Definition for singly-linked list. |
| * public class ListNode { |
| * int val; |
| * ListNode next; |
| * ListNode() {} |
| * ListNode(int val) { this.val = val; } |
| * ListNode(int val, ListNode next) { this.val = val; this.next = next; } |
| * } |
| */ |
| class Solution { |
| public ListNode sortList(ListNode head) { |
| Queue<ListNode> pq = new PriorityQueue<>((o1, o2) -> { |
| return o1.val - o2.val; |
| }); |
| while(head != null) { |
| pq.offer(head); |
| head = head.next; |
| } |
| |
| ListNode dummy = new ListNode(0); |
| ListNode res = dummy; |
| while(!pq.isEmpty()) { |
| res.next = pq.poll(); |
| res = res.next; |
| res.next = null; |
| } |
| return dummy.next; |
| } |
| } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!