【问题标题】:Loop that creates doubles and insert them into sorted array, in C在 C 中创建双精度并将它们插入排序数组的循环
【发布时间】:2012-09-18 09:12:52
【问题描述】:

假设我有一组排序的双精度数。

{ 0.124, 4.567, 12.3 }

一个正的非零双精度是由代码的另一部分创建的,需要插入到这个集合中,同时保持它的排序。例如,如果创建的double是7.56,那么最终的结果是,

{ 0.124, 4.567, 7.56, 12.3 }

在我的代码中,这个“创建双精度并在排序集中插入”过程会重复很多次。可能 500k 到 100 万次。我不知道总共会创建多少个双打,但我知道上限。

尝试

我天真的第一种方法是创建一个长度 = 上限的数组并用零填充,然后将初始的双精度集添加到其中(“添加”= 用双精度值替换 0 值条目)。每当创建一个 double 时,我将它添加到数组中并进行插入排序,我读到这对于排序有序数组很有用。

问题

我感觉运行 500k 到 100 万个插入插槽将是一个严重的性能问题。 (或者我错了吗?)在 C 中是否有更有效的数据结构和/或算法来执行此操作?

编辑:

我想让集合保持排序的原因是因为在每次“创建双精度并插入排序集合”过程之后,我需要能够查找该集合中的最小元素(并可能通过替换它来删除它带 0)。我认为最好的方法是保持集合排序。

但如果不是这样,也许还有其他选择?

【问题讨论】:

  • 如果您要拥有 100 万个条目,也许跳过列表会有所帮助。
  • 必须是排序列表吗?这个问题更适合平衡二叉搜索树(或类似的有序树)。
  • @nneonneo - 在每个“创建和插入”过程之后,我需要能够选择集合中最小的双精度数。我认为最好的方法是保持这个集合排序(将编辑以反映这一点)。在这种情况下我可以使用平衡二叉搜索树吗?
  • 如果你只需要 smallest double,使用最小堆。这是 O(log n) 插入和 O(1) 最小查询。

标签: c sorting


【解决方案1】:

由于您只想在每次迭代中提取最小元素,因此请改用min-heap。您可以将它们实现为具有 O(1) insertion、O(1) find-min 和 O(1) decrease-key 操作(但请注意,删除最小元素总是需要 O(log n) 时间)。对于你正在做的事情,堆会快得多。

【讨论】:

  • 谢谢!听起来这可能是解决方案。正要让你写下那条评论作为答案。将查找 min-heap (我不熟悉它),并接受它是否有效。我想您不知道 C 中最小堆的良好指南或教程(甚至库)吗?
  • C++ STL (stackoverflow.com/questions/2786398/…) 中有最小堆,但我不知道 C OTOH 中的任何实现。但是,一旦你有了这个想法,二进制堆就很容易实现,并且可以很容易地在数组之上实现(
  • 我应该注意到,如果你不经常删除最小元素,二叉堆会有点慢。但是,无论如何,O(n log n) 比 O(n^2) 要好得多。
  • 注明。我打算每次“find-min”时删除最小元素。会做一些阅读以获得更好的图片,然后+1并接受你的答案。非常感谢您的帮助!
【解决方案2】:

您可以使用二进制搜索来查找插入点,然后在其中插入值,而不是运行插入排序。但这很慢,因为您可能需要多次移动大量数据(想想如果随机数据与您需要的相反排序会发生什么情况,时间将是O(N^2))。

最快的方法是先插入,然后一次对所有内容进行排序。如果这不可行,请考虑使用自平衡有序树结构替换您的数组,例如 RB-Tree

【讨论】:

  • 或者甚至是一个 B-tree,在叶子中具有固定大小的数组。
  • 使用二分查找并没有渐近地更快(实际上可能会慢一点,因为您通常可以在查找元素时执行数组移动)。我认为,有序的树结构将是这项任务的理想选择。 (或者,只是一个巨大的数组,事后排序......)
  • @nneonneo 这就是第二段的精髓。
  • 其实运行时间为什么会是O(n^2 logn)?它只有 O(n^2)。每个循环的运行时间由数组移动决定,而不是二分查找。
  • @nneonneo 是的,你是对的,每个嵌套迭代都是O(N+LogN),而不是O(N*LogN)。谢谢!
猜你喜欢
  • 1970-01-01
  • 2018-02-18
  • 2016-08-24
  • 2011-05-30
  • 2020-03-18
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多