这篇是写单链表中是否有环的判断,环的长度,以及环的起始节点问题的思路以及实现。
第一个问题就是判断是否有环:
使用2个引用和一个循环可以解决这个问题,一个引用一次向后走2个节点,称为fast,一个引用一次向后走一个节点,称为slow,当fast与slow相遇时证明这个单链表有环,代码如下:
public boolean haveCircle(){
Node fast = this.head;
Node slow = this.head;
while(fast != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
return true;
}
}
return false;
}
第二个问题,环的长度,只需要记录下碰撞点的地址,从碰撞点的下一个节点遍历,再次回到这个点走过的节点数就是长度,代码如下:
public int getCircleNodeNum(){
if(this.haveCircle() == false){
return 0;
}
else{
Node fast = this.head;
Node slow = this.head;
Node p = null;
int count = 0;
while(fast != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
p = fast;
slow = slow.next;
count+=1;
break;
}
}
while(slow != p){
slow = slow.next;
count++;
}
return count;
}
}
最后一个问题,寻找循环的头,也就是这个环的连接点,遇到用到这个东西:
**碰撞点到连接点的距离 = 头指针到连接点的距离**
有了这个,一个引用从头开始走,另一个从碰撞点走,2个相遇时的那个节点就是这个环的连接点,代码如下:
public Node firstCircleNode(){
if(this.haveCircle() == false){
return null;
}
else{
Node fast = this.head;
Node slow = this.head;
while(fast != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
break;
}
}
slow = head;
while(slow != fast){
slow = slow.next;
fast = fast.next;
}
return slow;
}
}