当前位置: 面试刷题>> 排序链表(经典算法150题)


### 题目描述 给定一个单链表的头节点 `head`,请编写一个函数对链表进行排序。排序时,要求只能使用常数级额外空间,也就是说,你不能使用除链表本身以外的其他数据结构来辅助排序。 **注意**: - 链表的长度在范围 `[0, 5 * 10^4]` 内。 - `-10^5 <= Node.val <= 10^5` ### 示例 假设链表是 `1 -> 4 -> 2 -> 8 -> 3`,排序后应为 `1 -> 2 -> 3 -> 4 -> 8`。 ### 解题思路 由于题目要求只能使用常数级额外空间,我们不能使用归并排序(虽然归并排序对链表排序效率很高,但空间复杂度为 O(n))。这里我们可以采用**自底向上的归并排序**(也称为迭代归并排序),每次将链表分割成更小的部分,然后使用归并的思想将相邻的已排序部分合并起来。 ### PHP 示例代码 ```php val = $val; $this->next = $next; } } function sortList($head) { if ($head == null || $head->next == null) { return $head; } $dummy = new ListNode(0); $dummy->next = $head; $subLength = 1; while ($subLength < floor(countNodes($head) / 2) + 1) { $prev = $dummy; $curr = $dummy->next; while ($curr != null && $curr->next != null) { $head1 = $curr; $tail1 = splitList($head1, $subLength); $head2 = $tail1->next; $tail2 = splitList($head2, $subLength); $merged = mergeLists($head1, $head2); $prev->next = $merged; while ($prev->next != $tail2) { $prev = $prev->next; } $curr = $tail2; } $subLength *= 2; } return $dummy->next; } function countNodes($head) { $count = 0; while ($head != null) { $count++; $head = $head->next; } return $count; } function splitList($head, $n) { $prev = null; $count = 0; while ($head != null && $count < $n - 1) { $prev = $head; $head = $head->next; $count++; } if ($prev != null) { $prev->next = null; } return $head; } function mergeLists($l1, $l2) { $dummy = new ListNode(0); $tail = $dummy; while ($l1 != null && $l2 != null) { if ($l1->val < $l2->val) { $tail->next = $l1; $l1 = $l1->next; } else { $tail->next = $l2; $l2 = $l2->next; } $tail = $tail->next; } if ($l1 != null) { $tail->next = $l1; } if ($l2 != null) { $tail->next = $l2; } return $dummy->next; } ?> ``` ### Python 示例代码 ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def sortList(head): if not head or not head.next: return head dummy = ListNode(0) dummy.next = head sub_length = 1 while sub_length < len(list(to_list(head))) // 2 + 1: prev = dummy curr = dummy.next while curr and curr.next: head1 = curr tail1 = split_list(head1, sub_length) head2 = tail1.next tail2 = split_list(head2, sub_length) merged = merge_lists(head1, head2) prev.next = merged while prev.next != tail2: prev = prev.next curr = tail2 sub_length *= 2 return dummy.next def to_list(node): return [node.val for node in iter(lambda n=node: n if n else None, None)] def len_list(node): length = 0 while node: length += 1 node = node.next return length def split_list(head, n): prev = None for _ in range(n - 1): prev = head head = head.next if prev: prev.next = None return head def merge_lists(l1, l2): dummy = ListNode(0) tail = dummy while l1 and l2: if l1.val < l2.val: tail.next = l1 l1 = l1.next else: tail.next = l2 l2 = l2.next tail = tail.next tail.next = l1 if l1 is not None else l2 return dummy.next ``` ### JavaScript 示例代码 ```javascript function ListNode(val, next) { this.val = (val===undefined ? 0 : val) this.next = (next===undefined ? null : next) } function sortList(head) { if (!head || !head.next) return head; let dummy = new ListNode(0); dummy.next = head; let subLength = 1; while (subLength < Math.floor(countNodes(head) / 2) + 1) { let prev = dummy; let curr = dummy.next; while (curr && curr.next) { let head1 = curr; let tail1 = splitList(head1, subLength); let head2 = tail1.next; let tail2 = splitList(head2, subLength); let merged = mergeLists(head1, head2); prev.next = merged; while (prev.next !== tail2) { prev = prev.next; } curr = tail2; } subLength *= 2; } return dummy.next; } function countNodes(head) { let count = 0; while (head) { count++; head = head.next; } return count; } function splitList(head, n) { let prev = null; for (let i = 0; i < n - 1 && head; i++) { prev = head; head = head.next; } if (prev) prev.next = null; return head; } function mergeLists(l1, l2) { let dummy = new ListNode(0); let tail = dummy; while (l1 && l2) { if (l1.val < l2.val) { tail.next = l1; l1 = l1.next; } else { tail.next = l2; l2 = l2.next; } tail = tail.next; } tail.next = l1 ? l1 : l2; return dummy.next; } ``` 以上代码展示了如何在 PHP、Python 和 JavaScript 中使用自底向上的归并排序算法对链表进行排序,满足了题目要求的常数级额外空间。
推荐面试题