首页 > 解决方案 > 为什么对象的值会发生变化,即使它有不同的引用?

问题描述

我对这里的对象引用感到困惑。合并 2 个已排序的链表是 LC 问题。

我知道在第一次迭代current.next时引用了同一个对象,所以当我为值更改result分配新值时。current.nextresult

在第二次迭代中 r1 和 r2 都是假的,所以result, current and current.next指向不同的对象。

我不明白为什么为 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;
        }
public class ListNode
    {
        public int val;
        public ListNode next;
        public ListNode(int x = 0, ListNode next = null)
        {
            val = x;
            next = null;
        }
    }

编辑

假设我们有这些:

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;
}

此时我们有: 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 < l2.val所以我们执行

if (l1.val < l2.val)
{
    current.next = l1;
    l1 = l1.next;
}

此时我们有:

result = [0,1,1,2,4], current = [1,1,2,4], l2 = [3,4], l1 = [2,4]

这是我不明白的部分:结果和当前指向不同的对象,当当前更改结果仍然如此。结果如何保持对当前的参考?

接下来我们执行current = current.next, so current = [1,2,4],所以我们修改 current 但这次结果没有改变。

标签: c#oopreference

解决方案


结果和当前指向不同的对象,当当前更改结果时仍然如此。结果如何保持对当前的参考?

看看你问题的这一部分:

所以current = [1,3,4],它不再指向结果。

重要的是1,该列表的 in与in的元素相同。如果您修改该节点的字段,您将修改该节点所属的任何列表。包括引用的列表。1result = [0,1,3,4]next1result

稍后当你写:

此时我们有:

result = [0,1,1,2,4], current = [1,1,2,4], l2 = [3,4], l1 = [2,4]

请注意,列表result指向列表current指向不同。但是在第一个节点之后,它相同的。

在第一次迭代之后,result.next引用相同的对象current。这是因为resultandcurrent开始于引用同一个对象,然后作为第一次迭代的最后一步,current更改为 reference current.next。因为currentresult当时是一样的,current.next而且result.next也是一样的。所以改成 之后currentcurrent.next就和设置成一样了result.next

所以在第二次迭代中,result.nextcurrent都是一样的。这意味着当您修改时current.next,这与修改相同result.next.next,其效果是将result列表中前两个元素之外的内容替换为l2引用的新元素链。

再说一遍:这里的关键是每个变量都只指向一个节点。可以将其概念化为指向节点列表,但前提是您要记住,如果您修改该next列表中任何节点的字段,那么您就是在修改整个列表,即使该变量没有引用引用的变量列表的根。


推荐阅读