判断单链表中是否有环(循环链表)

Posted geziyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了判断单链表中是否有环(循环链表)相关的知识,希望对你有一定的参考价值。

有环的定义:链表的尾结点指向了链表中的某个结点,如下图所示

技术分享图片

判断是否有环,两种方法:

方法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
",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
",ListLength(L));
119     printf("
1.创建有环链表(尾插法)
2.创建无环链表(头插法)
3.判断链表是否有环 
0.退出

请选择你要的操作:
");
120     while(opp != 0){
121         scanf("%c",&opp);
122         switch(opp){
123             case 1:
124                 CreateListTail(L,10);
125                 printf("成功创建有环链表L(尾插法)
");
126                 printf("
");
127                 break;
128                 
129             case 2:
130                 CreateListHead(L,10);
131                 printf("成功创建无环链表L(头插法)
");
132                 printf("
");
133                 break;
134             
135             case 3:
136                 printf("方法一:

");
137                 if(HasLoop1(L)){
138                     printf("结论:链表有环


");
139                 }
140                 else{
141                     printf("结论:链表无环


");
142                 }
143                 printf("方法二:

");
144                 if(HasLoop2(L)){
145                     printf("结论:链表有环


");
146                 }
147                 else{
148                     printf("结论:链表无环


");
149                 }
150                 printf("
"); 
151                 break;
152             case 4:
153                 exit(0);     
154         }
155     } 
156     return 0;
157 }

运行结果:

技术分享图片

以上是关于判断单链表中是否有环(循环链表)的主要内容,如果未能解决你的问题,请参考以下文章

循环链表基础

循环链表

快慢指针判断单链表是否有环

小猪的数据结构辅助教程——2.4 线性表中的循环链表

4. 单向循环链表

单向循环链表