zoukankan      html  css  js  c++  java
  • 推断单向链表中是否有环和查找环的入口

    快慢指针

    算法描写叙述

    定义两个指针slow, fast。

    slow指针一次走1个结点,fast指针一次走2个结点。假设链表中有环,那么慢指针一定会再某一个时刻追上快指针(slow == fast)。假设没有环,则快指针会第一个走到NULL。

    实现

    结点定义例如以下:

    class Node {
        public Node next;
        public Object data;
    
        public static int sequence = 0;
    }

    算法:

    /**
         * 快慢指针
         * @param head
         * @return
         */
        public static boolean checkCircle(Node head) {
            Node fast = null;
            Node slow = null;
    
            fast = head;
            slow = head;
            while (true) {
                // 慢指针移动一步
                if (null != slow.next) {
                    slow = slow.next;
                } else {
                    return false;
                }
    
                // 快指针移动两步
                if (null != fast.next && null != fast.next.next) {
                    fast = fast.next.next;
                } else {
                    return false;
                }
    
                // 检查是否相遇
                if (slow == fast) {
                    return true;
                }
            }
        }

    步数检查

    算法描写叙述

    上面的算法仅仅能推断链表中有没有环,假设我们想找出环的入口怎么办呢?

    定义两个指针p, q。p每走一个结点(即一步),q则从头一直向后走,直到q走到NULL或p, q走到同一个结点但走过的步数不同样为止。

    此时q的步数就是环入口在结点中的位置。假设走到NULL则说明链表不存在环。

    为什么p, q走到同一个结点但步数不相等时就说明有环呢?由于假设p, q步数同样,说明它们走过的结点是一样的,假设p, q步数不同了。则说明p是从环里走了一圈又回到了环的入口。此时q到达该结点时还没有走过环,因此步数不相等,并且此时q的步数就是环的入口。

    实现

    /**
         * 查找环的起点
         * @param head
         * @return 返回元素的索引,从0開始。没有找到返回-1
         */
        public static int findCircleEntry(Node head) {
            Node p = head; // 总是从头開始
            Node q = head;
    
            int pSteps = 0;
            int qSteps = 0;
            while (null != q.next) {
                q = q.next;
                ++qSteps;
    
                // p从头開始走
                while (null != p.next) {
                    p = p.next;
                    ++pSteps;
    
                    // 当p与q指向同一个结点时
                    if (p == q) {
                        // 假设走的步数不同,则这就是入口
                        if (pSteps != qSteps) {
                            return pSteps - 1;
                        } else {
                            // 走的步数同样,不是入口
                            break;
                        }
                    }
                }
    
                p = head; // 回到头结点
                pSteps = 0;
            }
    
            // 当中有一个指针走到了头,说明没有环
            return -1;
        }
  • 相关阅读:
    Android 博客园客户端 (六) OnItemLongClickListener for Blog, News and Comment
    Android 博客园客户端 (五) 查看评论、搜索博主
    Android 博客园客户端 (四) 基本功能完成(博客列表和内容、新闻列表和内容、推荐博主)
    Android 博客园客户端 (三) 博客列表和内容显示
    Android 博客园客户端 (二) 新界面&部分功能
    Android UI 之 ListView
    Git 客户端基本配置
    Android 博客园客户端 (一) 基本界面
    性能优化的心得
    重构
  • 原文地址:https://www.cnblogs.com/llguanli/p/8452083.html
Copyright © 2011-2022 走看看