我一直对此感到困惑,可能是因为我对编译器缺乏了解。但是让我们以python为例。如果我们有一些名为numlist的大型数字列表,并希望摆脱任何重复,我们可以使用列表上的set运算符,例如set(numlist)。作为回报,我们将拥有一组数字。据我所知,此操作将在O(n)时间内完成。虽然如果我要创建自己的算法来处理这个操作,我绝对希望的最好的是O(n ^ 2)。
我不知道的是,什么允许像set()这样的内部操作比语言算法的外部操作快得多。检查仍然需要完成,不是吗?
答案 0 :(得分:3)
您可以使用哈希表在Θ(n)
平均时间内执行此操作。哈希表中的查找和插入平均为Θ(1)
。因此,您只需运行n
项目,并检查每个项目是否已存在于哈希表中,以及是否未插入项目。
我不知道的是,什么允许像set()这样的内部操作比语言算法的外部操作快得多。检查仍然需要完成,不是吗?
如果由语言实现者实现而不是由语言的用户实现,则算法的渐近复杂度不会改变。只要两者都用图灵完整语言和随机存取存储器模型实现,它们就具有相同的能力,并且每个算法中实现的算法将具有相同的渐近复杂度。如果一个算法在理论上是O(f(n))
,那么它是否用汇编语言实现并不重要,C#或它上面的Python仍然是O(f(n))
。
答案 1 :(得分:1)
算法的复杂性界限与它是“内部”还是“外部”
完全无关答案 2 :(得分:1)
将列表转换为set()
的集合是O(n)。
这是因为set
被实现为哈希集。这意味着要检查集合中是否存在某些内容或者向集合中添加内容只需要O(1),恒定时间。因此,要从可迭代(例如列表)创建集合,您只需从空集开始并逐个添加可迭代的元素。由于有n个元素且每个插入都需要O(1),因此将迭代转换为集合的总时间为O(n)。
要了解哈希实现的工作原理,请参阅hash tables
上的维基百科artcle答案 3 :(得分:1)
您可以使用任何语言在O(n)中执行此操作,基本上如下:
# Get min and max values O(n).
min = oldList[0]
max = oldList[0]
for i = 1 to oldList.size() - 1:
if oldList[i] < min:
min = oldList[i]
if oldList[i] > max:
max = oldList[i]
# Initialise boolean list O(n)
isInList = new boolean[max - min + 1]
for i = min to max:
isInList[i] = false
# Change booleans for values in old list O(n)
for i = 0 to oldList.size() - 1:
isInList[oldList[i] - min] = true
# Create new list from booleans O(n) (or O(1) based on integer range).
newList = []
for i = min to max:
if isInList[i - min]:
newList.append (i)
我在这里假设append
是一个O(1)操作,它应该是除非实施者脑死亡的。因此,对于每个O(n)的k步,您仍然有O(n)运算。
是否在代码中明确完成了步骤,或者是否在语言的掩盖下完成这些步骤无关紧要。否则你可以声称C qsort
是一个操作,你现在有一个O(1)排序程序的圣杯: - )
正如许多人发现的那样,您通常可以在时间复杂度上权衡空间复杂性。例如,上述方法仅适用,因为我们允许引入isInList
和newList
变量。如果不允许这样做,下一个最佳解决方案可能是对列表进行排序(可能没有更好的O(n log n)),然后是O(n)(我认为)操作以删除重复项。
一个极端的例子,您可以使用相同的额外空格方法在O(n)时间内对任意数量的32位整数(比如每个只有255或更少的重复项)进行排序,分配大约40亿个字节来存储计数。
只需将所有计数初始化为零,然后运行列表中的每个位置,根据该位置的数字递增计数。那是O(n)。
然后从列表的开头开始并运行计数数组,将许多正确的值放在列表中。那是O(1),其中1当然是大约40亿,但仍然是恒定的时间: - )
这也是O(1)空间复杂度,但是非常大的“1”。通常情况下,权衡并不是那么严重。
答案 4 :(得分:0)
我无法想到如何在O(n)中做到这一点,但这里很酷:
n ^ 2和n之间的差异太大了,实现它和python实现之间的差异与用于实现它的算法相比微不足道。 n ^ 2总是比O(n)差,即使n ^ 2一个在C中而O(n)一个在python中。你永远不应该认为这种差异来自于你不是用低级语言写作的事实。
也就是说,如果你想实现自己的,你可以做一个排序,然后删除重复。排序是n * ln(n),并删除O(n)...
中的重复项答案 5 :(得分:0)
这里有两个问题。
时间复杂度(以大O表示法表示)是算法在给定集合大小下运行多长时间的正式度量。它更多地是关于算法的缩放程度,而不是绝对速度。
算法的实际速度(例如,以毫秒为单位)是时间复杂度乘以常数(在理想世界中)。
两个人可以用O(log(n)* n)复杂度实现相同的复制算法删除,但如果用Python写入它而另一个用优化的C写入,则C程序会更快。 / p>