【问题标题】:What is the fastest way of updating an ordered array of numbers?更新有序数字数组的最快方法是什么?
【发布时间】:2011-07-29 16:26:41
【问题描述】:

我需要计算一个必须动态维护和经常查找的一维直方图。我的一个想法是用数据保持一个有序数组(因为这样我可以确定 O(1) 中的百分位数,这足以快速找到具有非均匀箱的直方图,每个箱内的点数量完全相同)。

那么,有没有一种小于 O(N) 的方法将一个数字插入到有序数组中,同时保持有序?

我想答案是众所周知的,但我对算法知之甚少(从事数值计算的物理学家很少这样做)。

【问题讨论】:

  • 如果它实际上是一个数组(而不是例如一个链表),那么实际插入本身必然是 O(n) (因为你需要将所有后续元素移动一个)。搜索找到要插入的位置显然可以少于 O(n).
  • 数据是完全随机的还是倾向于遵循一些统计方程?如果是后者,考虑到这一点,您将获得更好的优化。您将需要概率分布的反函数。
  • 如果你没有说明你使用的语言,你可能需要说明基本array操作的运行时间,否则人们会认为它是O(1)查找,O(index)插入, ETC。;这可能是你想要的。
  • 你存储的是整数还是浮点数?
  • 嗨。我正在存储浮点数,不知道它们是如何分布的(这几乎是我的程序最终必须确定的)并且我正在使用 C++。

标签: algorithm sorting data-structures


【解决方案1】:

在一般情况下,您可以使用更灵活的树状数据结构。这将允许在 O(log) 时间内访问、插入和删除,并且相对容易从库中获得现成的(例如:C++ 的 STL 映射)。

(或哈希映射...)

二分查找的有序数组与树的作用相同,但更严格。访问和内存使用可能会更快,但在中间插入或删除内容时您需要付费(O(n) 成本)。

但是请注意,有序数组可能对您来说就足够了:如果您的数据点经常相同,您可以维护一个按键排序的对 {key, count} 的列表,从而能够快速添加另一个实例现有项目(但仍然需要做更多工作才能添加新项目)

【讨论】:

    【解决方案2】:

    您可以使用二进制搜索。这是 O(log(n))。 如果您想插入数字 x,则将数组中间的数字与 x 进行比较。如果 x 较小,则取前半部分中间的数字,否则取后半部分中间的数字,依此类推。

    【讨论】:

    • 搜索是O(log n),插入是O(n)
    • 如果array 的实现允许O(1) 插入,这将起作用;类 C 语言中的数组不会。
    • @ninjagecko:在数据结构方面它不是数组,它更像是链表,当然取决于实现
    【解决方案3】:

    如果您将数组重新排列为悬挂在每个元素上的一组链表,则可以在 O(1) 时间执行插入操作:

    keys = Array([0][1][2][3][4]......)
                  a  c  b  e  f  .  .
                  d  g     i  .  .  .
                     h     j  .
                  |__|__|__|__|__|__|__/linked lists
    

    如果您的更新工作负载支持它而不增加常见操作的时间复杂度,那么还有同时保留两个数据结构的策略。

    【讨论】:

    • 但是如果我需要得到谁是序列的第 k 个元素,那将是 O(k),不是吗?
    • @Rafael:您必须明确说明“序列的第 k 个元素”是什么意思。如果您只关心收到元素的顺序,它是O(1)(使用哈希表)。如果您关心每个链接列表...我认为您没有理由关心键相等的元素的顺序,除非您没有告诉我们某些事情。即使你这样做了,如果你并排使用这两个数据结构,它要么是O(1),要么如果你只是使用这个数据结构,它会是O(log(N))(执行二进制搜索,跟踪有多少元素在每个 bin / 每个链表中)。
    【解决方案4】:

    那么,有没有一种小于 O(N) 的方法将一个数字插入到 有序数组同时保持有序?

    是的,您可以使用数组来实现binary search tree,并在 O(log n) 时间内进行插入。怎么样?

    保持索引 0 为空;索引 1 = 根;如果节点是父节点的左子节点,则节点索引 = 2 * 父节点索引;如果节点是父节点的右子节点,则节点索引 = 2 * 父节点索引 + 1。

    因此插入将是 O(log n)。不幸的是,您可能会注意到,如果您不平衡树,即 O(n),则有序列表的二叉搜索树可能会退化为线性搜索,这是没有意义的。在这里,您可能必须实现red black tree 以保持高度平衡。但是,这非常复杂,但是可以使用 O(log n) 中的数组完成插入。请注意,数组元素将不再是整数;相反,它们必须是具有颜色属性的对象。

    我不会推荐它。

    【讨论】:

    • 搜索是O(log n),插入是O(n)
    • 我认为插入仍然是 O(log n) 因为它需要 O(log n) 才能找到插入的位置,然后从那里插入只需 O(1) 以添加到正确的索引。查找更多信息here
    • 为什么要使用数组来实现?您所需要的只是一个可迭代的结构。听起来像经典的 RB 树/AVL 树
    • @kyun 提问者问道:“那么,有没有一种小于 O(N) 的方法来将一个数字插入到有序数组中,同时保持它的有序性?”。
    • @Dhruv Gairola 我现在明白了。
    【解决方案5】:

    这需要一个数组有什么特别的原因吗?您需要一个数据结构来保持数据有序并允许您快速插入。为什么不是二叉搜索树?或者更好的是,一棵红黑树。在 C++ 中,您可以使用标准模板库中的 Set 结构,该结构被实现为红黑树。为您提供 O(log(n)) 插入时间以及像数组一样对其进行迭代的能力。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-02
      • 1970-01-01
      • 2020-01-05
      • 1970-01-01
      • 2017-03-28
      • 1970-01-01
      相关资源
      最近更新 更多