我们前边已经讨论了关于单向链表的简单功能增删改查的实现,以及通过两个指针获取倒数k个节点以及合并两个有序链表的方法,接下来我们需要讨论的是有关于单向链表的环问题。一个链表是否有环的存在,如果有环那么我们的环的长度是多少,它的起点又在哪里,这都是我们需要考虑的问题。现在我们讨论第一个问题,判断一个链表是否有环:
一:链表是否有环:
我们还是先考虑一个思路,我们能不能通过两个指针的思路解决这个问题,假设链表有环,那么我们在遍历链表的时候是不是永远不会有结束的时候,一直会在结环处进行无休止的循环。那么这时候我们可以考虑的是我们设置的两个指针是不是可以仿照获取中间节点的思想,一个行走两步,一个行走一步,如果有环他们必然相遇,如果无环,那么他们是不可能相遇的。实现代码如下:
public boolean hasCycle(Node head){ //判断链表是否为空 if(head == null){ return false; } // 定义两个指针位于同一起点 Node first = head; Node second = head; //对链表进行遍历 while(second.next != null){ first = first.next; second = second.next.next; //判断这两个节点是否相遇 if(first == second){ return true; } } return false; }
二:链表如果有环那么我们的链表的环长度是多少:这个问题我们结合上一个问题是非常容易解决的,在链表有环的前提下,我们是必然找到了这个环的起始节点,那么我们在这时候对于first进行停止处理,让second继续前行,如果再次相遇,那么必然是对这个链表进行了一圈的遍历:
public int cycleLength(Node head){ //判断链表是否为空 if(head == null){ return 0; } //定义两个节点位于首节点 Node first = head; Node second = head; //对链表进行遍历,判断是否有环 while(second.next != null){ first = first.next; second = second.next.next; //如果相遇我们进行长度处理 if(first == second){ int length = 1; second = second.next; //second进行对环的再一次遍历 while(second != first){ second = second.next; length ++; } return length; } } return 0; }