数据结构与算法--判断环存在与否

给一个单链表,判断其中是否有环的存在
 两个思路: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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值