Algorithm 选择分隔数字序列中第i个最小数字的最佳方法

Algorithm 选择分隔数字序列中第i个最小数字的最佳方法,algorithm,optimization,search,binary-tree,big-o,Algorithm,Optimization,Search,Binary Tree,Big O,如果给我一组特定的数字(为了方便起见,我将其存储在一个平衡的二进制搜索树中),那么我想回答一个查询,该查询要求我告知[a,B]之间的第I个最小数字是什么,执行该任务的快速算法是什么 从技术上讲,我可以从根遍历树,搜索A(或者如果A不存在,则直接大于A的数字),而不是回溯搜索B(或者小于B的数字),同时我可以为I保留一个计数器,以确定何时我将位于第I个数字。但这在我看来并不理想 我可以在O(logn)上执行此操作吗?O是我用来存储通用数字集的树的高度 谢谢如果您能在节点中保留一些信息,您当然可以做

如果给我一组特定的数字(为了方便起见,我将其存储在一个平衡的二进制搜索树中),那么我想回答一个查询,该查询要求我告知[a,B]之间的第I个最小数字是什么,执行该任务的快速算法是什么

从技术上讲,我可以从根遍历树,搜索A(或者如果A不存在,则直接大于A的数字),而不是回溯搜索B(或者小于B的数字),同时我可以为I保留一个计数器,以确定何时我将位于第I个数字。但这在我看来并不理想

我可以在O(logn)上执行此操作吗?O是我用来存储通用数字集的树的高度


谢谢

如果您能在节点中保留一些信息,您当然可以做到这一点。要进行遍历
O(logn)
,我们需要让每个节点知道其右子树有多少个节点。(您可以维护此信息,并且在O(log(n))时间内仍然可以添加到树或从树中删除)

代码应该是不言自明的。
我们从
currentNode
开始,它是第一个编号
>=A
的节点,并查找第k个元素(k是基于0的)

  • 正如schnaader在他的评论中所说,如果
    k
    为 小的
  • 大多数广泛分布的库(如STL)不允许以这种方式遍历树(它们不提供任何类型的
    节点
    结构以及指向左、右子树的指针)。所以,虽然算法很简单,但实现起来可能很困难
  • 从你的问题中只考虑很少的修改来考虑<代码> b>代码> 。
    如果可以在节点中保留一些信息,您当然可以做到这一点。要进行遍历
    O(logn)
    ,我们需要让每个节点知道其右子树有多少个节点。(您可以维护此信息,并且在O(log(n))时间内仍然可以添加到树或从树中删除)

    代码应该是不言自明的。
    我们从
    currentNode
    开始,它是第一个编号
    >=A
    的节点,并查找第k个元素(k是基于0的)

  • 正如schnaader在他的评论中所说,如果
    k
    为 小的
  • 大多数广泛分布的库(如STL)不允许以这种方式遍历树(它们不提供任何类型的
    节点
    结构以及指向左、右子树的指针)。所以,虽然算法很简单,但实现起来可能很困难
  • 从你的问题中只考虑很少的修改来考虑<代码> b>代码> 。
    我想我这里有点不对劲,但是你不能直接搜索大于A的值,然后遍历
    I
    -1次吗?这是一个二叉搜索树,所以它被排序了,不是吗?我想象你的树是这样的:-在这个例子中,f.e.在[15,60]中搜索第四个最小的数字会得到50,对吗?@schnaader我猜,他想在一棵大小为100000的树中搜索第50000个数字:),但如果k很小,你的方法肯定是最优的。@Nikita:谢谢你的澄清。@schanaader这是正确的。我的算法必须适用于大型数据集,例如,我可以有100k个随机数,然后给我一个范围,可能是[10250],然后要求我找到数据集中包含的第27个最小数(存储在AVL树中),这也在给定的区间内,我想我在这里搞错了,但是你不能搜索一个大于A的值,然后遍历
    I
    -1次吗?这是一个二叉搜索树,所以它被排序了,不是吗?我想象你的树是这样的:-在这个例子中,f.e.在[15,60]中搜索第四个最小的数字会得到50,对吗?@schnaader我猜,他想在一棵大小为100000的树中搜索第50000个数字:),但如果k很小,你的方法肯定是最优的。@Nikita:谢谢你的澄清。@schanaader这是正确的。我的算法必须适用于大型数据集,例如,我可以有100k个随机数,然后给我一个范围,可能是[10250],然后我会被要求找到数据集中包含的第27个最小数(存储在AVL树中),这也在给定的intervalHi Nikkita范围内,谢谢你的回答。事实上,我已经记住了你描述的算法。但我的想法是,如果我首先运行搜索以查找a(并使用您的命名法确定我的currentNode),然后回溯我的树,在搜索a和B之间间隔的第I个数字(或确定它不存在)时检查子树上的元素数,我不必再执行一些操作,通过这样做,我的复杂性将大于O(logn),因为这本身就是我搜索A?非常感谢;)@AlexTex在二叉树中查找第一个数>=A需要精确的O(logn)时间。我描述的算法也需要O(logn)时间。而O(logn+logn)=O(logn),所以整个算法需要O(logn)时间。(假设你已经计算出了子树的大小)嗨,Nikkita,谢谢你的回复。事实上,我已经记住了你描述的算法。但我的想法是,如果我首先运行搜索以查找a(并使用您的命名法确定我的currentNode),然后回溯我的树,在搜索a和B之间间隔的第I个数字(或确定它不存在)时检查子树上的元素数,我不必再执行一些操作,通过这样做,我的复杂性将大于O(logn),因为这本身就是我搜索A?非常感谢;)@AlexTex在二叉树中查找第一个数>=A需要精确的O(logn)时间。我描述的算法也需要O(logn)时间。而O(logn+logn)=O(logn),所以整个算法需要
    def search(currentNode, k)
        if k == 0 then
            return currentNode
        else if currentNode.rightBranchSize >= k then
            // we remove 1 from k because currentNode isn't considered anymore
            return search(currentNode.right, k - 1)
        else
            // we decrease k because currentNode and its whole right subtree aren't considered anymore
            return search(currentNode.parent, k - currentNode.rightBranchSize - 1)
        end
    end