插入时排序vs稍后对整个数组进行排序

时间:2017-12-22 15:46:37

标签: java arrays sorting

假设我有一个带整数的文件(< 10 ^ 6)。我需要使用这些整数制作一个排序数组。考虑以下情况

  1. 案例1:将所有数据复制到一个数组中并排序(假设为O(nlgn))。
  2. 案例2:在将每个元素插入数组时进行排序。
  3. 哪个更安全,为什么? 哪个更快,为什么? 如果整数的数量进一步增加(> 10 ^ 9),那么其含义是什么?

    我尝试了这两种情况,并在排序后进行了#39;在速度方面产生了更好的结果。我可以看到原因,但是有更好的方法来做案例2(目前检查输入元素与数组中的每个元素以找到它的合适位置)。

3 个答案:

答案 0 :(得分:2)

将元素插入已排序的数组(又名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 + kn log n)= O(kn log n)用于分类 k> 0 次。 (如果我们解决 k ,我们会发现只要 k< n / 2 log n ,最后的排序会更快。)

答案 1 :(得分:1)

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

答案 2 :(得分:1)

情况1:将n元素插入数组需要n次,因为追加到数组是恒定时间。然后在n log n时间之后进行排序,总共n log n

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

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