假设我有一个带整数的文件(< 10 ^ 6)。我需要使用这些整数制作一个排序数组。考虑以下情况
哪个更安全,为什么? 哪个更快,为什么? 如果整数的数量进一步增加(> 10 ^ 9),那么其含义是什么?
我尝试了这两种情况,并在排序后进行了#39;在速度方面产生了更好的结果。我可以看到原因,但是有更好的方法来做案例2(目前检查输入元素与数组中的每个元素以找到它的合适位置)。
答案 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[]
或ArrayList
或LinkedList
中的数字,然后在结尾处进行排序似乎更好 - 当然,前提是您不需要每个步骤中数组的排序版本。
“排序插入”将为您(平均) 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可能需要更多内存。