链表去重代码疑问:为何函数结束时head为null仍正确?
问题解析:为何
removeDuplicates函数中head最终为null但仍能正确去重? 先贴出你提供的代码:
static void removeDuplicates(Node head) { HashSet<Integer> set = new HashSet<>(); Node previous = null; while (head != null) { if (set.contains(head.data)) { previous.next = head.next; } else { set.add(head.data); previous = head; } head = head.next; } }
核心原因:Java的参数传递是值传递
你混淆了函数内的「局部变量head」和调用者传入的「链表头引用」。函数里的head只是传入引用的一个副本——你在函数里执行head = head.next,只是改变了这个局部副本的指向,完全不会影响调用者那边原本的链表头变量。
函数真正的作用:修改链表的结构(而非头引用)
这个函数的核心逻辑是通过修改节点的next指针来跳过重复节点:
- 当检测到重复节点时,让
previous.next指向当前节点的下一个节点,相当于把当前重复节点从链表中移除 - 遇到非重复节点时,将当前节点数据加入集合,并把
previous移动到当前节点,继续遍历
整个过程中,链表的实际结构(节点间的连接关系)被修改了,而局部变量head只是用来遍历链表的工具,它最后变成null只是遍历到链表末尾的标志,和链表本身的正确性毫无关系。
举个直观例子:
假设原链表是1 -> 2 -> 2 -> 3
- 初始
head指向1,将1加入集合,previous变为1,head移动到2 - 第二个2被检测到重复,
previous.next(也就是1的next)指向3,跳过第二个重复节点 head继续移动到3,将3加入集合,previous变为3,head移动到null,循环结束
最终链表变成1 -> 2 -> 3,完全符合去重预期,而函数里的head只是遍历到了末尾的null,根本不会影响调用者手里的原链表头引用。
额外补充:函数的小缺陷
这个函数存在一个边界问题:如果链表的第一个节点就是重复的(比如1 -> 1 -> 2),它没法修改头节点——因为previous初始为null,第一次遇到重复时执行previous.next会抛出空指针异常。不过这和你问的head变null的问题无关,只是顺便提一下。
内容的提问来源于stack exchange,提问作者oerol
相关产品推荐
相关产品推荐

