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

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

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

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

运行结果:

原文地址:https://www.cnblogs.com/geziyu/p/9903952.html

时间: 2024-11-08 13:17:04

判断单链表中是否有环(循环链表)的相关文章

数据结构和算法设计专题之---判断单链表中是否有环,环的长度,环的入口节点

题目: 给定一个单链表,只给出头指针head: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的

判断单链表里面有没有环

原文链接:http://www.cnblogs.com/zhyg6516/archive/2011/03/29/1998831.html 这题目还是挺有意思的. 题目:0.如何判断单链表里面是否有环? 算法的思想是设定两个指针p, q,其中p每次向前移动一步,q每次向前移动两步.那么如果单链表存在环,则p和q相遇:否则q将首先遇到null. 这里主要理解一个问题,就是为什么当单链表存在环时,p和q一定会相遇呢? 假定单链表的长度为n,并且该单链表是环状的,那么第i次迭代时,p指向元素i mod

判断单向链表中是否有环和查找环的入口

快慢指针 算法描述 定义两个指针slow, fast.slow指针一次走1个结点,fast指针一次走2个结点.如果链表中有环,那么慢指针一定会再某一个时刻追上快指针(slow == fast).如果没有环,则快指针会第一个走到NULL. 实现 结点定义如下: class Node { public Node next; public Object data; public static int sequence = 0; } 算法: /** * 快慢指针 * @param head * @ret

[LeetCode] Linked List Cycle II 单链表中的环之二

Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Follow up: Can you solve it without using extra space? 这个求单链表中的环的起始点是之前那个判断单链表中是否有环的延伸,可参见我之前的一篇文章 (http://www.cnblogs.com/grandyang/p/4137187.html). 还是要设

如何判断单链表中有环及证明过程

问题: 1.如何判断单链表里面是否有环? 算法的思想是设定两个指针p, q,其中p每次向前移动一步,q每次向前移动两步.那么如果单链表存在环,则p和q相遇:否则q将首先遇到null. 这里主要理解一个问题,就是为什么当单链表存在环时,p和q一定会相遇呢? 假定单链表的长度为n,并且该单链表是环状的,那么第i次迭代时,p指向元素i mod n,q指向2i mod n.因此当i≡2i(mod n)时,p与q相遇.而i≡2i(mod n) => (2i - i) mod n = 0 => i mod

如何判断单链表是否存在环

原文:http://blog.csdn.net/liuxialong/article/details/6555850 如何判断单链表是否存在环 给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,

求有环单链表中的环长、环起点、链表长

1.判断单链表是否有环 使用两个slow, fast指针从头开始扫描链表.指针slow 每次走1步,指针fast每次走2步.如果存在环,则指针slow.fast会相遇:如果不存在环,指针fast遇到NULL退出. 就是所谓的追击相遇问题: 2.求有环单链表的环长 在环上相遇后,记录第一次相遇点为Pos,之后指针slow继续每次走1步,fast每次走2步.在下次相遇的时候fast比slow正好又多走了一圈,也就是多走的距离等于环长. 设从第一次相遇到第二次相遇,设slow走了len步,则fast走

11.判断单链表是否有环

判断单链表是否有环:   这里也是用到两个指针,如果一个链表有环,那么用一个指针去遍历,是永远走不到头的.   因此,我们用两个指针去遍历:first指针每次走一步,second指针每次走两步,如果first指针和second指针相遇,说明有环.时间复杂度为O (n). 方法 // 方法:检测单链表是否有环 public boolean hasCycle(Node head) { if (head == null) { return false; } Node first = head; Nod

判断单链表是否有环及寻找环的入口

一.判断单链表是否有环 1.遍历链表 遍历链表,将已经访问过的结点,设置为已访问,如果访问同一结点两次,则说明有环,时间O(n),空间O(n). 2.链表反转 遍历链表,将访问的结点指针反向.如果存在环,反转后next指向原链表头,但链表反转会破坏链表的结构,反转需要注意缓存当前结点的下一结点,时间O(n),空间(1). 3.快慢指针 设置快慢两个指针fast和slow,两个指针都链表头开始,fast每次移动2步,slow为1步.如果存在环,则fast先进入环,slow后进入环,最后两者在环中相