Sort List
2014-04-21 16:31
316 查看
要求时间复杂度是O(nlogn),只能用归并,堆,快排。
而堆排序和快速排序都是基于交换的排序,对于链表结构并不合适。归并排序,在数组情况下,空间复杂度为O(N).
但在链表情况下,却可以用常量空间复杂度来实现。见Merge Two Sorted
Lists
归并排序思路在各种排序算法的比较已详细分析。
现在最主要的就是如何把链表分割成两部分。
采用slow-fast指针,slow走一步,fast走两步,当fast走到尾时,slow的前驱正好到链表的一半。在分割时,用pre记录slow的前驱。
实际上,这道题目与Merge k Sorted Lists类似,只不过把Lists换成了单个节点,更加简单了。
上述合并两个有序链表的程序中,因为要构造头结点,所以程序显得比较复杂,我们可以先构造一个头结点,最后再删除头结点也可以实现。
下面的代码是C++实现:
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL)
{
return head;
}
ListNode* preslow = NULL;
ListNode* slow = head;
ListNode* fast = head;
while(fast != NULL && fast->next != NULL)
{
preslow = slow;
slow = slow->next;
fast = fast->next->next;
}
preslow->next = NULL;
ListNode* l1 = sortList(head);
ListNode* l2 = sortList(slow);
return mergeTwoSorted(l1, l2);
}
ListNode* mergeTwoSorted(ListNode* l1,ListNode* l2)
{
ListNode* l3 = new ListNode(0);//构造一个头结点
ListNode* head = l3;
while(l1!=NULL && l2!=NULL)
{
if(l1->val > l2->val)
{
l3->next = l2;
l2 = l2->next;
}
else
{
l3->next = l1;
l1 = l1->next;
}
l3 = l3->next;
}
if(l1 != NULL)
{
l3->next = l1;
}
if(l2 != NULL)
{
l3->next = l2;
}
ListNode* ret = head->next;
head->next = NULL;
delete head;
return ret;
}
而堆排序和快速排序都是基于交换的排序,对于链表结构并不合适。归并排序,在数组情况下,空间复杂度为O(N).
但在链表情况下,却可以用常量空间复杂度来实现。见Merge Two Sorted
Lists
归并排序思路在各种排序算法的比较已详细分析。
现在最主要的就是如何把链表分割成两部分。
采用slow-fast指针,slow走一步,fast走两步,当fast走到尾时,slow的前驱正好到链表的一半。在分割时,用pre记录slow的前驱。
实际上,这道题目与Merge k Sorted Lists类似,只不过把Lists换成了单个节点,更加简单了。
public ListNode sortList(ListNode head) { if(head == null || head.next == null){ return head; } ListNode slow = head; ListNode fast = head; ListNode pre = null; while(fast!=null && fast.next!=null){ pre = slow; slow = slow.next; fast = fast.next.next; } ListNode left = head; ListNode right = pre.next; pre.next=null; ListNode leftNode = sortList(left); ListNode rightNode = sortList(right); return mergeTwoLists(leftNode,rightNode); } ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode head = null; if(l1 == null)return l2; else if(l2 == null)return l1; else{ if(l1.val < l2.val){ head = l1; l1 = l1.next; }else{ head = l2; l2 = l2.next; } } ListNode l3 = head; while(l1!=null && l2!=null){ if(l1.val < l2.val){ l3.next = l1; l1 = l1.next; }else{ l3.next = l2; l2 = l2.next; } l3=l3.next; } while(l1!=null){ l3.next = l1; l1 = l1.next; l3=l3.next; } while(l2!=null){ l3.next = l2; l2 = l2.next; l3=l3.next; } return head; }
上述合并两个有序链表的程序中,因为要构造头结点,所以程序显得比较复杂,我们可以先构造一个头结点,最后再删除头结点也可以实现。
下面的代码是C++实现:
ListNode* sortList(ListNode* head) {
if(head == NULL || head->next == NULL)
{
return head;
}
ListNode* preslow = NULL;
ListNode* slow = head;
ListNode* fast = head;
while(fast != NULL && fast->next != NULL)
{
preslow = slow;
slow = slow->next;
fast = fast->next->next;
}
preslow->next = NULL;
ListNode* l1 = sortList(head);
ListNode* l2 = sortList(slow);
return mergeTwoSorted(l1, l2);
}
ListNode* mergeTwoSorted(ListNode* l1,ListNode* l2)
{
ListNode* l3 = new ListNode(0);//构造一个头结点
ListNode* head = l3;
while(l1!=NULL && l2!=NULL)
{
if(l1->val > l2->val)
{
l3->next = l2;
l2 = l2->next;
}
else
{
l3->next = l1;
l1 = l1->next;
}
l3 = l3->next;
}
if(l1 != NULL)
{
l3->next = l1;
}
if(l2 != NULL)
{
l3->next = l2;
}
ListNode* ret = head->next;
head->next = NULL;
delete head;
return ret;
}
相关文章推荐
- HDU 4433 locker (线性dp)
- 使用信号量和关键区来实现生产者消费者
- Git教程
- Linux初学者之网络配置(命令)
- JDK中rt.jar、tools.jar和dt.jar作用
- 【define宏定义和const常量定义之间的区别】
- Go lang concurrency: select with channels
- Extjs4.0 Ext.Class
- 妙趣横生的算法--二叉树
- 闲扯 Javascript 02 全选、不选、反选
- C#-Activex插件操作指南
- HTTP错误代码详细介绍
- 网关设置
- oracle pl/sql之函数(function)
- Openwrt移植IMX6之增加u-boot支持
- socket.error C2011: “sockaddr”: “struct”类型重定义
- STA线程模型中操纵串口的注意点
- unix socket 的缓冲区大小
- 2014腾讯校园招聘实习技术类笔试题目
- 【linux驱动分析】之dm9000驱动分析(三):sk_buff结构分析