存储来自数字流的最大5000个数字

时间:2012-05-25 09:34:49

标签: algorithm binary-search-tree

鉴于以下问题:

  

“存储数字流中最大的5000个数字”

考虑到的解决方案是二进制搜索树,它保持树中节点数的计数,并且一旦计数达到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++
}

2 个答案:

答案 0 :(得分:38)

最简单的解决方案是保持最小尺寸5000的最小heap

  • 每次有新号码到达时 - 检查堆是否小于 5000,如果是 - 加上它。
  • 如果不是 - 请检查最小值是否小于新值 如果是,则将其弹出并插入新元素。
  • 完成后 - 你有一个包含5000个最大元素的堆。

此解决方案的复杂度为O(nlogk),其中n是元素数量,k是您需要的元素数量(在您的情况下为5000)。

也可以使用selection algorithmO(n)中完成 - 存储所有元素,然后找到第5001个最大元素,并返回比它大的所有元素。但实施起来比较困难,并且合理的尺寸输入 - 可能不会更好。此外,如果流包含重复项,则需要进行更多处理。

答案 1 :(得分:1)

使用(最小)优先级队列。将每个传入项添加到队列中,当大小达到5,000时,每次添加传入元素时都删除最小(顶部)元素。队列将包含5,000个最大元素,当输入停止时,只需删除内容。这个MinPQ也称为堆,但这是一个重载的术语。插入和删除大约采用log2(N)。当N最大值为5,000时,这将超过你正在处理的项目数量的12 [log2(4096)= 12]倍。

一个很好的信息来源是Robert Sedgewick和Kevin Wayne的Algorithms,(第4版)。在coursera.org上有一个很好的MOOC,它基于这个文本。