【发布时间】:2012-09-21 14:00:19
【问题描述】:
我遇到了一个问题,需要一个支持快速第 k 个最大元素查找的队列数据结构。
这个数据结构的要求如下:
队列中的元素不一定是整数,但它们必须是相互可比的,即我们可以通过比较两个元素来判断哪个更大(它们也可以相等)。
数据结构必须支持入队(添加尾部元素)和出队(移除头部元素)。
可以快速找到队列中第k大的元素,请注意k不是常数。
您可以假设操作 enqueue 、 dequeue 和第 k 个最大元素查找都以相同的频率发生。
我的想法是使用修改后的平衡二叉搜索树。该树与普通平衡二叉搜索树相同,只是每个节点i都增加了另一个字段ni,ni表示数字根节点i 的子树中包含的节点数。上述操作支持如下:
为简单起见,假设所有元素都是不同的。
Enqueue(x):x首先插入到树中,假设对应的节点是nodet,我们追加pair(x,pointer to node t) 到队列中。
Dequeue:假设(e1, node1)是头部元素,node1是指向对应的树的指针e1。我们从树中删除 node1 并从队列中移除 (e1, node1)。
K-th最大元素查找:假设根节点是noderoot,它的两个子节点是nodeleft和noderight (假设都存在),我们比较 K 和 nroot ,可能会出现三种情况:
如果 Kleft 我们在 nroot 的左子树中找到第 K 个最大的元素;
如果 K>nroot-nright 我们找到 (Knroot+nright)-nroot的右子树中的最大元素;
否则nroot就是我们想要的节点。
这三个操作的时间复杂度都是 O(logN) ,其中 N 是当前队列中的元素个数。
如何加快上述操作?使用什么数据结构以及如何使用?
【问题讨论】:
-
这似乎是一个人为的容器(找到第 k 个元素但不删除它,所有操作的频率相同) - 您能否提供有关您要解决的潜在问题的更多信息?如果您真的需要所有这些要求,我认为您已经找到了可靠的解决方案。
-
@Mark B,我正在处理一个数据流,我想知道滑动窗口中当前的第 k 个最大元素。其实我想找到前k个元素。
-
这可能有点难读,但boost::multiIndex 可以帮助解决这个问题。
-
@outlaw,谢谢。我想我同意马克 B 的观点。如果
k是常量(不是),您可以使用堆来跟踪第 k 个元素。这将允许 O(1) 找到第 k 个元素和 O(logN) 用于入队/出队。 -
值得将二叉搜索树和队列组合成一个单一的结构。只需为每个节点使用一个额外的指针,它应该指向 FIFO 顺序中的下一个节点。
标签: java c++ algorithm data-structures