我不确定如何遍历下面的树结构,以便节点始终按升序排列。对数组[9 8 7 6 5 4 3 2 1 0]
进行修改会产生数组[0 1 3 2 5 4 7 9 6 8]
,我认为该对应于此表示:
想要保持数组不变(因为我想稍后进行高效的插入)如何以升序有效地遍历它? (即按此顺序访问节点[0 1 2 3 4 5 6 7 8 9]
)
答案 0 :(得分:3)
只需对数组进行排序。之后它仍然是一个小堆,没有其他算法渐进地更有效。
答案 1 :(得分:2)
您无法遍历堆,就像您可以遍历BST一样。如果排序遍历是一项重要的操作,@ Dukeling对于BST是一个更好的选择是对的。但是,您可以使用以下算法,该算法需要额外的O(1)空间。
假设您拥有通常数组形式的堆。
删除项目需要O(n log n)时间。逆转是另一个O(n)。
如果您不需要一直遍历,可以随时停止并通过运行O(n)heapify操作“修复”阵列。例如,请参阅pseudocode here。
答案 2 :(得分:1)
我实际上建议self-balancing binary search tree (BST)在这里:
二叉搜索树(BST)...是基于节点的二叉树数据结构,具有以下属性:
- 节点的左子树仅包含键小于节点键的节点。
- 节点的右子树只包含键大于节点键的节点。
- 左右子树每个也必须是二叉搜索树。
- 必须没有重复的节点。
以排序顺序(所谓的有序遍历)遍历BST比使用堆执行BST更简单,更节省空间。
BST将支持O(log n)插入和O(n)遍历。
如果在再次进行遍历之前进行大量插入操作,则在遍历之前将其排序为数组可能更有效 - 插入的相关运行时间为O(1)和O(n log) n)获得排序顺序 - 这个选项变得比使用BST更有效的确切点需要进行基准测试。
为了好奇,这里是你如何按排序顺序遍历堆(如果你知道,你不想只是从堆中删除最小值,直到它为空,这可能是更简单的选择,因为删除最小值是堆的标准操作。)
从堆的属性中,没有什么能阻止一些元素出现在左子树中,右边的元素在左边,后面的元素再次出现,等等 - 这意味着你不能完全完成左子树然后从右边开始 - 你可能需要在内存中保留大量的堆。
主要思想是基于一个元素总是小于其子元素的事实。
基于此,我们可以构建以下算法:
这需要O(n log n)时间和O(n)空间(作为参考,BST遍历需要O(log n)空间),更不用说增加的代码复杂性。