【发布时间】:2021-04-17 06:11:55
【问题描述】:
我正在学习 C#/Java 中的数据结构和算法。遇到Linked List去重问题的解决方法后,一直在努力理解。
解决方案是名著Cracking the coding Interview(第5版,第208页)提出的解决方案。
void RemoveDuplicates_HashSet(Node n)
{
HashSet<object> set = new HashSet<object>();
Node previous = null;
while (n != null)
{
if (set.Contains(n.Data)) // Condition 1
previous.Next = n.Next;
else // Condition 2
{
set.Add(n.Data);
previous = n;
}
n = n.Next;
}
}
使用以下链表A->B->A->B运行代码:
// Creating test Singly LinkedList
Node n = new Node("A");
n.Next = new Node("B");
n.Next.Next = new Node("A");
n.Next.Next.Next = new Node("B");
RemoveDuplicates_HashSet(n);
工作得很好:方法后n的值是A->B。
通过使用调试器跟踪代码,我可以看到方法循环中发生的情况如下:
| Pass | HashSet | n | previous | Comment |
| ---- | ------- | ---------- | ---------- | ------------------------ |
| – | – | A->B->A->B | null | |
| 1 | A | B->A->B | A->B->A->B | Condition 2 is triggered |
| 2 | A,B | A->B | B->A->B | Condition 2 is triggered |
| 3 | A,B | B | B->B | Condition 1 is triggered |
| 4 | A,B | null | B | Condition 1 is triggered |
我无法理解这实际上是如何导致的:
-
从
n删除的重复项在哪里/如何准确删除?我知道 HashSet 只包含唯一的元素,因此它会检测是否已经遇到了一个元素,但是我仍然看不到该算法的整体工作原理。 -
n指向的值怎么更新为A->B?它在哪里,鉴于本质上循环只是在链接列表上迭代执行n = n.Next,n实际上是用最终值A->B更新的?我知道列表是通过引用传递的,但我看不到它实际上是如何修改的。
【问题讨论】:
-
此代码:
if (set.Contains(n.Data)) previous.Next = n.Next检查是否已遇到该元素,如果已遇到,则从链接列表中删除n。它通过将n.Next分配给previous.Next来删除节点(这意味着previous.Next不再指向n)。 -
@Slaw 谢谢,这正是我正在寻找的答案。你让我意识到,实际上,
previous和n指向同一个列表(我错误地认为它们是同一个列表的“副本”)。因此,修改previous意味着也要修改原来的列表n。
标签: java c# algorithm linked-list pass-by-reference