1. 程式人生 > >判斷單鏈表中是否有環(循環鏈表)

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

創建 代碼實現 分享圖片 post 圖片 sca struct init 技術

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

技術分享圖片

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

方法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 }

運行結果:

技術分享圖片

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