您的位置:首页 > 其它

找出链表的中间元素 与 链表排序

2013-09-18 01:35 295 查看
Q2 找出链表的中间元素

1 ListNode* find_midlist(ListNode* head)

2 {

3 ListNode *p1, *p2;

4

5 if (head == NULL || head->next == NULL)

6 {

7 return head;

8 }

9 p1 = p2 = head;

10 while (1)

11 {

12 if (p2->next != NULL && p2->next->next != NULL)

13 {

14 p2 = p2->next->next;

15 p1 = p1->next;

16 }

17 else

18 {

19 break;

20 }

21 }

22 return p1;

23 }

思路分析:

单链表的一个比较大的特点用一句广告语来说就是“不走回头路”,不能实现随机存取(random
access)。如果我们想要找一个数组a的中间元素,直接a[len/2]就可以了,但是链表不行,因为只有a[len/2 - 1] 知道a[len/2]在哪儿,其他人不知道。因此,如果按照数组的做法依样画葫芦,要找到链表的中点,我们需要做两步(1)知道链表有多长(2)从头结点开始顺序遍历到链表长度的一半的位置。这就需要1.5n(n为链表的长度)的时间复杂度了。有没有更好的办法呢?有的。想法很简单:两个人赛跑,如果A的速度是B的两倍的话,当A到终点的时候,B应该刚到中点。这只需要遍历一遍链表就行了,还不用计算链表的长度。

上面的代码就体现了这个想法。

Q3 链表排序

1 double cmp(ListNode *p ,ListNode *q)

2 {return (p->keyVal - q->keyVal);}

3

4 ListNode* mergeSortList(ListNode *head)

5 {

6 ListNode *p, *q, *tail, *e;

7 int nstep = 1;

8 int nmerges = 0;

9 int i;

10 int psize, qsize;

11 if (head == NULL || head->next == NULL)

12 {return head;}

13 while (1)

14 { p = head;

15 tail = NULL;

16 nmerges = 0;

17 while (p)

18 { nmerges++; q = p; psize = 0;

19 for (i = 0; i < nstep; i++)
{

20 psize++;

21 q = q->next;

22 if (q == NULL)break;

23 }

24 qsize = nstep;

25 while (psize >0 || (qsize >0 && q))

26 {

27 if (psize == 0)
{
e = q; q = q->next; qsize--;
}

28 else
if (q == NULL || qsize == 0)
{
e = p; p = p->next; psize--;
}

29 else
if (cmp(p,q) <= 0)
{
e = p; p = p->next; psize--;
}

30 else
{
e = q; q = q->next; qsize--;
}

31 if (tail != NULL)
{
tail->next = e;
}

32 else{head = e;}

33 tail = e;

34 }

35 p = q;

36 }

37 tail->next = NULL;

38 if (nmerges <= 1){return head;}

39 else{nstep <<= 1;}

40 }

41 }

思路分析:

链表排序最好使用归并排序算法。堆排序、快速排序这些在数组排序时性能非常好的算法,在链表只能“顺序访问”的魔咒下无法施展能力;但是归并排序却如鱼得水,非但保持了它O(nlogn)的时间复杂度,而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)。真是好得不得了啊,哈哈。以上程序是递推法的程序,另外值得一说的是看看那个时间复杂度,是不是有点眼熟?对!这就是分治法的时间复杂度,归并排序又是divide
and conquer。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐