【问题标题】:Sorting while insertion vs Sorting the whole array later插入时排序与稍后对整个数组进行排序
【发布时间】:2017-12-22 15:46:37
【问题描述】:

假设我有一个包含整数 (

  1. 案例 1:将所有数据复制到数组中并排序(假设 O(nlgn))。
  2. 案例 2:在将每个元素插入数组时进行排序。

哪个更安全,为什么? 哪个更快,为什么? 如果整数的数量进一步增加(> 10 ^ 9),那意味着什么?

我尝试了这两种情况,“排序后”在速度方面产生了更好的结果。我明白为什么,但是有没有更好的方法来做情况 2(目前检查输入元素与数组中的每个元素是否合适位置)。

【问题讨论】:

  • 当你保持数组排序时,你应该使用二进制搜索来找到插入点。另外,你实际上是如何插入到数组中的?
  • 找到合适的位置并将其他所有位置上移一个位置。
  • 数字是唯一的吗?如果是这样,您可以将它们插入SortedSet,然后在该集合上调用toArray。如果有重复,您可以使用TreeMap,但更复杂。
  • 元素

标签: java arrays sorting


【解决方案1】:

将元素插入已经排序的数组(又名Insertion Sort)的问题是:当实际插入元素时,可以使用二进制搜索在 O(log n) 中找到插入元素的索引,以下所有元素都必须移动,导致(平均)O(n/2) 用于插入array[]ArrayList

当使用LinkedList时,元素不必移动,但在这里,你也不能二分查找:找到插入的索引大约是O(n/4)(根据this overview),另一个O(n/4)用于实际插入元素,添加到O(n/2),与为ArrayList。 (您可以创建自定义 Skip List 提供更快的查找和同时插入,但 AFAIK Java 不提供 something like this。)

如果数字是唯一的,您可以考虑将它们插入TreeSet,然后在最后调用toArray。插入每个数字将是 O(log n),总共 O(n log n),另外还有一个 O(n)每次您按排序顺序获得数字时。 (根据您的评论,它们不是唯一的,但也许这对其他人有帮助。)您仍然可以使用这种方法的变体,使用 TreeMap,将元素映射到它们的计数,但这将更复杂地实现。

因此,首先收集 array[]ArrayListLinkedList 中的数字,然后在最后进行排序似乎更好——当然,前提是您不需要数组的排序版本在每个步骤中。

“排序插入”会给您(平均)O(log n + n/2) = O(n/2) 用于插入每个 n 个数字,总共 O(n²/2),同时始终保持有序数组。最后的排序是 O(1) 用于插入 n 个数字中的每一个加上最后的 O(n log n) (或者当你需要在两者之间的排序列表时),导致 O(n + k n log n) = O(k n log n) 用于排序 k > 0 次。 (如果我们求解 k,我们会发现,只要 k ,最后的排序会更快。)

【讨论】:

  • 链表排序可以使用bottom up merge sort 来实现,它将节点合并到一个指向列表的指针的小数组中。收到所有元素后,将数组合并以形成单个排序列表。但是,链表排序比数组排序慢,因此如果可以选择使用数组,则使用链表可能不切实际。
【解决方案2】:

您应该使用二分搜索,而不是针对数组中的每个元素检查新元素(线性搜索):检查它属于数组的哪一半,然后将那一半切成两半,依此类推。这将产生O(n log n),与排序后的方法相同。

【讨论】:

  • 虽然这是真的,但插入本身将从插入点到数组末尾是线性的。鉴于数组的实现在内存中是连续的,我认为大多数 JVM 数组都是?
  • 你当然是对的。我是在用渐近运行时的数学术语而不是在实际的编程术语中考虑这个问题。这意味着无论渐近运行时间如何,案例 1 总是更快 - 当您可以从头到尾构建数组时,重复插入数组只是一个坏主意。
【解决方案3】:

案例 1:将 n 元素插入数组需要 n 时间,因为附加到数组是恒定时间。然后排序后需要n log n 时间,因此总共需要n log n

案例 2:将元素插入到排序数组中的“正确”位置需要 log n 时间(使用二进制搜索)。对n 元素执行此操作会产生n log n 的运行时间。

两者花费的时间相同,但案例 2 将使用 n 内存,而根据您的排序算法,案例 1 可能需要更多内存。

【讨论】:

  • 嗯,finding 位置需要 O(log n),但实际上 inserting 元素(并将以下所有元素“向上移动” ) 可能需要 O(n),具体取决于列表的类型。
  • 在原始数组的情况下,这将是无用的,但最好用于 LinkedList。对吗?
  • @tobias_k 情况2的最坏情况复杂度是n ^ 2 ??
  • @Atul 听起来很对,但实际上它更像 O(n²/2),因为列表一开始是空的,而且您不必总是移动所有元素。
猜你喜欢
  • 2019-07-15
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多