您的位置:首页 > 编程语言 > Java开发

(Java代码实现)单链表有环的一系列问题

2017-07-12 12:32 375 查看
本文主要用Java实现关于单链表有环的5个问题:

1. 判断一个单链表是否存在环?
2. 若存在环,找到环的入口位置?
3. 进一步,计算换上的节点数?
4. 进一步,计算环外的长度、链表的长度?
5. 环上对面的结点如何求?


解决每个问题的方法:

1. 利用快、慢指针从表头开始往后next,慢指针去追击快指针,若遍历完返回null,就没有环;若慢指针追上快指针相遇,就有环。
2. 经过数学推导,有这么个规律:从相遇点位置和从表头位置同时往后next,会在环的入口处相遇。
3. 基于以上,可以有2种方法:
(1)从环的入口处开始,在环上转一圈,计数。
(2)从相遇点位置同时开始,快慢指针继续转,直到下次二者相遇,二者走过步数差值(或者慢指针走过的步数)就是环的长度。当然,上面的理论是建立在 快指针一次走2步,慢指针一次走一步。
4. 基于以上,知道了入口的位置,从表头开始往入口走,计数。链表长度=环外长度+环长度。
5. 基于这个规律:在环内,快慢指针同时出发,快指针回到原点,慢指针走到距离原点最远处。


具体详细的数学推导参见

http://blog.csdn.net/doufei_ccst/article/details/10578315

Java 代码实现如下:

public class ListNode {

int val;
ListNode next;

public ListNode(int val) {
this.val = val;
}

public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}

public int getVal() {
return val;
}

public void setVal(int val) {
this.val = val;
}

public ListNode getNext() {
return next;
}

public void setNext(ListNode next) {
this.next = next;
}

@Override
public String toString() {
return "ListNode{" +
"val=" + val +
'}';
}

}

----------

public class BooleanCircular {

private static ListNode pos;
private static ListNode joint;

public static void main(String[] args) {
ListNode listNode1 = new ListNode(1);
ListNode listNode2 = new ListNode(2);
ListNode listNode3 = new ListNode(3);
ListNode listNode4 = new ListNode(4);
ListNode listNode5 = new ListNode(5);
ListNode listNode6 = new ListNode(6);
ListNode listNode7 = new ListNode(7);
ListNode listNode8 = new ListNode(8);
ListNode listNode9 = new ListNode(9);

listNode1.setNext(listNode2);
listNode2.setNext(listNode3);
listNode3.setNext(listNode4);
listNode4.setNext(listNode5);
listNode5.setNext(listNode6);
listNode6.setNext(listNode7);
listNode7.setNext(listNode8);
listNode8.setNext(listNode9);
listNode9.setNext(listNode4);

System.out.println(hasCycle(listNode1));
System.out.println(FindJoint(listNode1));
System.out.println(CircluarCount2(listNode1));
calculateLength(listNode1);
System.out.println(oppositeListNode(listNode4));

}

//判断单链表是否有环
public static boolean hasCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;

while (slow != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast) {
return true;
}
}
return false;
}

//找到环的入口
public static ListNode FindJoint(ListNode head) {
ListNode fast = head;
ListNode slow = head;

while (slow != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if (slow == fast) {
break;
}
}
if (slow == null || fast.next == null) {
System.out.println("没有环");
return null;
}

//记录相遇位置
pos = slow;

ListNode node = slow;
ListNode start = head;
while (node != start) {
node = node.next;
start = start.next;
}

//记录环入口位置
joint = start;

return start;
}

//计算环上的节点数,两种方法
public static int CircluarCount1(ListNode head) {
int count = 1;
//joint是入口位置
ListNode node = joint.next;
while (node != joint) {
node = node.next;
count++;
}
return count;
}

public static int CircluarCount2(ListNode head) {
int count = 1;
//pos是相遇位置
ListNode fast = pos.next.next;
ListNode slow = pos.next;
while (fast != slow) {
fast = fast.next.next;
slow = slow.next;
count++;
}
return count;
}

//计算头结点到环入口的长度、链表的长度
public static void calculateLength(ListNode head) {
int count = 0;
//joint是入口位置
for (ListNode node = head; node != joint; node = node.next, count++) ;
System.out.println("头结点到入口的长度:" + count);
int listCount = count+CircluarCount1(head);
System.out.println("链表的长度:" + lis
a5bf
tCount);
}

//求环上对面的结点,这里以 listNode4 对面结点 listNode7 来验证
public static ListNode oppositeListNode(ListNode listNode){
ListNode slow = listNode;
ListNode fast = listNode;

do{
slow=slow.next;
fast=fast.next.next;
}while(fast!=listNode);

return slow;
}
}


run结果:

true

ListNode{val=4}

6

头结点到入口的长度:3

链表的长度:9

ListNode{val=7}


本文结束,谢谢浏览!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  单链表有环