C# 为什么反对';s值即使有不同的引用也会更改?
我对这里的对象引用感到困惑。合并2个已排序的链表是一个LC问题 我知道在第一次迭代时,C# 为什么反对';s值即使有不同的引用也会更改?,c#,oop,reference,C#,Oop,Reference,我对这里的对象引用感到困惑。合并2个已排序的链表是一个LC问题 我知道在第一次迭代时,current.next和result引用了相同的对象,因此当我将新值分配给current.next时,result值也会改变 在第二次迭代中,r1和r2都为假,因此结果、当前和当前。下一次指向不同的对象 我不明白的是,为什么将新值赋给current(current=current.next)不会修改结果对象,而current.next=l1/l2会修改 谁能给我解释一下吗 public static List
current.next
和result
引用了相同的对象,因此当我将新值分配给current.next
时,result
值也会改变
在第二次迭代中,r1和r2都为假,因此结果、当前和当前。下一次指向不同的对象
我不明白的是,为什么将新值赋给current(current=current.next
)不会修改结果对象,而current.next=l1/l2
会修改
谁能给我解释一下吗
public static ListNode MergeTwoLists(ListNode l1, ListNode l2)
{
if (l1 == null) return l2;
if (l2 == null) return l1;
if (l2 == null && l1 == null) return null;
ListNode result = new ListNode(0);
ListNode current = result;
while (l1 != null && l2 != null)
{
var r1 = Object.ReferenceEquals(result, current);
var r2 = Object.ReferenceEquals(result, current.next);
if (l1.val < l2.val)
{
current.next = l1;
l1 = l1.next;
}
else
{
current.next = l2;
l2 = l2.next;
}
current = current.next;
}
// l1 is lognger than l2
if(l1 != null)
{
current.next = l1;
l1 = l1.next;
}
// l2 is lognger than l1
if (l2 != null)
{
current.next = l2;
l2 = l2.next;
}
return result.next;
}
编辑
假设我们有这些:
Input: l1 = [1,2,4], l2 = [1,3,4] Output: [1,1,2,3,4,4]
第一次迭代:
r1=true
,结果和当前都指向同一对象
r2=false
l1.val==l2.val
所以我们执行
else
{
current.next = l2;
l2 = l2.next;
}
if (l1.val < l2.val)
{
current.next = l1;
l1 = l1.next;
}
目前,我们有:
result=[0,1,3,4]
,current=[0,1,3,4],l2=[3,4]
接下来我们执行current=current.Next
,因此current=[1,3,4]
,它不再指向结果
第二次迭代
r1=false
,结果和当前都指向不同的对象
r2=false
l1.val
所以我们执行
else
{
current.next = l2;
l2 = l2.next;
}
if (l1.val < l2.val)
{
current.next = l1;
l1 = l1.next;
}
这是我不理解的部分:结果和当前指向不同的对象,仍然是当前更改时的结果。结果如何保持对当前的引用
下一步我们执行current=current.Next
,因此current=[1,2,4]
,所以我们修改current,但这次结果不变。您不应该将current.Next
分配给l1
或l2
中的节点。相反,您必须创建一个新的ListNode
,该节点的值与l1
或l2
相同,并将设置为当前值。下一步
指向新的ListNode
。否则你会试图弄直一碗意大利面,这是一项不可能的任务。你需要自己做一条新的意大利面
结果和当前指向不同的对象,但当当前更改时,结果也会更改。结果如何保持对当前的引用
看看你问题的这一部分:
所以current=[1,3,4]
它不再指向结果
重要的是,该列表中的1
与result=[0,1,3,4]
中的1
是相同的元素。如果修改该1
节点的next
字段,则将修改该节点所属的任何列表。包括结果
正在引用的列表
稍后当你写:
目前,我们有:
result = [0,1,1,2,4], current = [1,1,2,4], l2 = [3,4], l1 = [2,4]
result=[0,1,1,2,4],current=[1,1,2,4],l2=[3,4],l1=[2,4]
请注意,列表结果
指向的对象与列表当前
指向的对象不同。但在第一个节点之后,它是相同的
在第一次迭代之后,result.next
引用与current
相同的对象。这是因为result
和current
从引用同一对象开始,然后作为第一次迭代的最后一步,current
更改为referencecurrent.next
。由于current
和result
在该点相同,current.next
和result.next也相同。因此,将current
更改为current.next
后,这与将其设置为result.next
相同
因此,在第二次迭代中,结果。下一次
和当前
是相同的。这意味着当您修改current.next
时,这与修改result.next.next
相同,其效果是将result
列表中前两个元素之外的内容替换为引用的l2
新元素链
再次强调:这里的关键是每个变量只指向一个节点。可以将其概念化为指向一个节点列表,但前提是您记住,如果您修改该列表中任何节点的next
字段,您就是在修改整个列表,即使变量未引用引用列表根的变量。也不会使用current=current.next
指定新值。将新引用指定给变量current
。所以它不再指向result
引用的对象了。@YegorAndrosov是的,谢谢我得到了它们指向不同对象的部分,但在它们不断变化时仍保留一些引用。我提供了一些解释。@kenarf,result包含对0节点的引用(来自构造函数),然后在第一个操作中,您将l1或l2分配给result.next对象,最后将current分配给current.next,因此result.next变为current。当循环重复时,每个节点都被附加到结果的末尾。问题不是说代码不工作,只是他们不理解它。将两个链表变为一个合并链表并非不可能。您可能认为创建一个包含所有新节点的新链表更可取(坦白说,在没有任何上下文的情况下很难证明这一点),但这并不意味着不可能像您所说的那样对现有链表进行修改。@Servy,好吧,我从未考虑过这种方法。这肯定会更节省空间。