正文之前
今天早上看简书的时候,发现了一个写的很好的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和视频吗??
网友评论
健身方面的PDF和视频吗 这东西,还要看视频,文档吗?