存储数字流中最大的 5000 个数字
Posted
技术标签:
【中文标题】存储数字流中最大的 5000 个数字【英文标题】:Store the largest 5000 numbers from a stream of numbers 【发布时间】:2012-05-31 21:22:48 【问题描述】:鉴于以下问题:
“”
想到的解决方案是二叉搜索树,它维护树中节点数的计数,并在计数达到 5000 时引用最小节点。当计数达到 5000 时,每个要添加的新数字都可以与树中最小的项目进行比较。如果更大,则可以添加新数字,然后删除最小的数字并计算新的最小数字(这应该很简单,已经有了以前的最小数字)。
我对这个解决方案的担忧是二叉树自然会偏斜(因为我只删除一侧)。
有没有一种方法可以解决这个问题,并且不会产生非常倾斜的树?
如果有人想要的话,我已经在下面为我的解决方案提供了伪代码:
process(number)
if (count == 5000 && number > smallest.Value)
addNode( root, number)
smallest = deleteNodeAndGetNewSmallest ( root, smallest)
deleteNodeAndGetNewSmallest( lastSmallest)
if ( lastSmallest has parent)
if ( lastSmallest has right child)
smallest = getMin(lastSmallest.right)
lastSmallest.parent.right = lastSmallest.right
else
smallest = lastSmallest.parent
else
smallest = getMin(lastSmallest.right)
root = lastSmallest.right
count--
return smallest
getMin( node)
if (node has left)
return getMin(node.left)
else
return node
add(number)
//standard implementation of add for BST
count++
【问题讨论】:
您可以使用平衡搜索树,例如 AVL 或类似的 (en.wikipedia.org/wiki/AVL_tree)。但是基于堆的解决方案更自然。 【参考方案1】:对此最简单的解决方案是保持最小 heap 的最大大小为 5000。
每次有新数字到达时 - 检查堆是否小于 5000,如果是 - 添加它。 如果不是 - 检查最小值是否小于新的 元素,如果是,则将其弹出并插入新元素。 完成后 - 您有一个包含 5000 个最大元素的堆。此解决方案的复杂度为O(nlogk)
,其中n
是元素数,k
是您需要的元素数(在您的情况下为 5000)。
也可以在O(n)
中使用selection algorithm 完成 - 存储所有元素,然后找到第 5001 个最大的元素,并返回大于它的所有元素。但它更难实现和合理的大小输入 - 可能不会更好。此外,如果流包含重复项,则需要进行更多处理。
【讨论】:
+1 用于选择算法。只想补充一点:STL C++ 对此有实现。不过,不确定Java。然而,这种离线计算方法需要 O(n) 空间复杂度。 关于选择算法的优点。 OTOH 这需要 O(n) 内存。 您可以使用选择算法找到前 k 个元素,但通过存储 2k 个元素的数组仅使用 O(k) 内存。每次填充数组时,使用选择算法删除最低的 k。无论 k 的值如何,这都会花费 O(n) 时间,因为您正在执行 O(n / k) 选择算法,每个算法都需要 O(k) 时间。它也只使用 O(k) 内存。 @amit 在这种方法中假设我们从流的开头得到 1(假设流仅是自然数)然后它到达最小堆的顶部并停留在那里并且一旦达到堆大小(5000),就不会再对流的其余部分进行替换,因此从不是前 5000 个数字的意义上说,答案可能是不正确的。 @redzedi 它将在下一个数字到来时被替换,假设你有一个大小为 5000 的堆,顶部是 1,然后是 5。它会检查 5 是否大于最小元素 (1) - 确实如此,因此会弹出 1,并插入 5 而不是它。请记住,它是一个最小堆,所以 1 是“头”。【参考方案2】:使用(最低)优先级队列。将每个传入项目添加到队列中,当大小达到 5,000 时,每次添加传入元素时删除最小(顶部)元素。队列将包含 5,000 个最大的元素,当输入停止时,只需删除内容。此 MinPQ 也称为堆,但这是一个重载术语。插入和删除大约需要 log2(N)。 N 最大值为 5,000,这将是您正在处理的项目数的 12 [log2(4096) = 12] 倍。
Robert Sedgewick 和 Kevin Wayne 的 Algorithms(第 4 版)是一个很好的信息来源。 coursera.org 上有一个基于此文本的优秀 MOOC。
【讨论】:
以上是关于存储数字流中最大的 5000 个数字的主要内容,如果未能解决你的问题,请参考以下文章
varchar2存储汉字,英文字符,数字在oracle中的多少