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

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 *,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       =
 head;
15         tail =
 NULL;
16         nmerges = 0
;
17         while
 (p)
18           nmerges++ = p;  psize = 0
;
19             for (i = 0< nstep; i++
)
              {
20                 psize++
;
21                 = 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->next; qsize--;
                  }
28                 else
                     if (q == NULL || qsize == 0       
                     {
                       e = p; = p->next; psize--;
                     }
29                   else
                       if (cmp(p,q) <= 0)
                       {
                          e = p; = p->next; psize--;
                        }
30                     else
                        {
                           = q; = q->next; qsize--;
                         }
31                 if (tail != NULL)
                      {
                           tail->next = e;
                       }
32                 else{head =
 e;}
33                 tail =
 e;
34 
              }
35             =
 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值