网站首页 > java教程 正文
判断链表是否为带环链表
方法一、快慢指针移动判断
首先如何判断链表是否有环,这个时候首先需要知道链表是否为空,如果不为空,则继续判断。
思路:首先定义两个变量,一个fast,一个slow,让fast 每次走两步,slow每次走一步,当fast和slow相遇时,即是该链表存在环结构。如果该链表为无环结构,则当遍历完这个链表时也不会相遇。即是返回false。
图例如下:
图中为了说明情况,
fast指针初始标记为f0,每移动一次加1,如f1,f2,f3....
slow指针初始标记为s0,每移动一次加1,如s1,s2,s3....
代码实现如下:
//初始化一个有环的链表Node
Node nodeA = new Node("A");
Node nodeB = new Node("B");
Node nodeC = new Node("C");
Node nodeD = new Node("D");
Node nodeE = new Node("E");
Node nodeF = new Node("F");
nodeA.next = nodeB;
nodeB.next = nodeC;
nodeC.next = nodeD;
nodeD.next = nodeE;
nodeE.next = nodeF;
nodeF.next = nodeD;//此时F节点又指向了D节点,已经产生了环状
/**
* 判断链表是否有环 (快慢指针的方式)
* <-----------------
* | |
* [A] -> [B] -> [C] -> [D] -> [E] -> [F]
*
* 初始指针 f0
* s0
* 第一次 s1 f1
* 第二次 s2 f2
* 第三次 s3/f3
* 本例中即第三次遍历就判断出链表有环
* @param node
* @return
*/
private boolean hasCycle(Node node) {
if (node == null) {
return false;
}
Node fast = node;
Node slow = node;
//此字段仅用来记录遍历次数
int traverseCount = 0;
while (fast != null && fast.next != null && slow != null) {
fast = fast.next.next;//移动2步
slow = slow.next;//移动1步
traverseCount ++;
if (fast == slow) {
//如果碰面,就代表有环
Log.d(TAG, "hasCycle==>有环...traverseCount="+traverseCount);
return true;
}
Log.d(TAG, "hasCycle==>已经遍历次数...traverseCount="+traverseCount);
}
Log.d(TAG, "hasCycle==>无环");
return false;
}
方法二:使用Set<>集合记录Node元素,如果有重复元素则认为有环
代码实现如下:
/**
* 通过Set集合记录值的方式,如果有重复的数据,就代表有环
* @param node
* @return
*/
private boolean hasCycle2(Node node) {
Set<Node> nodeSet = new HashSet<>();
//此字段仅用来记录遍历次数
int traverseCount = 0;
while (node != null) {
if (nodeSet.contains(node)) {
Log.d(TAG, "hasCycle2==>有环...traverseCount="+traverseCount);
return true;
}
traverseCount ++;
Log.d(TAG, "hasCycle2==>traverseCount="+traverseCount);
nodeSet.add(node);
node = node.next;
}
Log.d(TAG, "hasCycle2==>无环");
return false;
}
三、扩展:(内容参考:https://blog.csdn.net/weixin_40879743/article/details/90646399)
如果链表有环,找到有环的入口点是哪个节点(如上图,入口点就是节点D,下面要找到这个节点)
思路:s=vt(路程=速度*时间)用方程思想列等式解
因为路程知道,速度知道(二倍关系),时间也知道(相等),所以可以列等式求关系。再用代码体现出关系,就可以解决这道题了。
如图:假设链表是Link fast是快的那个指针,Slow是慢的呢个指针,蓝色是fast走过的路程,绿色是slow走过的路程
K是环的入口,P是快慢指针相遇的地方
a,b,c 分别代表三段长度。
所以图就可以变成:
然后,让指针从 相遇点p 和 起始点first 同时遍历,这样由于 c = a , 所以p和first在k相遇,而k就是入口点。
代码实现如下:
/**
* 如果有环,获取相遇点的node
* @param node
* @return
*/
private Node getMeetNode(Node node) {
if (node == null) {
return null;
}
Node fast = node;
Node slow = node;
//此字段仅用来记录遍历次数
int traverseCount = 0;
while (fast != null && fast.next != null && slow != null) {
fast = fast.next.next;//移动2步
slow = slow.next;//移动1步
traverseCount ++;
if (fast == slow) {
//如果碰面,就代表有环
Log.d(TAG, "hasCycle==>有环...traverseCount="+traverseCount);
return fast;
}
Log.d(TAG, "hasCycle==>已经遍历次数...traverseCount="+traverseCount);
}
return null;
}
/**
* 如果有环,获取环出现的入口点
* @return
*/
public Node getCycleEntry(Node node) {
Node meetNode = getMeetNode(node);
Node p = meetNode;//相遇点元素的指针
Node first = node;//链表第一个元素的指针
while(p != first) {
//两个指针都进行移动,当相等的时候就找到了入口点
first = first.next;
p = p.next;
}
return p;
}
/**
* 将入口点打印出来:
*/
Node entryNode = getCycleEntry(nodeA);
Log.d(TAG, "有环的链表入口点Node Value="+entryNode.value);
链接:https://www.jianshu.com/p/3d6cd4f9a518
来源:简书
看了我的文章,肯定想要资料,是的话就别走啦,请你帮我转发点赞赞赞赞+关注我,然后想要完整版资料的私信回复暗号【06】即可免费获取
- 上一篇: JAVA 反转链表
- 下一篇: Java手写单向链表
猜你喜欢
- 2024-12-31 删除链表中重复的节点
- 2024-12-31 LeetCode每日一题,合并K个升序链表
- 2024-12-31 算法学习之合并两个有序链表
- 2024-12-31 面试必问-JAVA-LRU-双向链表+HashMap方式实现
- 2024-12-31 两个有序链表的合并
- 2024-12-31 【约瑟夫环】C语言数组法+java循环链表法
- 2024-12-31 Java手写单向链表
- 2024-12-31 JAVA 反转链表
- 2024-12-31 算法篇:图解双向链表及Java实现
- 2024-12-31 剑指Offer (十五):反转链表(Java版)
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)