美文网首页Java 杂谈数据结构和算法分析每周500字
【Java实现数据结构】链表成环的一些检测与操作

【Java实现数据结构】链表成环的一些检测与操作

作者: 张照博 | 来源:发表于2018-08-22 12:00 被阅读87次

    正文之前

    今天早上看简书的时候,发现了一个写的很好的Java实现的数据结构的Repo,所以就干脆对着学了起来。感觉还行,现在丢一点学习成果。地址是:https://github.com/buptdavid/datastructure

    正文

    如果你要测试,直接复制下面所有除了Node.java之外的代码,丢到一个文件LinkedListLoop.java里面,辅助文件Node.java如下,新建这个文件然后把两个java文件丢到一个文件夹下就OK:

    //Node.java
    public class Node<T> {
        public Node<T> next;
        public T data;
        
        public Node(T _data){
            data = _data;
        }
    }
    

    下面所有的都是LinkedListLoop.java里面的内容。

    /**
     * 1. 判断一个链表是否存在环儿<br>
     * 2. 如果有环儿计算环儿的长度<br>
     * 3. 找出环儿的连接点<br>
     * @author weijielu
     * @see LinkedListLoopTest
     */
    public class LinkedListLoop{
        
        /**
         * 判断一个链表是否存在环儿
         * @param header
         * @return 是否存在环儿
         */
        public static boolean isExistLoop(Node header){
            // 定义两个指针fast和slow,fast移动步长为2,slow移动步长为1
            Node fast = header;
            Node slow = header;
            
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                
                //如果相遇则存在环儿,跳出
                if(fast == slow){
                    break;
                }
            }
            
            // 根据跳出循环的条件return
            if(fast == null || fast.next == null){
                return false;
            }else{
                return true;
            }
        }
        
        /**
         * 计算有环儿链表的环儿长度<br>
         * fast, slow从碰撞点出发再次碰撞就是环儿的长度
         * @param header
         * @return 返回环儿的长度
         */
        public static int loopLength(Node header){
            // 如果不存在环儿,返回0
            if(!isExistLoop(header)){
                return 0;
            }
            
            Node fast = header;
            Node slow = header;
            int length = 0;
            boolean begin = false;
            boolean again = false;
            
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                
                // 超过两圈后停止计数,跳出循环
                if(fast == slow && again == true){
                    break;
                }
                
                // 超过一圈后开始计数
                if(fast == slow && again == false){
                    begin = true;
                    again = true;
                }
                
                if(begin == true){
                    ++length;
                }
            }
            
            return length;
        }
        
        /**
         * 找出环儿的连接点<br>
         * 碰撞点到连接点的距离=头指针到连接点的距离<br>
         * 因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点<br>
         * @param header
         * @return 环儿连接点
         */
        public static Node findLoopEntrance(Node header){
            Node fast = header;
            Node slow = header;
            while(fast != null && fast.next != null){
                fast = fast.next.next;
                slow = slow.next;
                if(fast == slow){
                    break;
                }
            }
            
            if(fast == null || fast.next == null){
                return null;
            }
            
            slow = header;
            while(slow != fast){
                slow = slow.next;
                fast = fast.next;
            }
            
            return slow;
        }
        public static void main(String[] args) {
            Node<Integer> node1 = new Node<Integer>(2);
            Node<Integer> node2 = new Node<Integer>(2);
            Node<Integer> node3 = new Node<Integer>(3);
            Node<Integer> node4 = new Node<Integer>(4);
            Node<Integer> node5 = new Node<Integer>(10086);
            Node<Integer> node6 = new Node<Integer>(5);
            Node<Integer> node7 = new Node<Integer>(6);
            Node<Integer> node8 = new Node<Integer>(7);
            Node<Integer> node9 = new Node<Integer>(8);
            Node<Integer> node10 = new Node<Integer>(9);
            Node<Integer> node11 = new Node<Integer>(10);
            Node<Integer> node12 = new Node<Integer>(11);
            Node<Integer> node13 = new Node<Integer>(12);
            Node<Integer> node14 = new Node<Integer>(13);
    
            node1.next = node2;
            node2.next = node3;
            node3.next = node4;
            node4.next = node5;
            node5.next = node6;
            node6.next = node7;
            node7.next = node8;
            node8.next = node9;
            node9.next = node10;
            node10.next = node11;
            node11.next = node12;
            node12.next = node13;
            node13.next = node14;
            node14.next = node5;
    
    
            Node<Integer> head = node1;
            int s=20;
            while (node1 != null && (s--)>0) {
                System.out.print(node1.data + " ");
                node1 = node1.next;
            }
    
            if (isExistLoop(head)) {
                System.out.println("\n\n\nExist Loop of this LinkedList! \n\n\nAnd the length of the Loop is : [ "+loopLength(head)+" ] and the Linked-Node is "+findLoopEntrance(head).data);
            }
    
            node1 = head;
        }
    }
    

    下面我讲讲关于这个东西的数学原理。

    上面是我随手瞎几把画的一个链表示意图。各个位置都有注释标注,我就不多说了。代码的含义是取两个移动速度,一个是另外一个的两倍。当二者的位置相同时,就代表着相遇了。这时候就产生了碰撞点这个概念。

    下面,是数学时间:

    * 令成环部分的长度为:h
    * 整条链表的长度为: l
    * 在碰撞过程中,慢速的行程: w
    * 头结点到连接点的距离: T
    * 碰撞点到连接点的距离: P
    
    那么,根据链表的性质: T = l - h;
    而根据运动学原理: P = l - w
    现在,我们只需要证明h = w 就可以得到关于连接点的获取方法中的理论支持了。
    那么,根据快速与慢速的两个运动的二倍关系。有2*w - w = h。
    

    因为很明显的快速的移动比慢速移动要多走一个环对吧?那么。。很明显,就得到了理论支撑。。。好吧。。这个是弱鸡了点,但是我想说的是,编程么。。到了最后都是数学。。语言只是工具,框架也是数学模型的合集。。不足为奇。。还是要学好数学啊!!!

    至于其他的也没啥好讲的。。就那个求环长的方法,就是求w/h的长度。。那么当我们得到了碰撞点,只需要继续往前走。下一次碰撞的时候就代表着又走过了一圈。。因为他们的运动行程的两倍关系,在一个环上必然是一直在原地相遇的。。。so。。。吃饭去了。。

    正文之后

    有谁想要健身方面的PDF和视频吗??

    相关文章

      网友评论

      • 知识学者:好像数学里面的追击问题, java的数据结构,没写过。
        健身方面的PDF和视频吗:grin: 这东西,还要看视频,文档吗?
        张照博:@东风冷雪 。。嗯。。跑步能减肥,,但是要一身好看的线条。跑步是不够的。。
        知识学者:@HustWolf 😂就跑步,。。。
        张照博:@东风冷雪 。。当然。。健身不当超容易伤到自己的。。

      本文标题:【Java实现数据结构】链表成环的一些检测与操作

      本文链接:https://www.haomeiwen.com/subject/sabeiftx.html