判断链表是否有环的算法

1, 两个指针同时遍历 ,一个快一个慢 互相追赶。

第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。
第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈(也可能多走了N圈,不影响计算)有2x=n+x; n=x;可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口。
 public static ListNode findEntryNode(ListNode pHead) {
        if (pHead == null || pHead.next == null)
            return null;
        ListNode p1 = pHead;
        ListNode p2 = pHead;

        while (p2 != null && p2.next != null) {
            p1 = p1.next;
            p2 = p2.next.next;
            if (p1 == p2) {
                p2 = pHead;
                while (p1 != p2) {
                    p1 = p1.next;
                    p2 = p2.next;
                }
                return p1;
            }
        }
        return null;
    }


2,直接遍历比较

用一个set去保存遍历过的节点,遍历下一个的时候去检查是否已经存在遍历过的节点中,如果有那就是环的入口,找不到就是没有环。

public static ListNode findEntryNode2(ListNode pHead) {
        if (pHead == null)
            return null;

        Set<ListNode> set = new HashSet<>();
        set.add(pHead);
        ListNode node = pHead.next;
        while (node != null) {
            if(set.contains(node)){
                return node;
            }
            set.add(node);
            node = node.next;
        }
        return null;
    }

3,测试结果两个思路都是正确的

public static void main(String args[]){
        ListNode<Integer> node = new ListNode<>();
        node.setElement(0);
        ListNode<Integer> head = node;
        //15个节点的直链
        for(int i = 0; i < 15; i++){
            node.next = new ListNode<>();
            node = node.next;
            node.setElement(i +1);
        }
        //标记一个环链入口
        ListNode<Integer> entry = node;
        //再建10个节点的直链,但是还没有环
        for(int i = 15; i <25; i++){
            node.next = new ListNode<>();
            node = node.next;
            node.setElement(i +1);
        }

        //查询结果应该是null
        ListNode listNode = findEntryNode(head);
        ListNode listNode2 = findEntryNode2(head);
        System.out.println(listNode == null);
        System.out.println(listNode2 == null);

        //将链的最后一个节点链接到入口节点形成环
        node.next = entry;

        //查询结果应该是就是入口节点entry
        listNode = findEntryNode(head);
        listNode2 = findEntryNode2(head);
        System.out.println(listNode == entry);
        System.out.println(listNode2 == entry);
    }










猜你喜欢

转载自blog.csdn.net/sunjin9418/article/details/80242525