判斷單鏈表中是否有環(循環鏈表)


有環的定義:鏈表的尾結點指向了鏈表中的某個結點,如下圖所示

判斷是否有環,兩種方法:

方法1:使用p、q兩個指針,p總是向前走,但q每次都從頭開始走,對於每個節點看p走的步數和q是否一樣,如上圖所示:當p從6走到3時,共走了6步,此時若q從出發,則q只需要走兩步就到達3的位置,因而步數不相等,出現矛盾,存在環。

方法2:快慢指針,定義p、q兩個指針,p指針每次向前走一步,q每次向前走兩步,若在某個時刻出現 p == q,則存在環。

具體代碼實現:

  1 #include<stdio.h>
  2 #include<iostream>
  3 #include<stdlib.h>
  4 #include<string.h>
  5 #include<malloc.h>
  6 #include<time.h>
  7 using namespace std;
  8 
  9 #define OK 1
 10 #define ERROR 0
 11 #define TRUE 1
 12 #define FALSE 0
 13 
 14 typedef struct Node{
 15     int data;
 16     struct Node *next;
 17 }Node,*LinkList;
 18 
 19 int InitList(LinkList &L){//初始化帶頭結點的空鏈表 
 20     L = (LinkList)malloc(sizeof(Node));//產生頭結點,並使L指向此頭結點 
 21     if(!L)//如果存儲分配失敗 
 22         return ERROR;
 23     L->next = NULL;//指針域為空 
 24     return OK;
 25 }
 26 
 27 int ListLength(LinkList &L){//返回鏈表L中數據元素個數 
 28     int i = 0;
 29     LinkList p;
 30     p = L->next;
 31     while(p){
 32         i++;
 33         p = p->next;
 34     }
 35     return i; 
 36 }
 37 
 38 //隨機產生n個元素的值,建立帶頭結點的單鏈表L(頭插法) 
 39 void CreateListHead(LinkList &L, int n){
 40     LinkList p;
 41     srand(time(0));
 42     for(int i = 0; i < n; i++){
 43         p = (LinkList)malloc(sizeof(Node));
 44         p->data = rand()%100+1;
 45         p->next = L->next;
 46         L->next = p; 
 47     }
 48 } 
 49 
 50 //隨機產生n個元素的值,建立帶頭結點的單鏈表L(尾插法) 
 51 void CreateListTail(LinkList &L, int n){
 52     LinkList r,p;
 53     r = L;
 54     srand(time(0));//初始化隨機數種子
 55     for(int i = 0; i < n; i++){
 56         p = (LinkList)malloc(sizeof(Node));
 57         p->data = rand()%100+1;//隨機產生100以內的數字
 58         r->next = p;
 59         r = p; 
 60     } 
 61     r->next = NULL;
 62     p->next = L->next->next;//成環 
 63 }
 64 
 65 //比較步數的方法 
 66 int HasLoop1(LinkList &L)
 67 {
 68     LinkList cur1 = L;//定義結點cur1 
 69     int post1 = 0;//cur1的步數
 70     while(cur1)
 71     {//cur1結點存在 
 72         LinkList cur2 = L;//定義結點cur2
 73         int post2 = 0;//cur2的步數
 74         while(cur2)
 75         {//cur2結點存在 
 76             if(cur2 == cur1)
 77             {//當cur1和cur2達到相同結點時 
 78                 if(post1 == post2)//走過的步數一樣 
 79                     break;//則沒有環 
 80                 else//否則 
 81                 {
 82                     printf("環的位置在第%d個結點處。",post2);
 83                     return 1;    
 84                 }
 85             }
 86             cur2 = cur2->next;//如果沒有發現環,則繼續下一個結點
 87             post2++;//cur2步數自增1     
 88         }
 89         cur1 = cur1->next;//cur1繼續向后一個結點 
 90         post1++;//cur2步數自增1    
 91     }
 92     return 0; 
 93 }
 94 
 95 //利用快慢指針的方法
 96 int HasLoop2(LinkList &L){
 97     int step1 = 1;
 98     int step2 = 2;
 99     LinkList p = L;
100     LinkList q = L;
101     while(p != NULL && q != NULL && q->next != NULL){
102         p = p->next;
103         if(p->next != NULL)
104             q = q->next->next;
105         printf("p:%d,q:%d\n",p->data,q->data);
106         if(p == q)
107             return 1;
108     }
109     return 0;
110 } 
111 
112 int main(){
113     LinkList L;
114     InitList(L); 
115     int i,e,find,temp;
116     char opp;
117     i = InitList(L);
118     printf("初始化L后,ListLength(L)=%d\n",ListLength(L));
119     printf("\n1.創建有環鏈表(尾插法)\n2.創建無環鏈表(頭插法)\n3.判斷鏈表是否有環 \n0.退出\n\n請選擇你要的操作:\n");
120     while(opp != '0'){
121         scanf("%c",&opp);
122         switch(opp){
123             case '1':
124                 CreateListTail(L,10);
125                 printf("成功創建有環鏈表L(尾插法)\n");
126                 printf("\n");
127                 break;
128                 
129             case '2':
130                 CreateListHead(L,10);
131                 printf("成功創建無環鏈表L(頭插法)\n");
132                 printf("\n");
133                 break;
134             
135             case '3':
136                 printf("方法一:\n\n");
137                 if(HasLoop1(L)){
138                     printf("結論:鏈表有環\n\n\n");
139                 }
140                 else{
141                     printf("結論:鏈表無環\n\n\n");
142                 }
143                 printf("方法二:\n\n");
144                 if(HasLoop2(L)){
145                     printf("結論:鏈表有環\n\n\n");
146                 }
147                 else{
148                     printf("結論:鏈表無環\n\n\n");
149                 }
150                 printf("\n"); 
151                 break;
152             case '4':
153                 exit(0);     
154         }
155     } 
156     return 0;
157 }

運行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM