Java 一个单链表怎么可能有两个头,找到它们的“头”意味着什么;公共节点“;?

Java 一个单链表怎么可能有两个头,找到它们的“头”意味着什么;公共节点“;?,java,singly-linked-list,Java,Singly Linked List,以下方法的JavaDocs包括: 问题中的单链表有两个头,n1和n2,它们合并在一个公共节点上。返回可从n1和n2访问的第一个公共节点。这必须在O(n)时间内运行 我不明白这个代码的目的。一个单链表怎么可能有两个头?什么是公共列表(或公共节点),为什么返回 是否有人可以提供一些输入列表的示例,以及findCommonList方法返回后的列表或列表的外观 代码是: public static<E> ListNode<E> findCommonList(ListNode<

以下方法的JavaDocs包括:

问题中的单链表有两个头,
n1
n2
,它们合并在一个公共节点上。返回可从
n1
n2
访问的第一个公共节点。这必须在O(n)时间内运行

我不明白这个代码的目的。一个单链表怎么可能有两个头?什么是公共列表(或公共节点),为什么返回

是否有人可以提供一些输入列表的示例,以及
findCommonList
方法返回后的列表或列表的外观

代码是:

public static<E> ListNode<E> findCommonList(ListNode<E> n1, ListNode<E> n2) {
int length1 = getLength(n1);
int length2 = getLength(n2);
if (length1 > length2)
    n1 = advance(n1, length1 - length2);
else
    n2 = advance(n2, length2 - length1);
while (n1 != n2) {
    n1 = n1.next;
    n2 = n2.next;
}
return n1; }

private static<E> ListNode<E> advance(ListNode<E> n, int k) {
while (k > 0) {
n = n.next;
k--; }
return n; 
}

private static<E> int getLength(ListNode<E> n) {
int total = 0;
while (n != null) {
    total++;
    n = n.next; }
return total;
}
公共静态ListNode findCommonList(ListNode n1,ListNode n2){
int length1=getLength(n1);
int length2=getLength(n2);
如果(长度1>长度2)
n1=前进(n1,长度1-长度2);
其他的
n2=前进(n2,长度2-长度1);
而(n1!=n2){
n1=n1.next;
n2=n2.next;
}
返回n1;}
专用静态ListNode高级(ListNode n,int k){
而(k>0){
n=n.next;
k--;}
返回n;
}
私有静态int getLength(ListNode n){
int-total=0;
while(n!=null){
总计++;
n=n.next;}
返回总数;
}

我看不到
ListNode
的代码,但我猜这是一个非常典型的单链接列表,引用了
E
类型的一些数据,并引用了下一个
ListNode
,称为
next
。最后一个
ListNode
将其
next
指向
null
。忽略对数据的引用,典型列表如下所示:

lnA→lnB→lnC→…→lnZ→null
这种结构的一个(许多)问题是没有一个列表“拥有”这些
ListNode
实例中的任何一个,因此多个列表可能会纠结在一起:

ln0→ln1→ln2↘
            lnQ→lnR→…→lnZ→null
lnA→lnB→lnC↗
findCommonList
方法接受两个
ListNode
引用,
n1
n2
,然后搜索它们有共同点的第一个“右侧”节点,这标志着它们共同尾部的开始

n1和n2作为一条共同的尾巴共享什么实际上取决于它们从哪里开始。把它们放在明显的地方:

n1
↓
ln0→ln1→ln2↘
            lnQ→lnR→…→lnZ→null
lnA→lnB→lnC↗
↑
n2
…将返回
lnQ
作为其公共尾部的开始。(如果
n2
是从
lnZ
开始的,那么显然结果不可能包括
lnQ
——它不再在其中一个列表中,因此对这两个列表都不常见。)

JavaDoc意味着此代码仅在上述情况下有效,但它也处理一些可能在开始时看起来非常不同的相关情况,例如当
n1
n2
指向同一列表的不同元素时:

甚至当他们指向两个不相关的列表时。。。 由于所有列表都以引用
null
结束,因此两个“完全独立”的列表将返回
null
作为其(零长度)公共尾部的开始:

n1
↓
ln0→ln1→ln2→ln3→ln4↘
                    null
        lnA→lnB→lnC↗
        ↑
        n2
如何
findCommonList
工作

findCommonList
要做的第一件事是找出
n1
n2
距离各自列表的末尾有多远(每个
null
之间分隔了多少个元素)

在本例中,
n1
n2
远“2”:

n1
↓
ln0→ln1→ln2→ln3→ln4↘
                    lnQ→…→lnZ→null
        lnA→lnB→lnC↗
        ↑
        n2
然后,它向前推进两个参考中的较远的一个,以便它与另一个参考之间的距离与
null
相同。它跳过的元素不可能是公共尾部的一部分,因为公共尾部不可能长于一个输入列表

前进
n1
后:

        n1
        ↓
ln0→ln1→ln2→ln3→ln4↘
                    lnQ→…→lnZ→null
        lnA→lnB→lnC↗
        ↑
        n2
现在我们已经到达
while
循环,它可以被改写为:

START:
if n1 and n2 point to the same ListNode:
    return that ListNode
otherwise:
    advance n1 and n2 each one hop to the right
go back to "START"
这就是我上面所说的“搜索他们共同拥有的‘右侧’第一个节点”。完成后,
n1
n2
都将指向相同的
ListNode
lnQ
,并返回:

                    n1
                    ↓
ln0→ln1→ln2→ln3→ln4↘
                    lnQ→…→lnZ→null
        lnA→lnB→lnC↗
                    ↑
                    n2
请注意,这在我上面概述的其他情况下也适用

如果
n1
n2
指两个完全独立的列表:

n1
↓
ln0→ln1→ln2→ln3→ln4↘
                    null
        lnA→lnB→lnC↗
        ↑
        n2
首先,进一步的参考将推进:

        n1
        ↓
ln0→ln1→ln2→ln3→ln4↘
                    null
        lnA→lnB→lnC↗
        ↑
        n2
然后,
while
循环将使两个引用同步前进,直到它们到达两个列表共同的唯一“节点”
null

                    n1
                    ↓
ln0→ln1→ln2→ln3→ln4↘
                    null
        lnA→lnB→lnC↗
                    ↑
                    n2
如果
n1
n2
已经指向相同的列表,则更容易:

n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
            ↑
            n2
findCommonList
将从推进远引用开始,与前面相同:

            n1
            ↓
ln0→ln1→ln2→ln3→ln4→…→null
            ↑
            n2
…而且已经完成了
findCommonList
将立即返回对
ln3
的引用,而不会在
循环期间执行
主体

最后,如果
n1
n2
开始指向相同的
ListNode

n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
↑
n2

…调整步骤什么也不做(“前进0跳”),然后返回
ln0
,再次没有执行
循环的主体。

也许我没有清楚地表达我的想法,我重新编辑了我的问题。我提交了一个编辑,以使Weiting的问题更清楚,因为最初的标题只是重述了代码的作用,这意味着一个非常不同的——而且非常广泛的——问题。我认为真正的问题值得重新讨论(尽管我没有机会打那个电话)。它在问为什么需要这个代码:一个单链表怎么可能有两个头?要想知道只有一个传出指针的节点如何仍然会纠结在一起,需要一些想象力。(魏婷:代码本身还可以改进——你能修复缩进吗?)太好了,非常感谢!
n1
↓
ln0→ln1→ln2→ln3→ln4→…→null
↑
n2