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

正文之前

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

【Java实现数据结构】链表成环的一些检测与操作_第1张图片

正文

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

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

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

/**
 * 1. 判断一个链表是否存在环儿
* 2. 如果有环儿计算环儿的长度
* 3. 找出环儿的连接点
* @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; } } /** * 计算有环儿链表的环儿长度
* 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; } /** * 找出环儿的连接点
* 碰撞点到连接点的距离=头指针到连接点的距离
* 因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点
* @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 node1 = new Node(2); Node node2 = new Node(2); Node node3 = new Node(3); Node node4 = new Node(4); Node node5 = new Node(10086); Node node6 = new Node(5); Node node7 = new Node(6); Node node8 = new Node(7); Node node9 = new Node(8); Node node10 = new Node(9); Node node11 = new Node(10); Node node12 = new Node(11); Node node13 = new Node(12); Node node14 = new Node(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 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; } }

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

【Java实现数据结构】链表成环的一些检测与操作_第2张图片

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

下面,是数学时间:

* 令成环部分的长度为:h
* 整条链表的长度为: l
* 在碰撞过程中,慢速的行程: w
* 头结点到连接点的距离: T
* 碰撞点到连接点的距离: P

那么,根据链表的性质: T = l - h;
而根据运动学原理: P = l - w
现在,我们只需要证明h = w 就可以得到关于连接点的获取方法中的理论支持了。
那么,根据快速与慢速的两个运动的二倍关系。有2*w - w = h。

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

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

正文之后

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

【Java实现数据结构】链表成环的一些检测与操作_第3张图片
【Java实现数据结构】链表成环的一些检测与操作_第4张图片
【Java实现数据结构】链表成环的一些检测与操作_第5张图片
【Java实现数据结构】链表成环的一些检测与操作_第6张图片

你可能感兴趣的:(【Java实现数据结构】链表成环的一些检测与操作)