原題鏈接
https://leetcode.com/problems/sort-list/
題目描述
Sort a linked list in O(nlogn) time using constant space complexity.
在O(nlogn)時間複雜度和常數空間複雜度內對單鏈表進行排序。
解題思路
在對數組的排序中,具有O(nlogn)時間複雜度的排序方式是歸併排序和快速排序,這裏也嘗試使用此兩種方式。在快速排序時,需要有兩個指針分別從數據首尾向中間結點移動,這對單鏈表來說不很方便。因此這裏首要考慮使用歸併排序的方法。
在歸併排序時,有一個比較關鍵的步驟是找到中間結點,在數組中找中間元素是很容易的,但是鏈表不具有隨機訪問的特性,爲了找到中間結點不得不遍歷整個鏈表,這裏我們使用快慢指針的方法來獲取中間結點,並把鏈表分爲左右均等的兩部分。
算法描述
- 找到單鏈表的中間結點,將鏈表分爲兩部分listA/listB
- 對listA和listB分別調用歸併排序
- 對排序之後的listA和listB進行歸併
代碼 c
/**
* 單鏈表歸併排序
*/
struct ListNode* sortList(struct ListNode* head) {
struct ListNode* merge(struct ListNode*, struct ListNode*);
if (head == NULL || head->next == NULL) return head;
/* 將鏈表平分爲兩個鏈表 */
struct ListNode first, *fast = &first, *slow = &first;
first.next = head;
while (fast->next && fast->next->next) {
fast = fast->next->next;
slow = slow->next;
}
struct ListNode* next = slow->next;
slow->next = NULL;
/* 對兩個子鏈表分別調用歸併排序 */
struct ListNode* partOne = sortList(head);
struct ListNode* partTwo = sortList(next);
/* 對排好序的子鏈表進行歸併 */
return merge(partOne, partTwo);
}
/* 歸併 */
struct ListNode* merge(struct ListNode* partOne, struct ListNode* partTwo) {
struct ListNode *curOne = partOne, *curTwo = partTwo;
struct ListNode head, *cur = &head;
while (curOne && curTwo) {
if (curOne->val < curTwo->val) {
cur->next = curOne;
cur = curOne;
curOne = curOne->next;
} else {
cur->next = curTwo;
cur = curTwo;
curTwo = curTwo->next;
}
}
while (curOne) {
cur->next = curOne;
cur = curOne;
curOne = curOne->next;
}
while (curTwo) {
cur->next = curTwo;
cur = curTwo;
curTwo = curTwo->next;
}
cur->next = NULL;
return head.next;
}
完整代碼https://github.com/Orange1991/leetcode/blob/master/148/c/main.c
運行情況
Language | Status | Time |
---|---|---|
c | Accept | 24ms |
2015/8/1