什么是环?
单链表有环,是指单链表中某个节点的next指针域指向的是链表中在它之前的某一个节点,这样在链表的尾部形成一个环形结构。
如上图,最后一个节点指向了第三个节点,所以后面四个节点构成了一个环,怎么判断单链表是否有环呢?
一.快慢指针法判断有无环:
1.算法思路:可以定义快慢指针(fast和slow),让fast每次步径是slow的两倍,因为fast是两步两步走,所以注意循环条件(fast!=null && fast.next!=null),如果单链表有环,fast速度是slow的两倍,所以肯定会有一个时刻两个指针相遇,相遇即代表链表有环。
(就和在操场上跑步的两个人一样,操场就代表着一个环,一个速度是另一个的两倍,速度快的肯定会有一个时刻追上速度慢的且处在同一个位置)
2.参考代码:
import java.util.List;
class ListNode{
public int data;
public ListNode next;
public ListNode(int data){
this.data=data;
this.next=null;
}
}//节点类
class MySignalList {
public ListNode head;
public MySignalList() {
this.head = null;
}
//尾插法
public void addLast(int data) {
ListNode node = new ListNode(data);
if (this.head == null) {
this.head = node;
} else {
ListNode cur = head;
while (cur.next != null) {
cur = cur.next;
}
cur.next = node;
}
}
//人为创造一个环
public void cycle(){
ListNode cur=this.head;
while(cur.next!=null){
cur=cur.next;
}
cur.next=this.head.next;
}
//有无环
public boolean hasCycle(){
ListNode fast=this.head;
ListNode slow=this.head;
while(fast!=null && fast.next!=null){
slow=slow.next; //slow每次走一步
fast=fast.next.next; //fast每次走两步
if(slow==fast){ //判断两指针是否相遇
return true;
}
}
return false;
}
}
public class Test {
public static void main(String[] args) {
MySignalList my = new MySignalList();
my.addLast(1);
my.addLast(5);
my.addLast(76);
my.addLast(12);
my.addLast(16);
my.cycle();
boolean i=my.hasCycle();
if(i==true){
System.out.println("有环");
}else{
System.out.println("没有环");
}
}
}
//打印结果
有环
二.判断环入口点
1.算法思路:
①先找到快慢指针第一次相遇的位置
②把其中一个指针拉到链表头
③之后再让快慢指针一人一步走,再次相遇的点就是环的入口处
2.原理如图:
假设链表总长为n,表头到环入口点距离为x,环入口点到第一次相遇的位置为y。因为fast速度是slow的两倍,所以fast走过的距离是slow的两倍
即2(x+y)=n+y ----- n=2x+y,所以可得第一次相遇点到链表尾部距离也为x,将slow移到head位置,此时可以看到slow距离环的入口点距离为x,fast距离环的入口点距离也为x,两个距离环入口点距离相等,之后一人一步走,肯定会在环的入口点相遇。
3.参考代码:
public ListNode detectCycle(){
ListNode fast=this.head;
ListNode slow=this.head;
//先找到第一次相遇的时候
while(fast!=null && fast.next!=null){
slow=slow.next;
fast=fast.next.next;
if(fast==slow){
break;
}
}
if(fast==null || fast.next==null){
return null;
}
//让slow或者fast到头那里
slow=this.head;
while(slow!=fast){
slow=slow.next;
fast=fast.next;
}
return slow;
}