Algorithm 查找最小堆是否有k个比查询小的元素

Algorithm 查找最小堆是否有k个比查询小的元素,algorithm,heap,time-complexity,Algorithm,Heap,Time Complexity,很长时间以来,我一直在琢磨这个问题。我需要找到一个O(k)算法来确定一个最小堆是否有k比一个查询q更小的元素 我尝试过这样的递归算法: count = 0; def kSmaller(H, q, k){ if (root(H) == Null or root(H) >= q ) return; else {count++; if (count == k) return true; kSmaller(LeftChild(root(H), q,

很长时间以来,我一直在琢磨这个问题。我需要找到一个O(k)算法来确定一个最小堆是否有
k
比一个查询
q
更小的元素

我尝试过这样的递归算法:

count = 0;
def kSmaller(H, q, k){
   if (root(H) == Null or root(H) >= q ) return;
   else {count++;
         if (count == k) return true;
         kSmaller(LeftChild(root(H), q, k)
         kSmaller(RightChild(root(H), q, k)
    }
}
但是在阅读了一些min-heap示例之后,我不太明白如何在O(k)时间内终止,而不是不必要地遍历每个元素


有人能帮我理解如何处理这个问题吗?也许最好不要使用递归,而是将解决方案展平。

最小堆的排列方式是每个节点都比它的两个子树中的所有节点都小。因此,当您看到大于或等于q值的节点时,您的代码将花费O(k)时间,因为您将停止递归。你可以画几个例子看看。如果最小堆的p个节点小于q,那么您只需要Min(p,k)时间,您可以看到吗?

最小堆的排列方式是每个节点都比它的两个子树中的所有节点都小。因此,当您看到大于或等于q值的节点时,您的代码将花费O(k)时间,因为您将停止递归。你可以画几个例子看看。如果最小堆的p个节点小于q,那么您将只使用Min(p,k)时间,您可以看到吗?

另一种方法可以看到此算法实际上是O(k)时间:


让所有节点最初都为白色。如果通过调用增加
计数的
kSmaller()
访问节点,则将其颜色设置为黑色;如果通过调用不增加计数的
kSmaller()
访问节点,则将其颜色设置为灰色。当
count
未递增时,递归停止,因此灰色节点下的每个节点都必须为白色;OTOH,黑色节点的每个子节点必须是黑色或灰色。显然,确实存在
count
黑色节点,由于每个节点最多有2个子节点,因此最多可以有
count*2
灰色节点,因此总体上最多可以有
count*3
访问(即黑色或灰色)节点。由于
count
显然始终保持另一种方法可以看出该算法实际上是O(k)时间:


让所有节点最初都为白色。如果通过调用增加
计数的
kSmaller()
访问节点,则将其颜色设置为黑色;如果通过调用不增加计数的
kSmaller()
访问节点,则将其颜色设置为灰色。当
count
未递增时,递归停止,因此灰色节点下的每个节点都必须为白色;OTOH,黑色节点的每个子节点必须是黑色或灰色。显然,确实存在
count
黑色节点,由于每个节点最多有2个子节点,因此最多可以有
count*2
灰色节点,因此总体上最多可以有
count*3
访问(即黑色或灰色)节点。因为
count
显然总是正确的,这只是因为min堆是如何构造的。这是一个与我的代码有关的一般性问题。如果我在递归的某个级别内返回“true”,它是为整个函数返回true,还是只返回到它上面的递归级别?@MarksCode:true返回到上一个递归级别。你可能想修改你的代码来处理子问题的递归调用返回的值。嗯,好吧,我理解返回一个递归级别,但就修改来处理返回的值而言,我并不完全理解你的意思,但我会考虑更多。谢谢是的,这只是因为最小堆是如何构造的。这是一个与我的代码有关的一般性问题。如果我在递归的某个级别内返回“true”,它是为整个函数返回true,还是只返回到它上面的递归级别?@MarksCode:true返回到上一个递归级别。你可能想修改你的代码来处理子问题的递归调用返回的值。嗯,好吧,我理解返回一个递归级别,但就修改来处理返回的值而言,我并不完全理解你的意思,但我会考虑更多。谢谢