我有这个问题需要解决。我不是在寻找答案,而是在寻找应该去的地方。我有一个算法,但它不是O(log n)。
给定二叉树T和一个不大于T中节点数的正整数k,写入伪代码来识别T中的元素v,使得T中的精确k - 1个元素小于v。您的代码应该花时间最多与之成正比 T的高度。
我在这里的基本想法是,我首先检查左侧树,检查左侧树的大小。如果左侧树的大小大于k-1,则继续向左搜索。否则我会搜索右。如果整个左侧树不包含具有k-1个元素的节点,则我搜索右侧子树。问题是我知道这不是O(log n),因为最坏的情况是我必须搜索树中的每个节点。
我有什么遗失的吗?任何提示或帮助都会很棒,但请不要只给我一个答案。
答案 0 :(得分:0)
(我假设树实际上是二进制搜索树,而不仅仅是任何旧的二叉树)
您的算法为O(d)
,其中d
是树的最大深度。
这是因为每次进行这种比较时,你会继续向下一级(假设你还没有找到该元素)。因此,您将最多进行与树中的级别一样多的比较。
因此,除非您的树真的不平衡,否则您实际上并不会查看每个元素。事实上,如果你可以假设树是平衡的,那么你已经很好了(为什么?)。
答案 1 :(得分:0)
如果我们谈论的是常规二叉树,那么很容易证明你需要探索整个树来找到这样一个节点,所以我假设我们正在谈论二元搜索树。
在二叉搜索树中,以下小于节点N:
节点A,它的左子节点及其所有后代,其中节点B是节点A的右子节点,节点B是节点N或其任何祖先。
A
/ \
X B
/ \
Y ...
\ /
Z N
A,X,Y和Z都小于N.(按照同样的规则,B也小于N)。
节点N的左子项
我怀疑你假设所有的孩子都比较小。
** SPOILER ALERT **
<强>算法:强>
寻找m
元素较小的节点......
从顶部开始。
设x
=左子树中的节点数(如果没有左子,则x = 0)
如果x = m
,则返回当前节点。
如果x < m
,请向左递归。
如果x > m
,请设置m = m - x - 1
并向右递送。
由于您只向左或向右移动,并且节点计数是常量(因为它是在节点级别给出的),因此运行时间为O(h)
,其中h
是树的高度,在平衡树中是O(log n)
。
答案 2 :(得分:0)
它与quickselect的算法几乎相同。根据左分支的大小递归到左或右分支。
Find(T, k) :=
size(T.left) == k - 1 -> return T
size(T.left) > k - 1 -> return Find(T.left, k)
size(T.left) < k - 1 -> return Find(T.right, k - size(T.left) - 1)
问题中没有直接给出(但 在评论中澄清)尺寸(T)是O(1)。
这需要最多高度(T)步长,因为在每个递归步骤中高度至少减少1。
你也可以迭代地写这个:
Find(T, k) :=
while size(T.left) != k - 1:
if size(T.left) > k - 1:
T = T.left
else:
T = T.right
k -= size(T.left) + 1
return T