148. 排序鏈表
在 O(n log n) 時間複雜度和常數級空間複雜度下,對鏈表進行排序。
輸入: 4->2->1->3
輸出: 1->2->3->4
來源:https://leetcode-cn.com/problems/sort-list/
歸併排序法:
- 利用快慢指針將鏈表分爲前後半段
- 先對
slow.next
找到後半段並進行排序 - 斷開鏈表前後半段,對前半段進行排序
- 合併排序完成後的左右兩條鏈表
function mergeTwoLists(x, y) {
if (!x || !y)
return x ? x : y;
let p = new ListNode(-1);
let root = p;
while (x && y) {
if (x.val < y.val) {
p.next = x;
x = x.next;
} else {
p.next = y;
y = y.next;
}
p = p.next;
}
/* 連接剩餘部分 */
p.next = x ? x : y;
return root.next;
}
function mergeSort(root) {
/* 數量不到2個直接返回 */
if (!root || !root.next) return root;
/* 快慢指針找出中間點 */
let slow = root, fast = root.next.next;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
}
/* 對右半部分進行歸併 */
let right = mergeSort(slow.next);
/* 斷開左右連接 */
slow.next = null;
/* 左半部分歸併 */
let left = mergeSort(root);
/* 合併左右 */
return mergeTwoLists(left, right);
}
var sortList = function (head) {
return mergeSort(head);
};
快速排序法:
- 設置頭尾指針,將第一個結點的值作爲參考值,
- 遍歷後面的元素,將小於參考值的節點抽離到臨時鏈表
- 此時原鏈表全爲大於等於參考值的元素,且第一個值爲參考值,臨時鏈表全爲小於參考值的元素,將原鏈表接到臨時鏈表後面即將參考節點放到了最終的位置
- 覆蓋原鏈表,對參考值左邊和右邊元素進行相同的操作
/* 對(st,ed)區間的元素進行排序 */
function quickSort(st, ed) {
/* 至少存在一個值 */
if (st == ed || st.next == ed) return st;
/* x爲遍歷指針 p爲參考值 */
let x = st.next, p = st.next;
/* 臨時鏈表存小於p的所有元素 */
let tpSt = new ListNode(-1);
let tp = tpSt;
/* 遍歷(st,ed)區間 */
while (x.next != ed) {
/* 當前值小於p則抽離到臨時鏈表 */
if (x.next.val < p.val) {
tp.next = x.next;
tp = tp.next;
/* 原鏈表刪除 */
x.next = x.next.next;
} else { x = x.next; }
}
/* 原鏈表全大於p 臨時鏈表全小於p*/
tp.next = st.next;
st.next = tpSt.next;
quickSort(st, p);
quickSort(p, ed);
return st.next;
}
var sortList = function (head) {
if (!head || !head.next)
return head;
let newHead = new ListNode(-1);
newHead.next = head;
return quickSort(newHead, null);
};