链表环算法

来源:互联网 发布:学泰语软件 编辑:程序博客网 时间:2024/05/17 09:15
1:链表有环的定义
所谓链表有环,就是指链表的尾指针指向链表中的某一个节点

方法1:设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。
代码实现:
int HasLoop(LinkList L)
{
   int step1=1;
   int step2=2;
   LinkList p=L;
   LinkList q=L;
   //p和q都先指向第一个节点,初始时p和q都不为空
   while(p!=NULL&&q!=NULL&&q->next!=NULL)
   {
   //p向后移1位
      p=p->next;
  //如果q的后继不为空,q向后移2位
  if(q->next!=NULL)
  {
  q=q->next->next;
  }
  //判断p是否等于q,如果等于,返回1,表示有环;
  if(p==q)
  {
  return 1;
  }
   
   
   }
   return 0;


}


2:如何知道环的长度?

思路:记录下问题1的碰撞点p,p是此环中的节点,p往后走,当再次走到次碰撞点的时候就说明走了一圈;这个就为长度

 //根据上述代码可获得碰撞点的指针,作为此函数的参数
static int GetCircleLength(Link point)
{
int length = 1;
Link curr = point;
//只要当前节点的后继不等于碰撞点
while (curr.Next != point)
{
//长度加1
length++;
curr = curr.Next;
}
return length;
}


3:如何找到环的“起始”点呢?
思路:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。

slist* FindLoopPort(slist *head)
{
    slist *slow = head, *fast = head;

    while ( fast && fast->next ) 
    {
        slow = slow->next;
        fast = fast->next->next;
        if ( slow == fast ) break;
    }

    if (fast == NULL || fast->next == NULL)
        return NULL;

    slow = head;
    while (slow != fast)
    {
         slow = slow->next;
         fast = fast->next;
    }

    return slow;
}

4:带环链表的长度是多少?
思路:问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度