判断两个单链表是否相交同时找出第一个相交点(单链表是否有环及寻找入口节点)
2014-04-25 11:28
603 查看
这个问题,首先应判断两个单链表是否含有环,判断是否有环的方法很多,目前最好的方法是:一开始设置两个指针都指向表头,其中一个每次(一步)前进一个节点的叫p1,另外那个每次(一步)前进两个节点的叫p2
。p1和p2同时走,当其中有一个遇到null,就证明链表没有环。如何某个时刻(假设走了n步之后),p1和p2指向的地址相同,那么链表就是有环的。
方法代码如下:
这样,就判断出两个链表是否存在环,有以下3种情况,一、两链表均不含环,此时为情况一;二、两链表均含环,此时为情况二;三,一个有环一个无环,显然两链表此时不可能相交,该情况不考虑。
一、均无环的情况下判断是否相交,且找出第一个相交点
无环情况下,判断是否相交,可以让两个链表均遍历至尾节点,如果尾节点相同,则说明两链表是有交点的,代码如下:
此时已判断出是否相交,相交后,来寻找第一个相交点,此时有两种思路:方法一:较易懂,算出两个链表的长度差δ,两个指针从表头出发,之后较长的链表先移动δ步,之后两链表同时移动,直到遇到相同的节点,该节点即为第一个相交点,代码如下:
方法二:将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在(该环就是首尾相连的链表),则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。需找出环的入口,设置p1,p2两个指针,同样一个走一步一个走两步,两者相遇则必在环上某一点相遇,记下此位置p1=p2,在p1和p2重合后,设置一个p3指向表头,然后p1和p3每次同时行走一步,每步前进一个节点,等到p1和p3重合时,重合的位置就是环的入口。
可以这样理解,如图:
设L1为无环长度,L2为环长,a为两指针相遇时慢速指针在环上走过的距离,而且a一定小于环总长L2(这是因为当慢速指针刚进入环时,快速指针已经在环中,且距离慢速指针的距离最长为L2-1,需要追赶的距离为L2-1,即刚好在慢速指针的下一个节点,需要几乎一整圈的距离来追赶,赶上时,慢速指针也不能走完一圈)。此时设慢速指针走过的节点数为N,则可列出:
快速指针走过的节点数为: 2N = L1 + k * L2 + a; (这里快速指针走过的节点数一定是慢速指针走过的2倍)。
慢速指针走过的节点数为: N = L1 + a;
则相减可得, N = k * L2 , 于是得到 k * L2 = L1 + a; 即, L1 = (k-1) * L2 + (L2 - a) (这里k至少是大于等于1的,因为快速指针至少要多走一圈)
即 L1的长度 = 环长的整数倍 + 相遇点到入口点的距离, 此时设置头结点p3, 与p1同时,每次都走一步,相遇点即为入口点。
整个过程代码如下:
二、均有环的情况下,判断是否相交
思路与无环时的思路较类似,二者均有环,那么可以找出各自环的入口点,然后从各自的入口点出发,一个快速(每次2步),一个慢速(每次1步),直到相遇,说明相交。
。p1和p2同时走,当其中有一个遇到null,就证明链表没有环。如何某个时刻(假设走了n步之后),p1和p2指向的地址相同,那么链表就是有环的。
方法代码如下:
public boolean isLoop(Node h){ Node p1 = h; Node p2 = h; while(p2.next != null && p2.next.next != null){ p1 = p1.next; p2 = p2.next; if(p1 == p2) break; } return !(p1==null||p2==null); }
这样,就判断出两个链表是否存在环,有以下3种情况,一、两链表均不含环,此时为情况一;二、两链表均含环,此时为情况二;三,一个有环一个无环,显然两链表此时不可能相交,该情况不考虑。
一、均无环的情况下判断是否相交,且找出第一个相交点
无环情况下,判断是否相交,可以让两个链表均遍历至尾节点,如果尾节点相同,则说明两链表是有交点的,代码如下:
/* * 无环情况下判断是否相交 两个链表无环时若相交,则至少尾节点必然是同一个 */ public boolean isJointNoLoop(Node h1, Node h2) { Node p = h1; Node q = h2; while (p.next != null) { p = p.next; } while (q.next != null) { q = q.next; } return p == q; }
此时已判断出是否相交,相交后,来寻找第一个相交点,此时有两种思路:方法一:较易懂,算出两个链表的长度差δ,两个指针从表头出发,之后较长的链表先移动δ步,之后两链表同时移动,直到遇到相同的节点,该节点即为第一个相交点,代码如下:
/* * 无环情况下找出第一个相交点 */ public Node getFirstJoint(Node h1, Node h2) { int len1 = 0; int len2 = 0; while (h1.next != null) { len1++; h1 = h1.next; } while (h2.next != null) { len2++; h2 = h2.next; } return len1-len2>=0?getNode(h1,h2,len1,len2):getNode(h2, h1, len2, len1); } private Node getNode(Node h1, Node h2, int len1, int len2) { int i = 0; while (i < len1 - len2) { h1 = h1.next; } while (true) { h1 = h1.next; h2 = h2.next; if (h1 == h2) return h1; } }
方法二:将其中一个链表首尾相连,检测另外一个链表是否存在环,如果存在(该环就是首尾相连的链表),则两个链表相交,而检测出来的依赖环入口即为相交的第一个点。需找出环的入口,设置p1,p2两个指针,同样一个走一步一个走两步,两者相遇则必在环上某一点相遇,记下此位置p1=p2,在p1和p2重合后,设置一个p3指向表头,然后p1和p3每次同时行走一步,每步前进一个节点,等到p1和p3重合时,重合的位置就是环的入口。
可以这样理解,如图:
设L1为无环长度,L2为环长,a为两指针相遇时慢速指针在环上走过的距离,而且a一定小于环总长L2(这是因为当慢速指针刚进入环时,快速指针已经在环中,且距离慢速指针的距离最长为L2-1,需要追赶的距离为L2-1,即刚好在慢速指针的下一个节点,需要几乎一整圈的距离来追赶,赶上时,慢速指针也不能走完一圈)。此时设慢速指针走过的节点数为N,则可列出:
快速指针走过的节点数为: 2N = L1 + k * L2 + a; (这里快速指针走过的节点数一定是慢速指针走过的2倍)。
慢速指针走过的节点数为: N = L1 + a;
则相减可得, N = k * L2 , 于是得到 k * L2 = L1 + a; 即, L1 = (k-1) * L2 + (L2 - a) (这里k至少是大于等于1的,因为快速指针至少要多走一圈)
即 L1的长度 = 环长的整数倍 + 相遇点到入口点的距离, 此时设置头结点p3, 与p1同时,每次都走一步,相遇点即为入口点。
整个过程代码如下:
/* * 相交的两个不含环单链表的第一个交点,方法一:将其中一个链表首尾相接,此时可看作一个含环单链表,找出环入口点即可 */ public Node entryNoLoop(Node h1, Node h2) { Node p = h1; while (p.next != null) { p = p.next; } // 此时p指向链表1的尾节点,首尾相连 p.next = h1; return entryLoop(h2); } /* * 找出一个含环单链表的环入口点 */ public Node entryLoop(Node h) { Node p3 = h; Node p1 = h; Node p2 = h; while (p2.next != null && p2.next.next != null) { p1 = p1.next; p2 = p2.next.next; if (p1 == p2) { break; } } while (p3 != p1) { p1 = p1.next; p3 = p3.next; } return p3; }
二、均有环的情况下,判断是否相交
思路与无环时的思路较类似,二者均有环,那么可以找出各自环的入口点,然后从各自的入口点出发,一个快速(每次2步),一个慢速(每次1步),直到相遇,说明相交。
相关文章推荐
- 判断两个链表是否相交,若相交,则找出相交的第一个节点
- 判断单链表是否有环,如果有找出环的入口位置=>求两个相交链表的交点
- 判断两个链表是否相交并找出第一个相交节点
- 数据结构—判断两个链表是否相交,寻找两个链表的相交节点
- 如何判断两个单链表是否相交以及找出第一个相交的位置
- 转:判断两个单向链表是否相交,并找到两个单向链表的第一个相交节点
- 单向链表相交的第一个公共结点, 判断链表是否有环以及环的入口节点
- 两个单向链表,判断它们是否相交,若相交,找出它们的第一个公共的结点
- 判断两个链表是否相交;查找两个链表的第一个公共节点;头插法建链表(补充)
- 题目:①判断一个单向链表是否有环,如果有环则找到环的入口节点。 ②判断两个单向链表是否相交,如果相交则找到交点节点。
- 3.6 判断两个无环链表是否相交 & 找出相交的第一个结点
- 已知有两个链表,判断它们是否相交,若相交求其第一个公共节点
- 判断单链表是否有环 并找出第一个相交的节点
- 用快慢指针判断单链表环,找到环入口 扩展到判断两个链表是否相交
- 判断两个链表是否相交及获得相交的第一个节点
- 判断单链表是否有环 并找出第一个相交的节点
- 判断单链表是否有环 判断两个链表是否相交
- 判断两个链表是否相交并找出交点
- 【数据结构】单链表—寻找两个相交链表中第一个公共结点 — 蛮力法 / 栈 / 指针先走
- 判断两个链表是否相交并找出交点