队列数据结构支持快速第k个最大元素发现

时间:2012-09-21 14:00:19

标签: java c++ algorithm data-structures

我遇到了一个需要队列数据结构支持快速第k个最大元素查找的问题。

此数据结构的要求如下:

  1. 队列中的元素不一定是整数,但它们必须相互比较,即当我们比较两个元素时,我们可以分辨出哪一个更大(它们也可以相等)。

  2. 数据结构必须支持enqueue(在尾部添加元素)并出列(删除头部的元素)。

  3. 它可以快速找到队列中第k个最大元素,请注意k不是常数。

  4. 您可以假设操作入队,出队和第k个最大元素查找都以相同的频率发生。

  5. enter image description here

    我的想法是使用修改后的平衡二叉搜索树。该树与普通平衡二叉搜索树相同,除了每个节点 i 用另一个字段n i 增强,n i 表示数字包含在具有根节点 i 的子树中的节点。支持上述操作如下:

    为简单起见,假设所有元素都是不同的。

    入队(x):首先将x插入树中,假设对应的节点是节点 t ,我们追加对(x,指向节点的指针) t )到队列。

    Dequeue :假设(e1,node 1 )是头部的元素,node 1 是指向对应的树的指针E1。我们从树中删除节点 1 并从队列中删除(e1,node 1 )。

    第K个最大元素发现:假设根节点是节点 root ,其两个子节点是 left 节点 sub (假设它们都存在),我们将K与n root 进行比较,可能会发生三种情况:

    1. 如果K < n left 我们在n root 的左子树中找到第K个最大的元素;

    2. 如果K&gt; n root -n right ,我们找到(Kn root + n right ) - n root 右子树中的最大元素;

    3. 否则n root 是我们想要的节点。

    4. 所有三个操作的时间复杂度为O(log N ),其中N是当前队列中元素的数量。

      如何加快上述操作?有什么数据结构和方式?

3 个答案:

答案 0 :(得分:9)

注意 - 对于所有人来说,你不可能达到O(logn)更好,最多你需要“选择”你最关心的操作。 (否则,您可以通过将数组提供给DS,并查询第1,第2,第3,......第n个元素来对O(n)进行排序)

  • 使用skip list代替平衡BST作为排序结构 可以减少出列的复杂性O(1) 平均情况。确实如此 不影响任何其他操作的复杂性。
    要从跳过列表中删除 - 您需要做的就是使用队列头部的指针到达元素,然后按照链接并删除每个链接。需要删除的预期节点数是1 + 1/2 + 1/4 + ... = 2.
  • 通过从leftest节点(而不是根节点)开始,找到Kth可以在O(logK) 中实现,直到找到“需要更多儿子”为止,然后将刚找到的节点视为根,就像问题中的算法一样。虽然渐近复杂度更好 - 常数因子是双倍的。

答案 1 :(得分:2)

我发现了一篇有趣的论文:

2008年VLDB中发布的不确定流上的滑动窗口Top-k查询,由71引用。

https://www.cse.ust.hk/~yike/wtopk.pdf

VLDB是数据库研究领域的最佳会议,引用次数证明数据结构确实有效。

这篇论文看起来很难,但如果你真的需要改进你的数据结构,我建议你阅读本文的论文或论文。

答案 2 :(得分:1)

您还可以使用finger tree

  

例如,可以通过在树中使用子节点的最小优先级标记内部节点来实现优先级队列,或者可以通过节点中的叶子计数来标记节点来实现索引列表/数组。儿童。手指树可以提供摊销的O(1)缺点,反转,cdr,O(log n)追加和分割;并且可以适用于索引或有序序列。

另请注意,作为纯粹的功能结构使其成为并发使用的理想选择。