根在 arr[0] 的二叉堆有啥好处
Posted
技术标签:
【中文标题】根在 arr[0] 的二叉堆有啥好处【英文标题】:What are the benefits of a binary heap with root at arr[0]根在 arr[0] 的二叉堆有什么好处 【发布时间】:2018-09-22 20:31:54 【问题描述】:我正在通过数组 arr
编写二进制堆。
除了叶子节点之外的每个节点都有两个孩子。
根可以在arr[0]
或arr[1]
。
Why in a heap implemented by array the index 0 is left unused? 接受的答案是 arr[1]
更快。
但该答案下方的一条评论说,大多数实现都将 root 设置为 arr[0]
。
将根放在arr[0]
有什么好处?
【问题讨论】:
节省空间?坦率地说,您发布的链接表明任何性能差异都会很小,这似乎回答了您的问题。 呃。节省 1 个节点的空间以使每个操作都变慢一点?如果是这样的话,我想我会把根放在arr[1]
。
如果你想从1
开始索引,去FORTRAN写代码,如果你想写正确的C,数组索引从0
开始。
@DavidC.Rankin 有趣的是,在那些从 1 开始的语言中,生成的代码是从 0 开始的。编译器会为你做索引偏移。
我想人类从1, 2, ..
给打孔卡编号比给它们编号0, 1, ...
更容易,因此该语言的创建者也将其应用于索引。回想一下,自从工程师在衬衫口袋里装计算尺以来,FORTRAN 就已经存在了……
【参考方案1】:
我是回答您所链接问题的人。
在具有从 0 开始的数组的语言中创建根位于 arr[1]
的二进制堆是愚蠢的。不是因为它浪费了微不足道的空间,而是因为它无益地创建了不必要的混乱代码。
为什么代码令人困惑?因为它打破了我们程序员多年来一直遵循的基本规则:数组从 0 开始。如果你想要一个包含 100 项的数组,你可以这样声明:
int a[100];
二进制堆除外。因为一些在 1973 年将原始二进制堆代码从 Algol(其数组基于 1)转换为 C(基于 0 的数组)的白痴没有大脑来更改子和父计算,所以我们结束了在这种特殊情况下,您必须分配 101 个物品来存放 100 个物品:
int a[101];
当有人打电话给那个人时,他提出了一个似是而非的表现论点。
是的,计算左子索引的代码中有一个额外的递增指令,计算子父索引时还有一个额外的递减指令。在二叉堆所做的更广泛的背景下,这两条指令不会对使用堆的任何程序的运行时间产生实际影响。没有。如果差异甚至可以测量,那肯定会很吵。您的计算机上还会发生许多其他事情,这些事情会对您的程序性能产生更大的影响。
如果您正在编写一个需要高性能优先级队列的程序,那么您首先要使用二进制堆做什么?如果你真的要在优先级队列中存储大量的东西,你可能应该使用像配对堆这样的东西,它会比二叉堆更好,尽管内存成本更高。
C++ STL priority_queue
、Java PriorityQueue
和 python 的 heapq 都使用从 0 开始的二进制堆。编写这些包的人了解性能方面的考虑。如果使用基于 1 的二进制堆可以显着提高性能,他们就会这样做。他们使用基于 0 的堆应该告诉您,从基于 1 的堆获得的任何性能提升都是虚幻的。
有关更完整的讨论,请参阅http://blog.mischel.com/2016/09/19/but-thats-the-way-weve-always-done-it/。
【讨论】:
我认为这很好地捕捉到了它。懒惰的程序员从 Algol 或 FORTRAN 等早期语言中提取了许多算法,只是简单地复制和实现了代码,而没有任何预先考虑在 C 中正确索引。“C 中的数字食谱”一书就是一个很好的例子。这足以驱使任何有原则的 C 程序员不得不重写和重新索引所谓的 C 例程。以上是关于根在 arr[0] 的二叉堆有啥好处的主要内容,如果未能解决你的问题,请参考以下文章