我多次访问二叉树的最小元素。哪些实现允许我访问常量时间中的最小元素,而不是O(log n)
?
答案 0 :(得分:10)
根据您的其他要求,您可能正在寻找min-heap。它为您提供了最小元素的恒定时间检索。
但是,您不能像使用简单的二叉搜索树一样轻松地执行其他操作,例如确定值是否在树中。您可以查看splay trees,这是一种自平衡二叉树,可以提高对最近访问过的元素的访问时间。
答案 1 :(得分:9)
在O(log n)中找到一次,然后将要添加的新值与此缓存的最小元素进行比较。
UPD:如果删除最小元素,该如何工作。你只需要再花一次O(log n)并找到新的。
让我们假设你的树中有10 000 000 000个整数。每个元素在内存中需要4个字节。在这种情况下,您的所有树都需要大约40 TB的硬盘空间。在这个巨大的树中搜索最小元素所花费的时间O(log n)大约是43次操作。当然,这不是最简单的操作,但无论如何,即使对于20年前的处理器来说也几乎没有。
当然,如果这是一个现实世界的问题,这是实际的。如果出于某些目的(也许是大学)你需要真正的O(1)算法,那么我不确定我的方法可以在不使用额外内存的情况下为你提供这样的性能。
答案 2 :(得分:4)
这可能听起来很愚蠢,但是如果您主要访问最小元素,并且不要过多地更改树,则在添加/删除(在任何树上)维护指向最小元素的指针可能是最佳解决方案。 / p>
答案 3 :(得分:3)
走树总是O(log n)。你自己编写了树实现吗?您始终可以简单地将对当前最低值元素的引用存储在数据结构旁边,并在添加/删除节点时保持更新。 (如果你没有编写树,你也可以通过将树实现包装在你自己的包装器对象中来做同样的事情。)
答案 4 :(得分:2)
TAOCP中有一个实现,它使用非完整节点中的“备用”指针按顺序完成沿节点的双链表(我现在不记得详细信息,但是我图像必须为每个方向都有一个“has_child”标志才能使其正常工作。
使用它和一个开始指针,你可以在O(1)时间内获得起始元素。
此解决方案缓存最小值的速度不快或效率更高。
答案 5 :(得分:1)
如果通过最小元素表示具有最小值的元素,那么您可以使用TreeSet
与自定义Comparator
对项目进行排序正确的顺序来存储单个元素,然后只需调用SortedSet#first()
或#last()
即可尽可能高效地获取最大/最小值。
请注意,与其他集/列表相比,向TreeSet
插入新项目的速度稍慢,但如果您没有大量不断更改的元素,那么它应该不是问题。
答案 6 :(得分:0)
如果你可以使用一点点记忆,那么听起来像一个合并的集合可能对你有用。
例如,您正在寻找的内容听起来很像链接列表。您始终可以获得最小元素,但插入或查找任意节点可能需要更长时间,因为您必须执行查找O(n)
如果您将链接列表和树组合在一起,您可能会获得两全其美的效果。要查找项目以获取/插入/删除操作,您可以使用树来查找元素。元素的“持有者”节点必须具有从树到链接列表进行删除操作的方法。链表也必须是双重链表。
所以我认为获得最小的项目是O(1),任意查找/删除都是O(logN) - 我认为即使插入也是O(logN),因为你可以找到把它放在哪里树,查看前一个元素并从那里跨越到链接列表节点,然后添加“next”。
嗯,这开始看起来像一个非常有用的数据结构,可能在内存中有点浪费,但我不认为任何操作会比O(logN)更差,除非你必须重新平衡树。 / p>
答案 7 :(得分:0)
如果你将二进制树升级/“upcomplex”为threaded binary tree,那么你可以获得O(1)的第一个和最后一个元素。
您基本上保留对当前第一个和最后一个节点的引用。
插入后,如果第一个上一个非空,则立即更新。同样是最后一次。
每当您删除时,首先要检查被删除的节点是第一个还是最后一个。然后更新存储的第一个,最后一个。