我正在编写一个函数,它将接收链表的头部,删除所有重复项,并返回新的头部。我已经测试了它,但我想知道你是否可以捕获任何错误或改进它。
removeDuplicates(Node head)
if(head == null) throw new RuntimeException("Invalid linked list");
Node cur = head.next;
while(cur != null) {
if(head.data == cur.data) {
head = head.next;
} else {
Node runner = head;
while(runner.next != cur) {
if(runner.next.data == cur.data) {
runner.next = runner.next.next;
break;
}
runner = runner.next;
}
cur = cur.next;
}
return head;
}
答案 0 :(得分:3)
如果你愿意在这个过程中花费更多的RAM,你可以在不改变结构的情况下让它快得多。
对于桌面应用程序,我通常喜欢使用更多RAM并赢得一些速度。所以我会做这样的事情。
removeDuplicates(Node head) {
if (head == null) {
throw new RuntimeException("Invalid List");
}
Node current = head;
Node prev = null;
Set<T> data = new HashSet<T>(); // where T is the type of your data and assuming it implements the necessary methods to be added to a Set properly.
while (current != null) {
if (!data.contains(current.data)) {
data.add(current.data);
prev = current;
current = current.next;
} else {
if (prev != null) {
prev.next = current.next;
current = current.next;
}
}
}
}
这应该在O(n)时间内运行。
修改强>
我希望我认为这是某种项目/家庭作业,你被迫使用链接列表是正确的,否则,如上所述,你最好使用不同的数据结构。
答案 1 :(得分:1)
我没有检查你的代码是否有bug,但我确实有改进它的建议。分配将Node映射到布尔值的Hashtable或HashMap。在处理每个元素时,如果它不是哈希中的键,则添加它(使用Boolean.TRUE作为值)。如果它确实作为键存在,那么它已经出现在列表中,你可以简单地删除它。
这比你的方法更快,因为哈希查找在大致恒定的时间内工作,而你有一个内部循环,必须在每个列表元素的列表的整个剩余部分下去。
此外,您可以考虑使用equals()
测试代替==
是否更适合您的应用。
答案 2 :(得分:1)
要有效删除重复项,您应远离链接列表:请改用java.util.PriorityQueue;它是一个已排序的集合,您可以为其定义排序标准。如果您总是插入已排序的集合中,则可以在插入时直接删除重复项,也可以使用单个O(n)-pass进行按需。
答案 3 :(得分:0)
除了使用列表的元素来创建哈希映射并使用它作为键来测试每个元素,这对于大量元素来说是理想的,其中 large 依赖于创建哈希映射所需的资源,顺序扫描列表是一个实用的选项,但还有其他更快。请参阅user138170的答案here - 就地合并排序是 O(n log(n))操作,它不使用额外的空间,而使用单独分配的数组的解决方案将在 O(n)时间工作。实际上,您可能想要分析代码并确定合理的 n,值,其中 n 是列表中元素的数量,之后分配内存的解决方案将用而不是不用的那个。
编辑:如果效率非常重要,我建议不要使用链表(主要是为了保持缓存一致性),也许是使用JNI并本地实现该功能;数据也必须在本机分配的缓冲区中提供。