判断单链表有环的三种方法

来源:互联网 发布:c语言程序的基本模块 编辑:程序博客网 时间:2024/06/11 12:59
判断链表是否有环的三种方法 

1. 在节点ListNode中增加一个域,用于记录此节点是否已经被访问,如下ListNode中被注释掉代码。此方法简单,能找出环开始的节点,但是增加了链表的开销。如果链表非常大 则需要十分大的内存来保存此域。

2. 使用链表逆序的方法。从头结点开始一直将链表逆序,头结点的next域为空。如果有环的话链表逆序必定会回到头节点而终止。这种做法同样简单,确保O(n)时间终止算法。但是修改了链表结构。原链表已经被改变。但是不能找出环开始的节点

3. 使用两个变量赛跑,一个变量走两步/次,一个变量走一步/次。 如果有环则两个变量必定会相逢,其中快的变量比慢的变量多走一圈。此算法 如果链表的环非常大 则需要较大的遍历时间。此算法同时也能找出环开始的地方


   class ListNode {      int val;      ListNode next;
 // Boolean visited=false;       ListNode(int x) {          val = x;         next = null;      }  } 
方法一:
 public class Solution {    public boolean hasCycle(ListNode head) {      if (head == null || head.next == null)return false;while(head!=null){
if(head.visited==false;)
   head.visited=true;
else
   return true;  //同时第一个vistited为true的节点即为环开始的节点。
head=head.next;
}return false;    }}

方法二:

public class Solution {
 public boolean hasCycle(ListNode head) {      if (head == null || head.next == null)return false;ListNode p = head;ListNode q = head.next;ListNode k = head.next.next;while (k != null) {if (p == k || k == head)return true;if (p == head)p.next = null;q.next = p;p = q;q = k;k = k.next;}return false;    }}

方法三:

/*找出环开始的节点证明:设链表长度为N(每个节点访问一次) 链表头到达环开始节点长度为 s ,环的大小为S因为 快节点比慢节点多跑一圈 到达相遇节点, 设n为循环的次数。 所以有 2*n-n=S =》 n=S,即到达相遇节点的时候慢节点相当于刚好走了一个环的大小。所以慢节点走完链表N剩下的节点为N-S。而从头节点到环开始的距离s =N-S。所以头结点和慢节点同时再走N-S步即能在环开始的地方相遇。*/

public class Solution {
    public ListNode detectCycle(ListNode head) {        ListNode meetNode = fineNode(head);if (meetNode == null)   //有相遇的节点就说明有环,没有就没有环return null;
while (meetNode != head) {
head = head.next;meetNode = meetNode.next;}return meetNode;    }        public static ListNode fineNode(ListNode head) {if (head == null)return null;ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null) {   //两个变量赛跑,找出相遇的节点fast = fast.next.next;slow = slow.next;if (fast == slow) {return slow;}}return null;}}


 
原创粉丝点击