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

正文之前

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

41a590431865?utm_source=oschina-app

正文

如果你要测试,直接复制下面所有除了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;

}

}

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

41a590431865?utm_source=oschina-app

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

下面,是数学时间:

* 令成环部分的长度为:h

* 整条链表的长度为: l

* 在碰撞过程中,慢速的行程: w

* 头结点到连接点的距离: T

* 碰撞点到连接点的距离: P

那么,根据链表的性质: T = l - h;

而根据运动学原理: P = l - w

现在,我们只需要证明h = w 就可以得到关于连接点的获取方法中的理论支持了。

那么,根据快速与慢速的两个运动的二倍关系。有2*w - w = h。

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

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

41a590431865?utm_source=oschina-app

正文之后

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

41a590431865?utm_source=oschina-app

41a590431865?utm_source=oschina-app

41a590431865?utm_source=oschina-app

41a590431865?utm_source=oschina-app

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值