始终保持n个最佳元素的数据结构

时间:2009-02-19 06:04:05

标签: language-agnostic data-structures priority-queue

我需要一个数据结构,它总是保存到目前为止插入的n个最大项目(没有特定的顺序)。

因此,如果n为3,我们可以进行以下会话,其中插入一些数字并且容器的内容发生变化:

[]  // now insert 1
[1] // now insert 0
[1,0] // now insert 4
[1,0,4] // now insert 3
[1,4,3] // now insert 0
[1,4,3] // now insert 3
[4,3,3]

你明白了。数据结构的名称是什么?实现这个的最佳方法是什么?或者这是在某个图书馆吗?

我正在考虑使用一个容器,其元素(委托)具有priority_queue,它使用反向比较,因此pop将删除最小的元素。因此insert函数首先检查要插入的新元素是否大于最小元素。如果是这样,我们抛出那个最小的并推动新元素。

(我有一个C++实现,但问题仍然与语言无关。)

8 个答案:

答案 0 :(得分:13)

您想要的特定数据结构可能是隐式堆。原始数据结构只是一个数组;为方便起见,假设它的大小为N = 2 ^ n个元素,并且你想保持最大的N-1个元素。

我们的想法是将数组(称为A)视为深度为n的完整二叉树:

  • 忽略A [0];将A [1]视为根节点
  • 对于每个节点A [k],孩子是A [2 * k]和A [2 * k + 1]
  • 节点A [N / 2..N-1]是叶子

要将树维护为“堆”,您需要确保每个节点小于(或等于)其子节点。这称为“堆条件”:

  • A [k]< = A [2 * k]
  • A [k]< = A [2 * k + 1]

使用堆来维护最大的N个元素:

基本上,这将导致任何替换元素“过滤”树,直到它达到其自然位置。这将最多花费n = log2(N)步骤,这是你能得到的最好的。此外,树的隐式形式允许非常快速的实现;现有的有界优先级队列库很可能使用隐式堆。

答案 1 :(得分:5)

在Java中,您可以使用已实现的SortedSet,例如通过TreeSet。每次插入后检查集合是否太大,如果是,则删除最后一个元素。

这是相当有效的,我已经成功地用它来解决几个Project Euler问题。

答案 2 :(得分:4)

priority_queue是C ++中最接近STL的东西。您可以将它包装在另一个类中,以创建自己的实现,自动修剪大小。

语言 - 非法(尽管可能不是内存碎片 - 安全):

  1. 插入数据
  2. 排序
  3. 删除第n个元素后的所有内容
  4. std :: priority_queue为你做了第2步。

答案 3 :(得分:2)

答案 4 :(得分:1)

是不是可以从排序的集合中获取前n个元素?

答案 5 :(得分:0)

是的,你可以保持最小的头部大小N. 然后在每次插入时将新项目与根项目进行比较 弹出根并插入项目,如果它比根“更大” 最后你最终获得了N个最大的项目

答案 6 :(得分:0)

在Pyhton中,使用heapq。在其周围创建一个小的包装,如下所示:

class TopN_Queue:
    def __init__(self, n):
        self.max_sz = n
        self.data = []

    def add(self, x):
        if len(self.data) == self.max_sz:
            heapq.heappushpop(self.data, x)
        else:
            heapq.heappush(self.data, x)

...

答案 7 :(得分:-1)

创建一个小堆,也存储一个计数器。

每当到达柜台时;提取分钟。

你可以这样做:O(1)insert,get-min和O(log log n)extract-min。[1]或者你可以用O(log n)插入和O(1)做到这一点)对于其他提到的操作。[2]


[1] M. Thorup,“整数优先级队列在恒定时间内减少关键并且单源最短路径问题”,在纽约州纽约市第35届年度ACM计算理论研讨会论文集中,USA,2003,pp.149-158。

[2] G. S. Brodal,G。Lagogiannis,C。Makris,A。Tsakalidis和K. Tsichlas,“指针机器中的最佳手指搜索树”,J.Comput。 SYST。 Sci。,vol。 67,不。 2,pp.381-418,2003年9月。