I've seen some resources on implementation of a max-heap in python based on dynamic arrays and indexing. However, I haven't yet seen an OOP tree-node based implementation. I'm wondering if there is a reason for this; would a node based implementation have worse time/space complexity? Is this array implementation just so much more succinct that a tree-node implementation isn't worth the effort? Some other reason?
时间:良好的实施方法通过成为完整的二进制树。保持完整性对于数组实现是微不足道的。让我们专注于将新值推向现有树。当您将数据推到包含 n 值的基于零的数组时,最初将在概念上将其放置在数组的位置 n 时,然后根据需要将其弹出。气泡上的过程涉及从概念上向下滑动的亲本值,直到不再违反堆属性,然后在该位置插入新值。由于树已完成,但可以通过日志(n)界限,但经常可以更快地终止。相反,基于节点的树的完整性具有挑战性。首先,您需要确定将成为新节点的父的节点,该节点需要穿越树或维护每个节点或维护邻居参考 n th 位置。更新一系列推动和流行音乐的指针涉及其他工作,如果您将其拧紧,天堂会为您提供帮助。冒泡的过程必须在所有经过的节点,他们的父母和兄弟姐妹的左,右和父母上进行指针更新。再次,胜利进入了数组实现。
The reasons are the ones you list. A tree-node based algorithm is less efficient in both space and time.
Space: An array implementation requires storage of just the data payload, and conceptual tree relationships are determined using trivial arithmetic operations. A tree-node implementation would require additional storage for the parent, left-child, and right-child. Win goes to the array.
Time: A good heap implementation gains its efficiency by being a complete binary tree. Maintaining completeness is trivial for the array implementation. Let's focus on pushing a new value into an existing tree. When you push data to a zero-based array containing n values, it will be initially be conceptually placed at location n of the array and then bubble up as needed. The bubble up process involves conceptually sliding successive parent values downwards until there's no longer a violation of the heap property, then inserting the new value at that location. This is bounded by log(n), since the tree is complete, but can frequently terminate sooner. In contrast, completeness for a node-based tree is challenging. First you need to identify the node that will become the new node's parent, which requires traversing the tree or maintaining neighbor references for each node or maintaining a pointer to the parent of the nth location. Updating pointers across a sequence of pushes and pops involves additional work, and heaven help you if you screw it up. The bubbling up process has to do pointer updates on left, right, and parent for all traversed nodes, their parents, and their siblings. Once again, the win goes to the array implementation.
Recycling array locations is easy — just put the new data in the next location for pushes and increment the count (letting python expand the array if needed), and decrement the count but leave the backing array as-is for pops. With a node-based tree, you either need to be constantly allocating/freeing nodes (computationally expensive), or store previously used nodes in an auxilliary container such as a stack to be recycled (additional storage).
Bottom line: Node based implementations are possible, but they're not worth it.
发布评论
评论(1)
原因是您列出的原因。基于树节的算法在空间和时间上的效率均不佳。
空间:数组实现需要仅存储数据有效载荷,并使用微不足道的算术操作确定概念树的关系。树节点的实现将需要父母,左子女和右子女的额外存储空间。获胜进入阵列。
时间:良好的实施方法通过成为完整的二进制树。保持完整性对于数组实现是微不足道的。让我们专注于将新值推向现有树。当您将数据推到包含
n
值的基于零的数组时,最初将在概念上将其放置在数组的位置n
时,然后根据需要将其弹出。气泡上的过程涉及从概念上向下滑动的亲本值,直到不再违反堆属性,然后在该位置插入新值。由于树已完成,但可以通过日志(n)界限,但经常可以更快地终止。相反,基于节点的树的完整性具有挑战性。首先,您需要确定将成为新节点的父的节点,该节点需要穿越树或维护每个节点或维护邻居参考n
th 位置。更新一系列推动和流行音乐的指针涉及其他工作,如果您将其拧紧,天堂会为您提供帮助。冒泡的过程必须在所有经过的节点,他们的父母和兄弟姐妹的左,右和父母上进行指针更新。再次,胜利进入了数组实现。回收阵列位置很容易 - 只需将新数据放在下一个位置以进行按下并增加计数(如果需要的话,请扩展python扩展数组),然后减少计数,但将支持用的倒数数组AS-IS留给POPS。使用基于节点的树,您要么需要不断分配/释放节点(计算昂贵),要么将先前使用的节点存储在辅助容器中,例如要回收的堆栈(附加存储)。
底线:基于节点的实现是可能的,但它们不值得。
The reasons are the ones you list. A tree-node based algorithm is less efficient in both space and time.
Space: An array implementation requires storage of just the data payload, and conceptual tree relationships are determined using trivial arithmetic operations. A tree-node implementation would require additional storage for the parent, left-child, and right-child. Win goes to the array.
Time: A good heap implementation gains its efficiency by being a complete binary tree. Maintaining completeness is trivial for the array implementation. Let's focus on pushing a new value into an existing tree. When you push data to a zero-based array containing
n
values, it will be initially be conceptually placed at locationn
of the array and then bubble up as needed. The bubble up process involves conceptually sliding successive parent values downwards until there's no longer a violation of the heap property, then inserting the new value at that location. This is bounded by log(n), since the tree is complete, but can frequently terminate sooner. In contrast, completeness for a node-based tree is challenging. First you need to identify the node that will become the new node's parent, which requires traversing the tree or maintaining neighbor references for each node or maintaining a pointer to the parent of then
th location. Updating pointers across a sequence of pushes and pops involves additional work, and heaven help you if you screw it up. The bubbling up process has to do pointer updates on left, right, and parent for all traversed nodes, their parents, and their siblings. Once again, the win goes to the array implementation.Recycling array locations is easy — just put the new data in the next location for pushes and increment the count (letting python expand the array if needed), and decrement the count but leave the backing array as-is for pops. With a node-based tree, you either need to be constantly allocating/freeing nodes (computationally expensive), or store previously used nodes in an auxilliary container such as a stack to be recycled (additional storage).
Bottom line: Node based implementations are possible, but they're not worth it.