判斷一個單鏈表是否存在環

判斷一個單鏈表是否有環及環的鏈接點(轉)
給定一個單鏈表,只給出頭指針h:
1、如何判斷是否存在環?
2、如何知道環的長度?
3、如何找出環的連接點在哪裏?
4、帶環鏈表的長度是多少?


解法:
1、對於問題1,使用追趕的方法,設定兩個指針slow、fast,從頭指針開始,每次分別前進1步、2步。如存在環,則兩者相遇;如不存在環,fast遇到NULL退出。
2、對於問題2,記錄下問題1的碰撞點p,slow、fast從該點開始,再次碰撞所走過的操作數就是環的長度s。
3、問題3:有定理:碰撞點p到連接點的距離=頭指針到連接點的距離,因此,分別從碰撞點、頭指針開始走,相遇的那個點就是連接點。(證明在後面附註)
4、問題3中已經求出連接點距離頭指針的長度,加上問題2中求出的環的長度,二者之和就是帶環單鏈表的長度
void Isloop(Llink head)
{
 if(!head||!head->next)
  return;
 Llink p,q;
 bool loop=false;
 p=q=head->next;
 while(q&&q->next)//判斷是否有環
 {
  p=p->next;
  q=q->next->next;
  if(p==q)
  {
   loop=true;
   break;
  }
 }
 if(!loop)
  cout<<"This link has not loop\n";
 else
 {
  cout<<"This link has a loop\n";
  Llink r=p;
  q=head->next;
  int nonloop=1,loopcount=1;
  //nonloop計算非環結點數,loopcount計算環上結點數
  do//計算環上的結點數
  {
   p=p->next;
   ++loopcount;
  }while(p!=r);
  --loopcount;
  while(p!=q)//得到環的入口結點,同時計算得到非環的結點數
  {
   p=p->next;
   q=q->next;
   ++nonloop;
  }
  --nonloop;
  cout<<"\nStart of loop: "<<p->data<<endl;  
  cout<<"\nCount of nonloop: "<<nonloop
      <<"\nCount of loop: "<<loopcount
      <<"\nCount of Linknode: "<<nonloop+loopcount<<endl;
 }
}
  
//判斷是否存在環的程序:
bool IsExitsLoop(slist *head)  
{  
    slist *slow = head, *fast = head;  
    while ( fast && fast->next )   
    {  
        slow = slow->next;  
        fast = fast->next->next;  
        if ( slow == fast ) break;  
    }    
    return !(fast == NULL || fast->next == NULL);  
}  
 
//尋找環連接點(入口點)的程序:
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;  
} 
//亦可以用類似與hash表的方法,即設立一個數組,將鏈表結點中的值做數組下標,當賦值衝突時就是環的接入點
bool isloop(Llink p)
{
 if(!p||!p->next)
  return true;
 int a[MAXSIZE],n=0;
 memset(a,0,sizeof(int)*MAXSIZE);
 p=p->next;
 while(p)
 {
  if(a[p->data]==-1)//存在環時,會發生衝突
  {
   cout<<"\nLoop node: "<<p->data<<endl
    <<"\nLen of node: "<<n<<endl;
   return true;
  }
  a[p->data]=-1;
  ++n;
  p=p->next;
 }
 return false;
}
Llink CreatlinkLoop()
//創建一個有環的鏈表
{
 Llink head=new Lnode;
 //head->data=0;
 head->next=NULL;
 Lelemtype e;
 Llink q=head;
 int N=0;
 cout<<"input elems:";
 while(cin>>e)
 {
  Llink p=new Lnode;
  ++N;
  p->data=e;
  p->next=q->next;
  q->next=p;
  q=p;
 }
 cin.clear();
 cin.sync();
 srand(time(0));
 q->next=Findnode(head,rand()%N);//隨機產生環的接入點
 return head;
}
Llink Findnode(Llink head,int n)//找出鏈表中的第n個結點
{
 if(n<=0)
  return head;
 Llink p=head->next;
 for(int i=1;p&&i<n;++i)
  p=p->next;
 return p;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章