思路分析
假设,现在有一个存在环的单链表。
// null->node1->node2->node3->node4->node5->node6->node1
对其进行分析,可以设置2个“指针”。
singleStep 每次向后 更新一个节点;doubleStep 每次向后更新两个节点。
步骤如下:
java代码
public class Linked {
// Node静态类
private static class Node {
private Integer data;
private Node next;
Node(){}
Node(Integer data){
this(data, null);
}
Node(Integer data, Node next){
this.data = data;
this.next = next;
}
}
/**
* 判断单链表是否有环。
* @param head 头指针
* @return 有环返回true,否则返回false
*/
public static boolean isLoop(Node head) {
// 指针,头指针的下一个为单步,下一个的下一个是双步
Node singleStep = head.next;
Node doubleStep = head.next.next;
// 存在2个以上的结点时
while(doubleStep != null) {
Integer num1 = singleStep.data;
Integer num2 = doubleStep.data;
// 当值相同时,说明是存在环了
if(num1 == num2) return true;
// 更新2个节点
singleStep = singleStep.next;
doubleStep = doubleStep.next.next;
// 双步的结点先更新到链表尾部,说明不存在环
if(doubleStep == null) return false;
}
// 只存在一个节点,必然是环
return true;
}
public static void main(String[] args) {
Node head = new Node();// 头为null
// 6个节点
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
Node node5 = new Node(5);
Node node6 = new Node(6);
// 创建有环链表
// null->node1->node2->node3->node4->node5->node6->node3
head.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = node5;
node5.next = node6;
node6.next = node1;
boolean loop = isLoop(head);
System.out.println(loop);
}
}
打印结果:true
总结分析
单链表是否存在环,重要的一点需要明白,有环时是什么情况,这里的条件是当【链表中存在两个节点的值相同时,因为我的数据是Integer类型的,所以可以直接使用==来判断其值是否相同。】
当存储的数据是对象类型时,尽可能的使用equals方法来比较。
另外,当整个链表只有1个节点时,判断其是有环的;当其链表中有2个及2个以上的节点时,对其值进行比较,当值相同时就判断为有环,当值不同时,更新指针的位置,单步指针跳一步,双步指针跳两步,直到双步指针跳到null,证明其已经到了链表的尾部,说明是没有环的。
注意:优化,在Node中可以重写equals方法,因为这是链表,比较Node节点即可,但是什么情况下的Node是相等的就需要自己去定义了。
/**
* 自定义equals方法。
* 当数据和传入的对象的数据(Integer类型)的data相同时。
*/
@Override
public boolean equals(Object obj) {
return this.data == ((Node)obj).data;
}
// 当值相同时,说明是存在环了
if(singleStep.equals(doubleStep)) return true;
不再继续比较值,而是比较Node节点是否相同。