给定一个单链表,
1 判断该连表是否存在环
2 如何知道环的长度
3 如何找到环的连接点
4 连表的长度
定义一个节点:
public class Node {
public String value ;
public Node next ;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
public class IsCricle {
public static void main(String[] args) {
Node node = new Node() ;
node.setValue("node");
Node node01 = new Node() ;
node01.setValue("node01");
Node node02 = new Node() ;
node02.setValue("node02");
Node node03 = new Node() ;
node03.setValue("node03");
Node node04 = new Node() ;
node04.setValue("node04");
Node node05 = new Node() ;
node05.setValue("node05");
Node node06 = new Node() ;
node06.setValue("node06");
Node node07 = new Node() ;
node07.setValue("node07");
Node node08 = new Node() ;
node08.setValue("node08");
node.setNext(node01);
node01.setNext(node02);
node02.setNext(node03);
node03.setNext(node04);
node04.setNext(node05);
node05.setNext(node06);
node06.setNext(node07);
node07.setNext(node08);
node08.setNext(node02);
IsCricle isCricle = new IsCricle() ;
// boolean flag = isCricle.isCricle(node) ;
// System.out.println("result = " + flag ) ;
/**
* slow->1->2->3->4->5->6->7->8->2->3->4->5->6
* fast->2->4->6->8->3->5->7->3->5->7->2->4->6
*/
// int size = isCricle.cricleSize(node);
// System.out.println("size = " + size ) ;
// isCricle.findLoopNode(node) ;
int size = isCricle.size(node);
System.out.println(size);
}
/**
* 判断单链表中是否存在闭环
* 主题思想:设定两个指针slow,fast.从头开始分别走一步和两步,如果存在环则两者相遇,如果不存在环fast遇到null退出
* @param node
* @return
*/
public boolean isCricle(Node node){
Node fast = node ;
Node slow = node ;
int i = 0 ;
while( fast != null && fast.next != null ){
slow = slow.next ;
fast = fast.next.next ;
if( slow == fast ){
System.out.println("i=" + i++);
return true ;
}
++i ;
}
return false ;
}
/**
* 环的长度
* 主题思想:在判断是否为闭环时找到碰撞点,然后slow,fast从该点开始继续执行,再次碰撞所走过的操作就是环的长度s
* @param node
* @return
*/
public int cricleSize( Node node ){
Node fast = node ;
Node slow = node ;
while( fast != null && fast.next != null ){
slow = slow.next ;
fast = fast.next.next ;
if( slow == fast ){
break ;
}
}
if( fast == null || fast.next == null ){
return 0 ;
}
int i = 1 ;
slow = slow.next ;
fast = fast.next.next ;
while(slow != fast){
slow = slow.next ;
fast = fast.next.next ;
i++ ;
}
return i ;
}
/**
* 环的连接点
* 基本思想:碰撞点p到连接点的距离等于头指针到连接点的距离,因此分别从碰撞点和头指针开始遍历,相遇的点即为连接点
* @param node
* @return
*/
public Node findLoopNode( Node node ){
Node fast = node ;
Node slow = node ;
while( fast != null && fast.next != null ){
slow = slow.next ;
fast = fast.next.next ;
if( slow == fast ){
break ;
}
}
if( fast == null || fast.next == null ){
return null ;
}
slow = node ;
while(slow != fast){
slow = slow.next ;
fast = fast.next ;
}
// System.out.println(slow.value);
return slow ;
}
/**
* 计算连表的长度:
* 1 计算环的长度
* 2 计算头结点到连接点的长度
* 3 1+2
* @param node
* @return
*/
public int size( Node node ){
int cricleSize = cricleSize(node);
Node loopNode = findLoopNode( node ) ;
while( node != loopNode ){
node = node.next ;
cricleSize++ ;
}
return cricleSize ;
}
}