判断单链表中是否有环(循环链表)
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 }
运行结果:
以上是关于判断单链表中是否有环(循环链表)的主要内容,如果未能解决你的问题,请参考以下文章