LeetCode21合并两个有序链表:outputNode.next返回结果原理咨询
LeetCode 21 合并两个有序链表dummy节点逻辑解答
核心原因是混淆了Java对象引用和对象本身的概念,整个逻辑拆解开非常简单:
- 代码执行
ListNode outputNode = new ListNode(0);时,会在堆内存里创建一个值为0的虚拟头节点(dummy),outputNode这个变量存的是这个节点的内存地址,指向这个节点。 - 紧接着
ListNode tail = outputNode;并没有创建新的节点,只是让tail这个变量也存了同一个dummy节点的内存地址,此时两个变量指向完全同一个对象。
后续遍历合并的全流程里,两个变量的分工非常明确:
- 每次选到更小的待合并节点时,执行
tail.next = 选中节点:因为此时tail指向的是结果链表当前的最后一个节点,修改它的next属性,就是把新节点接到结果链表的尾部。注意:第一次执行这行代码的时候,tail还指向最开始的dummy节点,所以这一步本质上就是直接修改了dummy节点的next属性,把第一个真实的结果节点挂到了dummy后面——这时候虽然你没写outputNode.next = xxx,但因为两个引用一开始指向同一个对象,这步修改已经同步到outputNode指向的dummy节点上了。 - 接完新节点后执行
tail = tail.next;:这一步只是把tail这个引用往后移动一位,让它指向刚接好的新的尾节点,方便下一次接新节点。而outputNode从始至终都没有被重新赋值,一直稳稳指向最开始创建的那个dummy节点,从来没移动过。 - 循环结束后把剩余没遍历完的链表直接挂到tail的next上,整个结果链表就拼接完成了。
你可以把这个过程类比成串珠子:
dummy节点是你一开始捏在手里的那个绳扣,outputNode就是你捏着绳扣的那只手,全程不动。tail是你另一只负责穿珠子的手,一开始和捏绳扣的手放在同一个位置,每穿一颗珠子,穿珠子的手就往前挪到刚穿好的珠子位置,准备穿下一颗。等所有珠子穿完,你捏着的绳扣从来没动过,只要把绳扣本身摘掉(也就是返回
outputNode.next,跳过占位用的dummy节点),剩下的就是一整串穿好的有序珠子。
另外你贴的代码里有两行冗余逻辑:最后两个if块里的list2 = list2.next;和list1 = list1.next;完全没有作用,因为后续不会再操作list1和list2了,这部分可以简化成一行:
tail.next = list1 != null ? list1 : list2;
内容的提问来源于stack exchange,提问作者allison xu
相关产品推荐
相关产品推荐

