存储数字流中最大的 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 个数字的主要内容,如果未能解决你的问题,请参考以下文章

输入类型=具有最小值和最大值的文本模式数字

base64加密后有5000个字节。文件有多大

存储数字的最大数据类型

varchar2存储汉字,英文字符,数字在oracle中的多少

varchar2存储汉字,英文字符,数字在oracle中的多少

如何获得两个数字之间的最大素数并将它们存储在数组中?