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

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

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

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

运行结果:

posted @ 2018-11-04 14:49  无心小男  阅读(5909)  评论(0编辑  收藏  举报