如何判断链表有环
如何判断链表有环
前天晚上临睡觉前看到了公众号脚本之家推送的一篇文章,文章内容是一道算法题,并给出了思路解释,但没有具体源码实现,这让我觉得少了点什么,于是,趁周末,我补齐了缺失的内容,好了,no code, no bb,我们开始吧。
题目描述:
有一个单向链表,链表中有可能出现“环”,就像下图这样。那么,如何用程序来判断该链表是否为有环链表呢?(图片来自公众号)
//单向链表
public class SingleLinkedList {
private Node head;//标识头节点
private int size;//标识链表中节点个数
public SingleLinkedList() {
this.size = 0;
this.head = null;
}
//node类
private class Node{
private Object data;//每个节点的数据
private Node next;//指向下一个节点的链接
public Node(Object data) {
this.data = data;
}
}
/**
* 将节点插入链表
* @param data 带插入的值
*/
public void add(Object data) {
Node temp = head;
if (size == 0) {
head = new Node(data);
size++;
return;
}
while (temp.next != null) {
temp = temp.next;
}
temp.next = new Node(data);
size++;
}
/**
* 从头开始遍历节点
*/
public void display() {
if (size > 0) {
Node node = head;
if (size == 1) {
System.out.println("[" + node.data + "]");
return;
}
while (node != null) {
System.out.println(node.data);
node = node.next;
}
} else {
System.out.println("[]");
}
}
}
View Code
方法1如下:
/** * 根据索引得到链表的某个节点的值 * @param key * @return */ public Object getNode(int key) { if (key < 0 || key > size - 1) { throw new ArrayIndexOutOfBoundsException("越界!"); } else { Node temp = head; int count = 0; while (temp != null) { if (count == key) { return temp.data; } temp = temp.next; count++; } } return null; } /** * 从头开始,依次与给定索引位置的节点的值进行比较,如果相同,则返回true,否则false * @param key * @return */ public boolean havaSameElement(int key) { boolean flag = false; int count = 0; Node temp = head; while (temp != null && count < key) { if (temp.data == getNode(key)) { flag = true; return flag; } count++; temp = temp.next; } return flag; } /** * 方式1 * @return */ public boolean isAnnulate1() { boolean flag = false; for (int i = 1; i < size; i++) { if (havaSameElement(i)) { flag = true; break; } } return flag; }
方法2:
这种方法用到了HashSet中add方法去重的特点,思路是这样的:
① new一个HashSet,用来存储之前遍历过的节点值
②从头节点head开始,依次遍历链表中的节点,并把它add到集合中
③ 如果在集合中已经有一个相同的值,那么会返回false,这样便证明链表有环,退出遍历
方法2如下:
/** * 方式2 * @return */ public boolean isAnnulate2() { boolean flag = false; Set<Object> set = new HashSet<>(); Node temp = head; while (temp != null) { if (!set.add(temp.data)) { flag = true; break; } temp = temp.next; } return flag; }
方法3:
定义两个指针tortoise与rabbit,让它们一开始均指向head头节点,之后,tortoise每次向后移动一个节点,rabbit每次向后移动2个节点,只要这个链表是有环的,它们必定会在某一次移动完后相遇,什么?你问我为什么?我们来思考这样一个问题,两个人在运动场跑步,他们的起始位置都是一样的,当开跑后,只有在两种情况下,他们的位置会重合,第一就是他们的速度始终一致,第二就是跑得快的那个人套圈,如下图所示:
package judgeLinkedListCircle; import java.util.HashSet; import java.util.Set; /** * 单向链表 * @author Cone * @since 2019年7月27日 * */ public class SingleLinkedList { private Node head;//标识头节点 private int size;//标识链表中节点个数 public SingleLinkedList() { this.size = 0; this.head = null; } //node类 private class Node{ private Object data;//每个节点的数据 private Node next;//指向下一个节点的链接 public Node(Object data) { this.data = data; } } /** * 将节点插入链表 * @param data 带插入的值 */ public void add(Object data) { Node temp = head; if (size == 0) { head = new Node(data); size++; return; } while (temp.next != null) { temp = temp.next; } temp.next = new Node(data); size++; } /** * 从头开始遍历节点 */ public void display() { if (size > 0) { Node node = head; if (size == 1) { System.out.println("[" + node.data + "]"); return; } while (node != null) { System.out.println(node.data); node = node.next; } } else { System.out.println("[]"); } } /** * 根据索引得到链表的某个节点的值 * @param key * @return */ public Object getNode(int key) { if (key < 0 || key > size - 1) { throw new ArrayIndexOutOfBoundsException("越界!"); } else { Node temp = head; int count = 0; while (temp != null) { if (count == key) { return temp.data; } temp = temp.next; count++; } } return null; } /** * 从头开始,依次与给定索引位置的节点的值进行比较,如果相同,则返回true,否则false * @param key * @return */ public boolean havaSameElement(int key) { boolean flag = false; int count = 0; Node temp = head; while (temp != null && count < key) { if (temp.data == getNode(key)) { flag = true; return flag; } count++; temp = temp.next; } return flag; } /** * 方式1 * @return */ public boolean isAnnulate1() { boolean flag = false; for (int i = 1; i < size; i++) { if (havaSameElement(i)) { flag = true; break; } } return flag; } /** * 方式2 * @return */ public boolean isAnnulate2() { boolean flag = false; Set<Object> set = new HashSet<>(); Node temp = head; while (temp != null) { if (!set.add(temp.data)) { flag = true; break; } temp = temp.next; } return flag; } public Node getIntersect() { Node temp = head; Node tortoise = temp; Node rabbit = temp; while (rabbit != null && rabbit.next != null) { tortoise = tortoise.next; rabbit = rabbit.next.next; if (tortoise == rabbit) { return tortoise; } } return null; } /** * 方式3 * @return */ public Object isAnnulate3() { Node temp = head; if (temp == null) { return null; } Node intersect = getIntersect(); if (intersect == null) { return null; } Node startNode = head; while (startNode != intersect) { startNode = startNode.next; intersect = intersect.next; } return startNode.data; } }View Code 如有错误,欢迎指正。
代码已上传至github:
- 如何判断两个单向链表是否有相交,并找出交点
- 如何判断链表是否有环?如何计算环的长度?
- 如何判断两个链表相交及找到第一个相交点
- 如何判断链表是否有环
- (转)如何判断链表中是否有环
- 如何判断链表有环
- 如何判断链表中是否有环
- 如何判断链表相交
- 如何判断链表有环
- 如何判断两个链表相交及找到第一个相交点
- 如何判断链表中是否有环
- 如何判断链表是否有环
- 漫画算法:如何判断链表有环?
- 如何判断 单链表中是否存在环 ( How judges in Singly Linked List whether has a circle )
- 如何判断单链表是否存在环 & 判断两链表是否相交
- 如何判断两个单向链表是否有相交,并找出交点
- 如何判断两个链表是否相交并求出相交点
- 如何判断链表有环?
- 如何判断一个单向链表是否有环路
- 如何判断两个链表相交及找到第一个相交点