常见链表操作-链表中环的检测(JAVA实现)
问题
如何检测一个单链表中是否有环,例如下图的例子。
解决思路1:快慢指针法
这是最常见的方法。思路就是有两个指针P1和P2,同时从头结点开始往下遍历链表中的所有节点。
P1是慢指针,一次遍历一个节点。
P2是快指针,一次遍历两个节点。
如果链表中没有环,P2和P1会先后遍历完所有的节点。
如果链表中有环,P2和P1则会先后进入环中,一直循环,并一定会在在某一次遍历中相遇。
因此,只要发现P2和P1相遇了,就可以判定链表中存在环。
实现代码
public class LinkADT<T> {
/**
* 单链表节点
*
* @author wangtao
* @param <T>
*/
private static class SingleNode<T> {
public SingleNode<T> next;
public T data;
public SingleNode(T data) {
this.data = data;
}
public T getNextNodeData() {
return next != null ? next.data : null;
}
}
/**
* 判断是否有环 快慢指针法
*
* @param node
* @return
*/
public static boolean hasLoopV1(SingleNode headNode) {
if(headNode == null) {
return false;
}
SingleNode p = headNode;
SingleNode q = headNode.next;
// 快指针未能遍历完所有节点
while (q != null && q.next != null) {
p = p.next; // 遍历一个节点
q = q.next.next; // 遍历两个个节点
// 已到链表末尾
if (q == null) {
return false;
} else if (p == q) {
// 快慢指针相遇,存在环
return true;
}
}
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
解决思路2:足迹法
顺序遍历链表中所有的节点,并将所有遍历过的节点信息保存下来。如果某个节点的信息出现了两次,则存在环。
实现代码
public class LinkADT<T> {
/**
* 单链表节点
*
* @author wangtao
* @param <T>
*/
private static class SingleNode<T> {
public SingleNode<T> next;
public T data;
public SingleNode(T data) {
this.data = data;
}
public T getNextNodeData() {
return next != null ? next.data : null;
}
}
// 保存足迹信息
private static HashMap<SingleNode, Integer> nodeMap = new HashMap<>();
/**
* 判断是否有环 足迹法
*
* @param node
* @return
*/
public static boolean hasLoopV2(SingleNode node, int index) {
if (node == null || node.next == null) {
return false;
}
if (nodeMap.containsKey(node)) {
return true;
} else {
nodeMap.put(node, index);
return hasLoopV2(node.next, ++index);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
总结
分别从时间复杂度与内存复杂度比较两种方法。快慢指针法的时间复杂度更高,内存复杂度更低。除此之外,足迹法额外引入了其它的数据结构:散列表。
从面试的角度看,快慢指针法更符合面试的意图。而从实际工作的角度看,快慢指针法更难理解,代码也不好写,我更推荐用足迹法。
完整代码请参考:
https://github.com/wanf425/Algorithm/blob/master/src/com/wt/adt/LinkADT.java
博文地址
https://www.taowong.com/blog/2018/10/07/data-strutctures-and-algorithm-02.html
---------------------
作者:Tao的博客
来源:CSDN
原文:https://blog.csdn.net/wanf425/article/details/83048761
常见链表操作-链表中环的检测(JAVA实现)的更多相关文章
- 第三百零八节,Django框架,models.py模块,数据库操作——链表结构,一对多、一对一、多对多
第三百零八节,Django框架,models.py模块,数据库操作——链表结构,一对多.一对一.多对多 链表操作 链表,就是一张表的外键字段,连接另外一张表的主键字段 一对多 models.Forei ...
- 六 Django框架,models.py模块,数据库操作——链表结构,一对多、一对一、多对多
链表操作 链表,就是一张表的外键字段,连接另外一张表的主键字段 一对多 models.ForeignKey()外键字段一对多,值是要外键的表类 from __future__ import unico ...
- JAVA 链表操作:循环链表
主要分析示例: 一.循环链表简述 二.单链表循环链表 三.双链表循环链表 一.循环链表简述 循环链表即链表形成了一个循环的结构,尾节点不再指向NULL,而是指向头节点HEAD,此时判定链表的结束是尾节 ...
- JAVA 链表操作:单链表和双链表
主要讲述几点: 一.链表的简介 二.链表实现原理和必要性 三.单链表示例 四.双链表示例 一.链表的简介 链表是一种比较常用的数据结构,链表虽然保存比较复杂,但是在查询时候比较便捷,在多种计算机语言都 ...
- linux 内核的链表操作(好文不得不转)
以下全部来自于http://www.ibm.com/developerworks/cn/linux/kernel/l-chain/index.html 无任何个人意见. 本文详细分析了 2.6.x 内 ...
- Python链表操作(实现)
Python链表操作 在Python开发的面试中,我们经常会遇到关于链表操作的问题.链表作为一个非常经典的无序列表结构,也是一个开发工程师必须掌握的数据结构之一.在本文中,我将针对链表本身的数据结构特 ...
- Python面试常考点之深入浅出链表操作
Python面试常考点之深入浅出链表操作 在Python开发的面试中,我们经常会遇到关于链表操作的问题.链表作为一个非常经典的无序列表结构,也是一个开发工程师必须掌握的数据结构之一.在本文中,我将针对 ...
- 算法入门 - 链表的实现及应用(Java版本)
之前我们学习了动态数组,虽然比原始数组的功能强大了不少,但还不是完全纯动态的(基于静态数组实现的).这回要讲的链表则是正儿八经的动态结构,是一种非常灵活的数据结构. 链表的基本结构 链表由一系列单一的 ...
- 单链表操作B 分类: 链表 2015-06-07 12:42 15人阅读 评论(0) 收藏
数据结构上机测试2-2:单链表操作B TimeLimit: 1000ms Memory limit: 65536K 题目描述 按照数据输入的相反顺序(逆位序)建立一个单链表,并将单链表中重复的元素删除 ...
随机推荐
- lighttpd 轻量级WEB服务器
Lighttpd 是一款开源 Web 服务器软件.Lighttpd 安全快速,符合行业标准,适配性强并且针对高配置环境进行了优化.相对于其它的 Web 服务器而言,Lighttpd 占用内存更少:因其 ...
- 性能调优必备:NIO的优化实现原理
前言 我们就从底层的网络 I/O 模型优化出发,再到内存拷贝优化和线程模型优化,深入分析下 Tomcat.Netty 等通信框架是如何通过优化 I/O 来提高系统性能的. 网络 I/O 模型优化 网络 ...
- Django(44)drf序列化源码分析(1)
序列化与反序列化 一般后端数据返回给前端的数据格式都是json格式,简单易懂,但是我们使用的语言本身并不是json格式,像我们使用的Python如果直接返回给前端,前端用的javascript语言 ...
- Go语言标准库log介绍
Go语言标准库log介绍 无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志一直都是非常重要的一个环节,我们也应该养成在程序中记录日志的好习惯. log Go语言内置的log包实现了简单的日志服 ...
- Java读取SQL server数据库
要打开SQL server 的三个服务,然后再执行代码. package com.sql; import java.sql.SQLException; import java.sql.Statemen ...
- 太方便了!利用Python对批量Pdf转Word
在wps或者office里面可以将pdf转word,不过只能免费转前面5页,超过5页就需要会员.今天教大家一个Python办公小技巧:批量Pdf转Word ,这样可以自由想转多少页都可以. 思路:这里 ...
- Go string 详解
前言 字符串(string) 作为 go 语言的基本数据类型,在开发中必不可少,我们务必深入学习一下,做到一清二楚. 本文假设读者已经知道切片(slice)的使用,如不了解,可阅读 Go 切片 基本知 ...
- git stash的常用操作
列出stash的: git stash list移除stash: git stash drop stash@{0}查看stash: git stash sho ...
- EasyExcel 框架使用-读
EasyExcel 框架使用 官方介绍:JAVA解析Excel工具EasyExcel Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内 ...
- 深入理解java虚拟机笔记Chapter2
java虚拟机运行时数据区 首先获取一个直观的认识: 程序计数器 线程私有.各条线程之间计数器互不影响,独立存储. 当前线程所执行的字节码行号指示器.字节码解释器工作时通过改变这个计数器值选取下一条需 ...