原理:
假设链表节点依次从左向右排列,p为链表头,即第一个节点,q为链表第二个节点,且设置p每次向右走一步,q每次向右走两步,
1.若链表没有环,则在q等于null之前,p永远追不上q,即q到链表尾部时即可确定该链表没有环;
2.若链表有环,则q会回到p的左边,当q最接近p时,有下面两种情况:
(1)p和q再向右走一步,则会相遇
(2)p和q再向右走两步,则会相遇
即在p和q相遇时即可判断该链表有环
代码如下
public class Node
{
private int value;
private Node next;
public Node()
{
}
public Node(int value)
{
super();
this.value = value;
}
public int getValue()
{
return value;
}
public void setValue(int value)
{
this.value = value;
}
public Node getNext()
{
return next;
}
public void setNext(Node next)
{
this.next = next;
}
}
public class Link
{
/**
* 判断一个单向链表是否有环
*
* @param head
* 表头
* @return
*/
public static boolean isLoopLink(Node head)
{
// 如果是空链表,则没有环
if (null == head)
{
return false;
}
// 第一个节点
Node p = head;
// 第二个节点
Node q = head.getNext();
// 只有一个节点自环
if (p == q)
{
return true;
}
while (p != q && null != p && null != q)
{
p = p.getNext();
if (null != q.getNext())
{
q = q.getNext().getNext();
}
else
{
q = null;
}
if (p == q)
{
return true;
}
}
return false;
}
}
单元测试
public class LinkTest
{
/**
* 空链表
*/
@Test
public void test1()
{
Node node1 = null;
assertFalse(Link.isLoopLink(node1));
}
/**
* 只有一个节点
*/
@Test
public void test2()
{
Node node1 = new Node(1);
assertFalse(Link.isLoopLink(node1));
}
/**
* 单节点自环
*/
@Test
public void test3()
{
Node node1 = new Node(1);
node1.setNext(node1);
assertTrue(Link.isLoopLink(node1));
}
/**
* 多节点无环
*/
@Test
public void test4()
{
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(node4);
assertFalse(Link.isLoopLink(node1));
}
/**
* 多节点首尾相连有环
*/
@Test
public void test5()
{
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(node4);
node4.setNext(node1);
assertTrue(Link.isLoopLink(node1));
}
/**
* 多节点非首尾相连有环
*/
@Test
public void test6()
{
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
node1.setNext(node2);
node2.setNext(node3);
node3.setNext(node4);
node4.setNext(node2);
assertTrue(Link.isLoopLink(node1));
}
}
测试结果