數據結構與算法--判斷環存在與否

給一個單鏈表,判斷其中是否有環的存在
 兩個思路:1、如果鏈表元素沒有重複的,則可以用一個set集合存放鏈表的value,查看是否有重複的
       2、如果有重複的,可以設置兩個快慢指針fast、slow,若是fast能夠追上slow則有環
public class LinkedList {


    public void print(LinkedNode<Integer> root){
        LinkedNode<Integer>  tmp = root;
        while (tmp!=null){
            System.out.print(tmp.value+" ");
            tmp = tmp.next;
        }
        System.out.println();
    }
    //創建鏈表
    public LinkedNode<Integer> constructLinkedList(LinkedNode<Integer>... nodes){
        LinkedNode<Integer>  root = new LinkedNode<>(0);
        LinkedNode<Integer>  tmp  = root;
        for(LinkedNode<Integer> node:nodes){
            tmp.next = node;
            tmp = tmp.next;
        }
        return root.next;
    }


    /**
     * 2、給一個單鏈表,判斷其中是否有環的存在
     * 思路:1、如果鏈表元素沒有重複的,則可以用一個set集合存放鏈表的value,查看是否有重複的
     *       2、如果有重複的,可以設置兩個快慢指針fast、slow,若是fast能夠追上slow則有環
     */
    @Test
    public void test2(){
        LinkedNode<Integer>  node11 = new LinkedNode<>(1);
        LinkedNode<Integer>  node12 = new LinkedNode<>(3);
        LinkedNode<Integer>  node13 = new LinkedNode<>(5);
        LinkedNode<Integer>  node14 = new LinkedNode<>(8);
        LinkedNode<Integer>  node15 = new LinkedNode<>(9);
        LinkedNode<Integer>  node16 = new LinkedNode<>(10);
        LinkedNode<Integer>  node17 = new LinkedNode<>(12);
        LinkedNode<Integer>  node18 = new LinkedNode<>(11);
        LinkedNode<Integer>  node19 = new LinkedNode<>(17);

        LinkedNode<Integer>  root = constructLinkedList(node11,node12,node13,node14,node15,node16,node17,node18,node19);
        node19.next = node15;

        //方法1  set法
        LinkedNode<Integer>  tmp = root;

        Set<Integer> set = new HashSet<>();
        while (tmp!=null){
            if(set.contains(tmp.value)){
                System.out.println("this linked list has circle and it's start node is "+tmp.value);
                break;
            }
            set.add(tmp.value);
            tmp = tmp.next;
        }

        //方法2:快慢法
 /**
         * 快慢法原理
         * a、第一步,找環中相匯點。分別用fast,slow指向鏈表頭部,slow每次走一步,fast每次走二步,直到fast==slow找到在環中的相匯點。
         *
         * b、第二步,找環的入口。接上步,當fast==slow時,fast所經過節點數爲2x,slow所經過節點數爲x,
         *          設環中有n個節點,fast比slow多走一圈有2x=n+x; n=x;
         *
         * 可以看出slow實際走了一個環的步數,再讓fast指向鏈表頭部,slow位置不變。
         *
         *   假設鏈表開頭到環接口的距離是y,如下圖所示,那麼x-y表示slow指針走過的除鏈表開頭y在環中走過的距離,那麼slow再走y步,
         *    此時fast結點與slow結點相遇,fast == slow ,x-y+y=x = n,即此時slow指向環的入口。
         */
        LinkedNode<Integer>  fast = root;
        LinkedNode<Integer>  slow = root;
        int x = 0;
        int circleLen = 0;  //鏈表環的長度
        while (fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            circleLen ++;
            x ++;
            if(fast.value == slow.value){
                System.out.println("x = "+x);
                break;
            }
        }
        fast = root;
        int startToCircleHeadLen = 0; // 鏈表頭結點到環接口距離
        while (fast!=null && slow!=null){
            fast = fast.next;
            slow = slow.next;
            startToCircleHeadLen ++;
            if(fast.value == slow.value){
                System.out.println("circle start value : "+fast.value);
                break;
            }
        }
        System.out.println("circle len = "+circleLen);
        System.out.println("startToCircleHead len = "+startToCircleHeadLen);

        //此時 slow節點在環的接口處
        //尋找距離接口節點最遠的節點
        LinkedNode<Integer>  circleStartNode = slow;
        while (slow!=null && fast !=null){
            slow = slow.next;
            fast = fast.next.next;
            if(circleStartNode == fast || circleStartNode.next == fast){
                System.out.println("circle start node = "+circleStartNode.value+",max len node = "+slow.value);
                break;
            }
        }


    }

   
}

輸出:

this linked list has circle and it's start node is 9
this linked list has circle 
circle start value : 9
circle len = 5
startToCircleHead len = 4
circle start node = 9,max len node = 11

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章