这个题目要求在时间复杂度O(nLogn)、空间复杂度O(1)内,对单链表进行排序。常见的满足这两项要求的排序算法就是归并排序和快排。我先尝试了快排,由于在单链表中实现随机选择哨兵项A[r]不够方便,我令每组最后一个数据项为A[r](参考算法导论实现),这样做对于一般的数据应该没有问题,但对于特殊设计的数据(如本题的输入数据),还是会把快排降为O(N^2)。关于快排单链表的实现见这篇Blog利用快速排序对单链表进行排序

于是我又尝试了归并排序,这回很顺利就AC了。对链表进行归并,我习惯于分别将他们加上头指针,再进行merge合并。在合并操作时要务必小心,不要把链表指乱,事实证明我写过几次链表合并,每次写的时候还是要想一想,估计写十次以上才能默出吧。对于分裂链表(即寻找中间结点),有个小技巧:用两个指针,都从头部开始,分别以步长1,步长2对链表进行遍历,当第二个指针到达链表尾部,第一个指针就是链表中间。这里我为了令指针1的next节点是我想要的中间位置,所以初始化令指针2指向指针1的Next。最后令mid=指针1->next,指针1->next=NULL来实现对链表的割裂。

下面是代码,main函数和ListNode数据结构与Blog 利用快速排序对单链表进行排序共享,这里就省略了。

class Solution {
public:
	ListNode *sortList(ListNode *head) {
		if (head == NULL)
			return head;
		return mergeSort(head);
	}
	ListNode* merge(ListNode* l1, ListNode* l2)
	{
		
		ListNode* head1 = new ListNode(0);
		head1->next = l1;
		ListNode* node1 = head1;
		ListNode* head2 = new ListNode(0);
		head2->next = l2;
		ListNode* node2 = head2;

		while (node1->next != NULL&&node2->next != NULL)
		{
			if (node1->next->val <= node2->next->val)
			{
				node1 = node1->next;
			}
			else{
				ListNode* tmp = node1->next;
				node1->next = node2->next;
				node2->next = node2->next->next;
				node1->next->next = tmp;
			}
		}
		if (node2->next != NULL)
		{
			node1->next = node2->next;
		}
		return head1->next;
			
	}
	ListNode* mergeSort(ListNode* list)
	{
		ListNode* p1 = list;
		ListNode* p2 = list->next;
		if (p2 == NULL)
			return list;
		if (p2->next == NULL)
		{
			if (p1->val > p2->val)
				swap(p1->val, p2->val);
			return p1;
		}
		while (p1->next != NULL&&p2->next != NULL)
		{
			p1 = p1->next;
			p2 = p2->next;
			if (p2 != NULL)
				p2 = p2->next;
			if (p2 == NULL)
				break;
		}
		ListNode* mid = p1;
		ListNode* head1 = list;
		ListNode* head2 = p1->next;
		p1->next = NULL;

		head1 = mergeSort(head1);
		head2 = mergeSort(head2);
		ListNode*res=merge(head1, head2);
		return res;
	}
};


posted on 2014-07-17 16:07  xlert  阅读(166)  评论(0编辑  收藏  举报