单链表找环

15年腾讯的实习生招聘笔试题出现了这个经典问题:在只知道链表头指针的情况下,怎么判断链表中是否存在环。如果有环,判断环有多大,环的入口节点在哪里。

对这几个问题,整理了一下网友提供的思路,自己动手实现了一下。

首先,判断环的存在。用两个指针,分别以一次走一步和一次走两步的速度遍历单链表,若有环,两指针肯定会在环中相遇,若没有,快指针会先遍历到NULL跳出

bool findc(node*head)
{ node*fast=head,*slow=head;
   while(fast&&fast->next)
   {fast=fast->next->next;
     slow=slow->next;
     if(fast==slow) break;
   }
   return !(fast==NULL || fast->next==NULL);
}

其次,判断环有多大。我们知道在环中,若快慢两指针从同一点出发,前进过程中第一次相遇时快指针肯定比慢指针多走一整圈。而快指针速度是慢指针的2倍,因此慢指针走的路程刚好是一圈:2vt=vt+C 即:vt=C

   int i=0;
   node*p=x;   //x是环中某节点
   node*q=x; 
   do{p=p->next->next;
      q=q->next;
      i++;
   }while(p!=q);
   cout<<"Size of circle is "<<i<<endl;


最后,判断环的起始点。如果,单链表头节点到环起始点距离a,快慢指针相遇点到环起始点距离x,在找环的过程中有S=a+x,2S=a+x+nC,则a+x=nC,即a=nC-x.

由此知道,若在头结点和相遇结点分别设一指针,同时出发,单步前进,则最后一定相遇在环入口相遇。

#include<iostream>
#include<malloc.h>

using namespace std;

typedef struct node{
int num;
node* next;
}node;

node*createlist(int n)   //创建单链表
{ node*head=NULL,*t,*r=NULL;
   for(int i=0;i<n;i++)
   {  t=(node*)malloc(sizeof(node));
      t->num=i+1;
      t->next=NULL;
      if(!head) {head=t;
      r=t;}
      else  r->next=t;
      r=t;
  }
    return head;
}


node* findcx(node*head)    //返回快慢指针相遇节点的找环函数,bool findc(node*head)的变形
{ node*fast=head,*slow=head;
   while(fast&&fast->next)
   {fast=fast->next->next;
     slow=slow->next;
     if(fast==slow) break;
   }
   bool flag =!(fast==NULL || fast->next==NULL);
   if(flag)
   { cout<<"A circle exist in the list"<<endl; 
      return fast;
   }else{ 
   cout<<"No circle!"<<endl;
   return NULL;}
}

int main()
{  node*l1=createlist(7);
   node*l2=createlist(8);
   node*s=l1;
   int i=7-1,j=8;
   while(i--) s=s->next;
   s->next=l2;
   while(j--) s=s->next;
   s->next=l2;       //初始化带环的单链表
  
   i=15;
   node*t=l1;
   while(t&&i--)
   { cout<<t->num<<" ";
     t=t->next;
   }
   cout<<endl;        //打印单链表

   node*x=findcx(l1);
   cout<<"Cross point: "<<x->num<<endl;
   node*p=l1,*q=x;
   while(p&&q)
   { p=p->next;
     q=q->next;
     if(p==q)break;
   }
   cout<<"Entrance of the circle: "<<q->num<<endl;   //判断环入口

   i=0;
   p=q=x;
   do{p=p->next->next;
           q=q->next;
           i++;
   }while(p!=q);
   cout<<"Size of circle is "<<i<<endl;              //判断环size
   return 1;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值