Python 绘制(Cormen)红黑树插入时出现奇怪结果

Python 绘制(Cormen)红黑树插入时出现奇怪结果,python,big-o,red-black-tree,Python,Big O,Red Black Tree,我根据Cormen的《算法简介》中的伪代码,在Python中用红黑树实现 我想亲眼看到我的insert实际上是O(logn),因此我绘制了在树中插入n=1,10,20,…,5000个节点所需的时间 结果是: x-轴是n,y-轴是以毫秒为单位的时间 在我看来,这张图更像是线性的,而不是对数的。有什么可以解释呢?5000可能不够大,无法真正“看到”对数——请尝试在50000和500000处运行。如果需要2秒20秒,那么线性增长是有意义的。如果需要更少的时间,那么对数是有意义的。如果你把大多数“简单

我根据Cormen的《算法简介》中的伪代码,在Python中用红黑树实现

我想亲眼看到我的
insert
实际上是
O(logn)
,因此我绘制了在树中插入
n=1,10,20,…,5000个节点所需的时间

结果是:

x
-轴是
n
y
-轴是以毫秒为单位的时间


在我看来,这张图更像是线性的,而不是对数的。有什么可以解释呢?

5000
可能不够大,无法真正“看到”对数——请尝试在
50000
500000
处运行。如果需要2秒20秒,那么线性增长是有意义的。如果需要更少的时间,那么对数是有意义的。如果你把大多数“简单”函数放大得足够近,结果看起来是线性的。

对于任何“为什么”的问题总是有一些猜测。我怀疑您看到的跳跃与系统内存管理有关。如果系统必须分配更大的内存空间以继续增长,则会增加一定的时间来完成整个程序的处理。如果您向节点添加了一个“payload”字段,从而增加了所需的存储空间量(我是正确的),那么跳转将更频繁地发生


顺便说一句,这是一个很好的图表。

好的,因此图表显示了在树中插入
n
元素的成本度量,其中x轴是我们插入的元素数量,y轴是总时间

让我们调用一个函数,该函数汇总将n个元素插入到树中所需的时间
f(n)

然后我们可以大致了解
f
的外观:

f(1) < k*log(1)                 for some constant k.

f(2) < k*log(1) + k*log(2)      for some constant k

...

f(n) < k * [log(1) + log(2) + ... + log(n)]   for some constant k.
我们可以看看维基百科,看看
log(n!)
是什么样子的。看看这篇文章中的图表。你看起来应该很熟悉。:)

也就是说,我认为你这样做是偶然的:

for n in (5000, 50000, 500000):
    startTime = ...
    ## .. make a fresh tree
    ## insert n elements into the tree
    stopTime = ...
    ## record the tuple (n, stopTime - startTime) for plotting
并绘制了构建大小为n的树的总时间,而不是将一个元素插入大小为n的树的单个成本:

for n in range(50000):
    startTime = ...
    ## insert an element into the tree
    stopTime = ...
    ## record the tuple (n, stopTime - startTime) for plotting

Chris Taylor在评论中指出,如果绘制
f(n)/n
,您将看到一个对数图。这是因为相当接近于
log(n!)
的是
n*log(n)
(参见维基百科页面)。所以我们可以回到我们的领域:

f(n) < k * log(n!)                for some constant k
一些常数k的f(n)
并获得:

f(n) < k * n * log(n)             for some constant k
f(n)

现在应该更容易看到,如果你用
f(n)
除以
n
,你的图形将以对数的形状为界。

对不起,你一定看到了使用pypy的预编辑版本。我相信这就是跳转的原因。所以
50000
需要2.5秒,
500000
需要30秒,根据你的猜测,这看起来是线性的,这正是我要发布的答案!扎克,如果你绘制
f(n)/n
,你会看到你的日志图像白天一样清晰。
f(n) < k * n * log(n)             for some constant k