您的位置:首页 > 其它

如何判断链表有环

2019-07-27 22:29 1571 查看

                                                    如何判断链表有环

前天晚上临睡觉前看到了公众号脚本之家推送的一篇文章,文章内容是一道算法题,并给出了思路解释,但没有具体源码实现,这让我觉得少了点什么,于是,趁周末,我补齐了缺失的内容,好了,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:

https://github.com/Thinker-Mars/ByteDance

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: