老钟古

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

链表反转

单向链表的反转是一个经常被问到的一个面试题,也是一个非常基础的问题。比如一个链表是这样的: 1->2->3->4->5 通过反转后成为5->4->3->2->1。最容易想到的方法遍历一遍链表,利用一个辅助指针,存储遍历过程中当前指针指向的下一个元素,然后将当前节点元素的指针反转后,利用已经存储的指针往后面继续遍历。源代码如下:

代码
 1 struct linka {
 2      int data;
 3      linka* next;
 4 };
 5 
 6 void reverse(linka*& head)
 7 {
 8      if(head ==NULL)
 9           return;
10      linka*pre, *cur, *ne;
11      pre=head;
12      cur=head->next;
13      while(cur)
14      {
15           ne = cur->next;
16           cur->next = pre;
17           pre = cur;
18           cur = ne;
19      }
20      head->next = NULL;
21      head = pre;
22 }
23 

 

还有一种利用递归的方法。这种方法的基本思想是在反转当前节点之前先调用递归函数反转后续节点。源代码如下。不过这个方法有一个缺点,就是在反转后的最后一个结点会形成一个环,所以必须将函数的返回的节点的next域置为NULL。因为要改变head指针,所以我用了引用。算法的源代码如下:
代码
 1 linka* reverse(linka* p,linka*& head)
 2 {
 3      if(p == NULL || p->next == NULL)
 4      {
 5           head=p;
 6           return p;
 7      }
 8      else
 9      {
10           linka* tmp = reverse(p->next,head);
11           tmp->next = p;
12           return p;
13      }
14 }
15 

 

 判断链表是否有环(转)

写一算法检测单向链表中是否存在环(whether there is a loop in a link list), 要求算法复杂度(Algorithm's complexity是O(n)) 并只使用常数空间(space is O(c)).
注意,你只知道一个指向单向链表头的指针。链表的长度是不定的,而且环出现的地方也是不定的,环有可能在头,有可能在中间。而且要求是检测, 不能破坏环的结构。

算法思路:用两个指针来遍历这个单向链表,第一个指针p1,每次走一步;第二个指针p2,每次走两步;当p2指针追上p1的时候,就表明链表当中有环路了。

 

代码
 1 int testLinkRing(Link *head)
 2 {
 3   Link *t1=head,*t2=head;
 4   while( t1->next && t2->next)
 5   {
 6       t1 = t1->;next;
 7       if (NULL == (t2 = t2->next->next))
 8           return 0;   //无环
 9       if (t1 == t2)
10           return 1// 有环
11    }
12    return 0;
13 }

 

如果要定位环路在链表当中的开始点,则可以采用下面的方法:当发现p2和p1重合,确定了单向链表有环路了,接下来,让p2回到链表的头部,重新走,P1也继续走,每次步长都走1,那么当p1和p2再次相遇的时候,就是环路的入口了。

 

posted on 2010-09-26 23:46  老钟古  阅读(407)  评论(0编辑  收藏  举报