转载请注明出处:
声明:现大部分文章为寻找问题时在网上相互转载,此博是为自己做个记录记录,方便自己也方便有类似问题的朋友,本文的思想也许有所借鉴,但源码均为本人实现,如有侵权,请发邮件表明文章和原出处地址,我一定在文章中注明。谢谢。
题目:7_2判断两个单链表是否相交,若相交,求出第一个交点。
题目分析:
创建A,B两个单链表,将B的尾部指向头部,若两个单链表相交,则交点必为环的入口,这就又变成上边判断一个单链表是否有环的问题了。
注: 若两个单链表相交,则相交之后的那些节点比都是一样的(相交之后的长度是一样的),否则若一长一短或者相交之后有分叉,则在短链表末尾或者分叉节点处,该节点将有两个next分别指向两边的链表,这就不是单链表了。
源码实现:
1 package com.interview; 2 3 /** 4 * 判断两个单链表是否相交,若相交,求出第一个交点 5 * 方法:创建A,B两个单链表,将B的尾部指向头部,若两个单链表相交,则交点必为环的入口 6 * 若两个单链表相交,则相交之后的那些节点比都是一样的(相交之后的长度是一样的), 7 * 否则若一长一短或者相交之后有分叉,则在锻炼表末尾或者分叉节点处,该节点将有 8 * 两个next分别指向两边的链表,这就不是单链表了 9 * @author wjh 10 * 11 */ 12 public class _7_2JudgeListCross { 13 14 /** 15 * @param args 16 */ 17 //分别记录相交前A表的长度,B链表(圈)的长度,第一次相遇时慢指针走的总长度 18 public static int x=0, y=0, k=0; 19 public static void main(String[] args) { 20 //1)创建两个相交的链表 21 Node nodeA = createList("A", 28); 22 Node nodeB = createList("B", 3); 23 Node tail = createTail(3); 24 nodeA = merge(nodeA, tail); 25 nodeB = merge(nodeB, tail); 26 //2)将B的尾节点指向B的第一个节点 ,此时若相交,A的结构就变成带环单链表了, 27 //若不相交则遍历A会走到null 28 Node r = findTail(nodeB); //若要求A B的长度,则在上面遍历nodeA,nodeA 29 r.next = nodeB.next; 30 judge(nodeA); 31 32 } 33 34 35 //创建带头节点的无环单链表的相较之前的部分 36 public static Node createList(String name, int k){ 37 /** 1)用尾插法构建单链表,此处构建有环单链表,让node24指向node6*/ 38 Node first = new Node(null,null); //头节点 39 Node r = first; //指向链表的尾节点 40 for(int i=1;i<=k;i++){ //根据传入参数创建相交之前的部分节点 41 Node node = new Node("猫狗_"+name+"_"+i,null); 42 r.next = node; 43 r = node; 44 } 45 r.next = null; //若是构建无环单链表,此处 r.next = null; 46 return first; 47 } 48 49 //创建带头节点的无环单链表的相较之后的相同的部分 50 public static Node createTail(int k){ 51 Node first = new Node(null,null); //头节点 52 Node r = first; //指向链表的尾节点 53 for(int i=1;i<=k;i++){ //创建相交之后的部分节点 54 Node node = new Node("相同节点@"+i,null); 55 r.next = node; 56 r = node; 57 } 58 r.next = null; //若是构建无环单链表,此处 r.next = null; 59 return first; 60 } 61 62 //将相交之前和相交之后的链表穿起来 63 public static Node merge(Node first, Node second){ 64 Node r = first; //记录前面链表的尾部节点 65 while(r.next!=null){ 66 r = r.next; 67 } 68 //因为second是后面链表的头节点,是空的,头节点下一个节点才是真正的节点 69 r.next = second.next; 70 return first; 71 } 72 73 //找到一个链表的尾节点 74 public static Node findTail(Node node){ 75 Node r = node; //记录前面链表的尾部节点 76 while(r.next!=null){ 77 r = r.next; 78 } 79 return r; 80 } 81 82 //判断是否有环 83 public static void judge(Node first){ 84 /** 2)判断是否有环若pq先重合则有环,若q先指向null,则无环 */ 85 Node p = first.next; 86 Node q = first.next; 87 String flag = "0"; //标记有环还是无环,0-无环,1-有环 88 if(p==null){ //空链表 89 System.out.println("链表为空!"); 90 return; 91 } 92 k=1; 93 while(q.next!=null && q.next.next!=null){ 94 k++; //记录相遇时p指针走的长度,k从0开始,因为k已经加过1了才判断pq是否相等 95 p=p.next; 96 q=(q.next).next; 97 if(q.equals(p)){ 98 flag="1"; 99 System.out.println("p和q相遇了,这两个单链表相交!");100 break;101 }102 }103 104 /** 3)有环的时候求环的入口节点 */105 if(flag.equals("1")){ //有环106 p=first.next; //p重新指向第一个节点107 searchEnter(p,q);108 }109 else{ //是因为q走到了尽头才跳出循环的,无环110 System.out.println("这两个单链表不相交!");111 }112 }113 114 //求环的入口节点 115 public static void searchEnter(Node p, Node q){116 x=1;117 while(!q.equals(p)){118 x++; //求圈外长度119 p=p.next;120 q=q.next;121 }122 Node r = q.next; //为了求圈长设定的123 y = 1; //求圈长度124 while(r!=q){125 r = r.next;126 y++;127 }128 System.out.println("相交节点是A链表中的第"+ x+"个节点!");129 System.out.println("相交节点的名字为: "+ p.name);130 System.out.println("B链表的长度是:"+ y);131 System.out.println("第一次相遇时,慢指针在B圈内走的长度为:"+ (k-x));132 System.out.println("第一次相遇时,快指针在B圈内走了:"+ (k/y)+"圈");133 System.out.println("第二次相遇时,快指针在B圈内又走了:"+ (k/y-1)+"圈");134 }135 136 137 //创建一个私有的节点类138 private static class Node {139 public String name;140 public Node next;141 public Node(String name, Node next) {142 super();143 this.name = name;144 this.next = next;145 }146 }147 }
运行结果:
1.有交点:
p和q相遇了,这两个单链表相交!
相交节点是A链表中的第29个节点!相交节点的名字为: 相同节点@1B链表的长度是:6第一次相遇时,慢指针在B圈内走的长度为:2第一次相遇时,快指针在B圈内走了:5圈第二次相遇时,快指针在B圈内又走了:4圈
2.无交点:
这两个单链表不相交!