【发布时间】:2011-02-12 06:49:42
【问题描述】:
要求/约束:
- 只删除重复项
- 保留一份
- 列表最初没有排序
这如何在 C 中实现? (算法和/或代码将不胜感激!)
【问题讨论】:
标签: c data-structures linked-list
要求/约束:
这如何在 C 中实现? (算法和/或代码将不胜感激!)
【问题讨论】:
标签: c data-structures linked-list
如果列表很长并且您想要合理的性能并且您可以分配额外的 log(n) 内存,您可以使用 qsort 或合并排序在 nlog(n) 中排序:
http://swiss-knife.blogspot.com/2010/11/sorting.html
那么就可以去除n中的重复项(总数为:nlog(n) + n)
如果你的列表非常小,你可以像 jswolf19 建议的那样做,你会得到:n(n-1)/2 最差的。
【讨论】:
有几种不同的方法可以检测/删除重复项:
依次取下一个值,然后扫描到列表末尾,看看这个值是否再次出现。这是 O(n2) - 尽管我相信界限可以更低? -- 但实际性能可能会更好,因为只完成了从i 到end(不是0 到end)的扫描,并且它可能会提前终止。除了一些变量之外,这不需要额外的数据。
(请参阅 Christoph 的回答,了解如何仅使用链表的遍历和破坏性的“附加”到新列表来完成 - 例如,嵌套循环不必“感觉”像嵌套循环。)
对列表进行排序(合并排序可以修改为在链表上工作)然后检测重复值(它们现在将并排)。一个好的排序是 O(n*lg(n))。排序阶段通常是/可能是破坏性的(例如,您有“一个副本”),但它已被修改;-)
扫描列表并在扫描列表时将值添加到查找中。如果查找已包含所述值,则存在重复!如果查找访问为 O(1),则此方法可能为 O(n)。通常使用“哈希/字典”或“集合”作为查找,但如果只使用有限范围的积分,那么数组就可以正常工作(例如,索引就是值)。这需要额外的存储空间,但不需要“额外的副本”——至少在字面意思上是这样。
对于较小的 n 值,大 O 几乎毫无价值 ;-)
编码愉快。
【讨论】:
我愿意
前者会更快,后者更容易从头开始实现:只需从旧列表中弹出元素并通过扫描将它们插入新列表中,直到找到更大价值的元素(在这种情况下,您将元素插入到列表中)或相等的值(在这种情况下,您丢弃该元素)。
【讨论】:
好吧,您可以先对列表进行排序,然后检查是否有重复项,或者您可以执行以下操作之一:
for i from 0 to list.length-1
for j from i+1 to list.length-1
if list[i] == list[j]
//delete one of them
fi
loop
loop
【讨论】:
这可能是最未经优化的废话,但它可能会起作用。
遍历列表,每次进入下一个对象时都持有指向前一个对象的指针。在您的迭代循环中遍历所有内容以检查重复项。如果有重复,现在回到主迭代循环,获取下一个对象。将前一个对象的指针设置为刚刚检索到的对象的下一个对象,然后跳出循环并重新开始整个过程,直到没有重复。
【讨论】:
您可以使用哈希表在线性时间内完成此操作。
您希望按顺序浏览列表。每次遇到奇数元素时,请在哈希表中查找它。如果该数字已经在哈希表中,则将其从列表中删除,否则将其添加到哈希表中并继续。
基本上,这个想法是,对于您在列表中扫描的每个元素,您都可以在恒定时间内检查它是否与您看到的前一个元素重复。这只需要通过您的列表一次,并且最坏的情况是会占用线性内存量(最坏的情况是列表中的每个元素都是唯一的奇数,因此您的哈希表与您的列表一样长)。
【讨论】: