原题链接
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