问题:如何判断一个单向链表中是否存在环?

例如:

链表中存在环(B-->D):

     <-- <--^
| |
v |
A-->B-->C-->D 链表中不存在环: A-->B-->C-->D-->E-->F

解题思路:

  从一个实际的生活场景出发,两个人,在一个环形的操场上跑步的时候,如果有一个人跑得比另一个人还要快,那么,在n圈之后,这两个人总会在操场上的某个点相遇。将操场类比于链表中存在的环路径,将两个人看成两个指针,那么这道题的解题思路就自然而然的出来了。

具体步骤如下:

  1. 初始化两个指针a,b,同时指向链表的开头
  2. a指针走一步,b指针走两步(我们姑且将a指针称为慢指针,将b指针称为快指针)
  3. 重复步骤2,直到b指针无法继续往下走两步或者a,b指针相遇
  4. 当b指针无法继续往下走两步的时候,说明链表中不存在环,b指针即将走到链表的末尾端。
  5. 当a,b指针相遇,说明链表中存在环,因为只有存在环的情况,a,b指针才有可能会在环中的某个点相遇

具体代码如下:

/**
* @author 学徒
*
* 用于判断链表中是否存在环
*
*/
public class CycleLinkedList {
/**
* 循环链表中的节点类
*/
static class Node<T>{
//节点值
T value;
//节点的下一个节点的指针
Node<T> next;
public Node(T value){
this(value,null);
}
public Node(T value,Node next){
this.next=next;
this.value=value;
}
} /**
* 用于判断该链表中是否存在着环
* @param head 链表的头节点
* 当存在环时,返回true,否则返回false
*/
public boolean judge(Node head) {
if(head==null){
return false;
}
//两个指向头结点的指针
Node a=head,b=head;
while(true){
if(b.next==null||b.next.next==null){
return false;
}
a=a.next;
b=b.next.next;
if(a==b){
return true;
}
} } public static void main(String[] args){
Node<String> a=new Node<String>("A");
Node<String> b=new Node<String>("B");
Node<String> c=new Node<String>("C");
Node<String> d=new Node<String>("D");
a.next=b;
b.next=c;
c.next=d;
d.next=b;
CycleLinkedList list=new CycleLinkedList();
boolean result=list.judge(a);
System.out.println("链表中环的结果:"+result);
}
}

  从上面的链表中是否存在环的问题,可以延伸出与链表中是否存在环相关的另一个问题

问题: 链表中构成环的元素的个数应该如何计算?

  对于这个问题,我们稍微沿着解决上面的链表存在环的问题的思路继续往下想,当链表中存在环的时候,快慢指针相遇,那么这个时候,我们只需要让快指针停留在相遇的位置,让慢指针再次走一遍,边走边记录步数,当快慢指针再次相遇的时候,慢指针所走的步数,便是构成环的链表的环中元素个数。

我们只需要稍微修改下上面的代码即可,具体代码如下:

/**
* @author 学徒
*
* 用于判断链表中是否存在环
*
*/
public class CycleLinkedList {
/**
* 循环链表中的节点类
*/
static class Node<T>{
//节点值
T value;
//节点的下一个节点的指针
Node<T> next;
public Node(T value){
this(value,null);
}
public Node(T value,Node next){
this.next=next;
this.value=value;
}
} /**
* 用于判断该链表中是否存在着环
* @param head 链表的头节点
* 当存在环时,返回环中元素个数,否则返回0
*/
public int judge(Node head) {
if(head==null) {
return 0;
}
//两个指向头结点的指针
Node a=head,b=head;
while(true){
//当出现该情况的时候,说明无环
if(b.next==null||b.next.next==null){
return 0;
}
a=a.next;
b=b.next.next;
//当其存在环
if(a==b){
int number=1;
a=a.next;
while(a!=b){
a=a.next;
number++;
}
return number;
}
} } public static void main(String[] args){
Node<String> a=new Node<String>("A");
Node<String> b=new Node<String>("B");
Node<String> c=new Node<String>("C");
Node<String> d=new Node<String>("D");
a.next=b;
b.next=c;
c.next=d;
d.next=b;
CycleLinkedList list=new CycleLinkedList();
int result=list.judge(a);
System.out.println(result);
}
}

  顺着上面的问题继续的往下想,我们可以延伸出另一个问题

问题:我们是否可以得到第一个进入该链表的环的节点的元素?

  对于该问题,我们可以通过以下的方式得到该节点。

  1. 将快指针重新指向链表的头节点
  2. 快指针和慢指针同时走,当快指针和慢指针相遇时,该节点便是链表中第一个进入环的节点

ps:以上只是一个结论的步骤总结。实际上,可以通过分析得到,在环中,快慢指针第一次相遇时的节点位置与进入环的第一个节点的顺时针方向的距离同链表头节点到进入环中第一个节点的位置的距离相等。

具体代码如下:

/**
* @author 学徒
*
* 用于判断链表中是否存在环
*
*/
public class CycleLinkedList {
/**
* 循环链表中的节点类
*/
static class Node<T>{
//节点值
T value;
//节点的下一个节点的指针
Node<T> next;
public Node(T value){
this(value,null);
}
public Node(T value,Node next){
this.next=next;
this.value=value;
}
} /**
* 用于判断该链表中是否存在着环
* @param head 链表的头节点
* 当存在环时,返回环中元素个数,否则返回0
*/
public Node judge(Node head) {
if(head==null) {
return null;
}
//两个指向头结点的指针
Node a=head,b=head;
while(true){
//当出现该情况的时候,说明无环
if(b.next==null||b.next.next==null){
return null;
}
a=a.next;
b=b.next.next;
//当其存在环
if(a==b){
b=head;
while(a!=b){
a=a.next;
b=b.next;
}
return b;
}
} } public static void main(String[] args){
Node<String> a=new Node<String>("A");
Node<String> b=new Node<String>("B");
Node<String> c=new Node<String>("C");
Node<String> d=new Node<String>("D");
a.next=b;
b.next=c;
c.next=d;
d.next=b;
CycleLinkedList list=new CycleLinkedList();
Node result=list.judge(a);
System.out.println(result.value);
}
}

主目录:

回到目录|·(工)·)

Q:判断链表中是否存在环的相关问题的更多相关文章

  1. <数据结构>XDOJ323.判断有向图中是否有环

    问题与解答 问题描述 判断有向图中是否有环. 输入格式 输入数据第一行是一个正整数,表示n个有向图,其余数据分成n组,每组第一个为一个整数,表示图中的顶点个数n,顶点数不超过100,之后为有向图的邻接 ...

  2. LeetCode -- 推断链表中是否有环

    思路: 使用两个节点.slow和fast,分别行进1步和2步.假设有相交的情况,slow和fast必定相遇:假设没有相交的情况,那么slow或fast必定有一个为null 相遇时有两种可能:1. 仅仅 ...

  3. 查找链表中是否有环linked-list-cycle

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...

  4. [Leetcode] Linked list cycle 判断链表是否有环

    Given a linked list, determine if it has a cycle in it. Follow up:Can you solve it without using ext ...

  5. leetcode - 链表两两元素交换 + 判断链表有无环

    链表两两元素交换 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表. 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换. 示例: 给定 1->2->3->4, 你 ...

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

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Foll ...

  7. POJ 1860 Currency Exchange(如何Bellman-Ford算法判断图中是否存在正环)

    题目链接: https://cn.vjudge.net/problem/POJ-1860 Several currency exchange points are working in our cit ...

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

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. To r ...

  9. 判断链表是否有环(Java实现)

    判断给定的链表中是否有环.如果有环则返回true,否则返回false. 解题思路:设置两个指针,slow和fast,fast每次走两步,slow每次走一步,如果有环的话fast一定会追上slow,判断 ...

随机推荐

  1. Atcoder Tenka1 Programmer Contest 2019题解

    传送门 \(C\ Stones\) 最后肯定形如左边一段白+右边一段黑,枚举一下中间的断点,预处理一下前缀和就可以了 int main(){ // freopen("testdata.in& ...

  2. Python任意网段Web端口信息探测工具

    此篇关于多线程工具的文章,非常适合新手学习,工具效率也挺高的,代码也比较完善,如题. 本文作者:i春秋签约作家——Aedoo 0×00 前言 笔者前一段时间发布了原创文章,“[Python黑客] Py ...

  3. php 删除二维数组中某个key值

    /** * 根据key删除数组中指定元素 * @param array $arr 数组 * @param string/int $key 键(key) * @return array */ priva ...

  4. [微信小程序]——bug记录

    记录日常开发小程序遇到的一些小问题: input 输入框(unfixed) 描述:输入框focus的时候,placeholder会往上面跳动一下 当 scroll-view 遇上 fixed 描述:给 ...

  5. 【Hight Performance Javascript】——脚本加载和运行

    脚本加载和运行 当浏览器遇到一个<script>标签时,无法预知javascript是否在<p>标签中添加内容.因此,浏览器停下来,运行javascript代码,然后继续解析. ...

  6. 非常好用的@ResponseBody注解

    AJAX的写法: ajax接收json格式: ①如果ajax接收的是text dataType:"text", var json = eval("(" + da ...

  7. css实现响应式九宫格效果

    1. 首先看下九宫格的效果图: 2. html代码比较简单,如下: <div class="main"> <div class="box1"& ...

  8. Redis客户端使用

    http://wenku.baidu.com/view/6ccd650af12d2af90242e63d.html 一.下载jedis 代码 jedis 代码地址:https://github.com ...

  9. Java序列化接口Serializable接口的作用总结

    一.Java序列化接口Serializable的作用: 一个对象有对应的一些属性,把这个对象保存在硬盘上的过程叫做”持久化”. 对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字 ...

  10. (转)ldd 查看程序依赖库

    原文:https://blog.csdn.net/u010977122/article/details/52993560?spm=a2c4e.11153940.blogcont551034.8.4f7 ...