leetcode148. Sort List

题目:

Sort a linked list in O(n log n) time using constant space complexity.

题目解析:要求用链表作为排序的数据结构,时间复杂度为O(nlogn),空间复杂度为O(1)。

分析:首先想到复杂度为O(nlogn)的排序算法有:快排,堆排和归并排序,三者的空间复杂度都为O(n)。本例使用归并排序,归并排序如果用数组结构存储归并排序后的数据,则需要开辟出O(n)的空间来容纳数组,空间复杂度为O(n),但是若用链表作为数据结构,只需要改变next指针指向下一个归并后的顺序就行,空间复杂度降为O(1)。

要用归并排序,难点是:怎么样找到分治时的middle指针,采用快慢指针的思想。快指针一次走两步,慢指针一次走一步,当快指针走到头时,慢指针刚好走到中间位置,此位置即为middle的位置。

两个有序序列的合并

 1 LinkList* mergelist(LinkList *head1,LinkList *head2)
 2 {
 3     LinkList *newhead = new LinkList(-1);
 4     LinkList *newtail;
 5     newtail = newhead;
 6     while (head1 != NULL &head2 != NULL)
 7     {
 8         if (head1->data < head2->data)
 9         {
10             newtail->next = head1;
11             head1 = head1->next;
12         }else
13         {
14             newtail->next = head2;
15             head2 = head2->next;
16         }
17         newtail = newtail->next;
18     }
19     if (head1 != NULL)
20     {
21         newtail->next= head1;
22     }
23     if (head2 != NULL)
24     {
25         newtail->next = head2;
26     }
27     return newhead->next;
28 }

得到middle指针

 1 LinkList* getmid(LinkList *head)
 2 {
 3     LinkList *fast,*slow;
 4     fast = head;
 5     slow = head;
 6     while (fast->next != NULL && fast->next->next != NULL)
 7     {
 8         fast = fast->next->next;
 9         slow = slow->next;
10     }
11     fast = slow->next;
12     //从中间节点断开
13     slow->next = NULL;
14     return fast;
15 }

归并函数

 1 LinkList* sortlist(LinkList *head)
 2 {
 3     if (head == NULL || head->next == NULL)
 4     {
 5         return head;
 6     }    
 7     LinkList *mid;
 8     mid = getmid(head);
 9     head = sortlist(head);
10     mid = sortlist(mid);
11     head = mergelist(head,mid);
12     return head;
13 }

测试例子补全:

创建单链表:(返回是是没有头结点的链表)

 1 LinkList* createlinklist(LinkList *l,int n)
 2 {
 3     LinkList *p,*s;
 4     l = (LinkList *)malloc(sizeof(LinkList));
 5     s = l;
 6     int m;
 7     for (int i = 0; i < n;i++)
 8     {
 9         p = (LinkList *)malloc(sizeof(LinkList));
10         cin >> m;
11         p->data = m;
12         s->next = p;
13         s = p;
14     }
15     s->next = NULL;
16     return l->next;
17 }

主函数:

 1 void main()
 2 {
 3     LinkList *l = new LinkList(-1);
 4     l = createlinklist(l,6);
 5     l = sortlist(l);
 6     for (int i = 0;i<6;i++)
 7     {
 8         cout << l->data << " ";
 9         l = l->next;
10     }
11     system("pause");
12 }

运行结果:

 

在本题中用到了快慢指针,下面顺便详述一下快慢指针思想。

 快慢指针是指指针移动的步长,快指针移动的快,慢指针移动的慢,例如可以让快指针一次移动两个步长,让慢指针一次移动一个步长。

快慢指针有两个比较重要的应用:

1、判断链表是否为单链表

2、在有序链表中寻找中位数

posted @ 2016-05-06 16:35  泥石流小盆友  阅读(691)  评论(0编辑  收藏  举报