这个问题出现在我的中期计算机科学入门考试准备考试中。
存在一种算法,可以在列表中找到第k个元素 O(n)时间,并假设它已到位。使用这个算法, 写一个在最坏的情况下运行的就地排序算法 O(n * log(n)),并证明它确实如此。鉴于此算法存在, 为什么mergesort仍在使用?
我假设我必须写一些替代形式的快速排序算法,其最坏情况是O(n ^ 2),因为merge-sort不是就地算法。令我困惑的是给定的算法来查找列表中的第k个元素。是不是通过已经是O(n)算法的数组元素进行简单的循环迭代?
如果排序算法的运行时间没有在执行时间内发生任何变化,那么所提供的算法怎么能有所不同呢?我不知道如何使用快速排序,插入排序或选择排序,它可以将最坏的情况降低到O(nlogn)。任何意见都表示赞赏!
答案 0 :(得分:1)
检查wiki,即“按排序选择”部分:
类似地,给定中值选择算法或应用于查找中值的一般选择算法,可以将其用作Quicksort中的枢轴策略,从而获得排序算法。如果选择算法是最优的,意味着O(n),那么得到的排序算法是最优的,意味着O(n log n)。中位数是排序的最佳枢轴,因为它可以均匀地划分数据,从而保证最佳排序,假设选择算法是最优的。使用Quicksort中的枢轴策略(近似中值),存在类似于中位数中值的排序,并且类似地产生最佳Quicksort。
简短回答为什么mergesort在某些情况下优先于快速排序是it is stable(而快速排序不是)。
答案 1 :(得分:0)
合并排序的原因。合并排序稳定。合并排序比快速排序更多,但比较少。如果比较开销大于移动开销,则合并排序更快。比较开销可能更大的一种情况是排序索引数组或指向对象的指针,如字符串。
如果对链表进行排序,那么使用指向工作列表的第一个节点的指针数组进行合并排序是我所知道的最快的方法。这就是HP / Microsoft std :: list :: sort()的实现方式。在指针数组中,array [i]为NULL或指向长度为pow(2,i)的列表(除了最后一个指针指向无限长度的列表)。
答案 2 :(得分:0)
我找到了解决方案:
if(start>stop) 2 op.
pivot<-partition(A, start, stop) 2 op. + n
quickSort(A, start, pivot-1) 2 op. + T(n/2)
quickSort(A, pibvot+1, stop) 2 op. + T(n/2)
T(n)=8+2T(n/2)+n k=1
=8+2(8+2T(n/4)+n/2)+n
=24+4T(n/4)+2n K=2
...
=(2^K-1)*8+2^k*T(n/2^k)+kn
Recursion finishes when n=2^k <==> k=log2(n)
T(n)=(2^(log2(n))-1)*8+2^(log2(n))*2+log2(n)*n
=n-8+2n+nlog2(n)
=3n+nlog2(n)-8
=n(3+log2(n))-8
is O(nlogn)
答案 3 :(得分:0)
快速排序具有最坏情况O(n ^ 2),但只有在选择枢轴时运气不佳时才会出现这种情况。如果你可以选择O(n)中的第k个元素,这意味着你可以通过执行额外的O(n)步骤来选择一个好的数据透视表。这产生了一个woest-case O(nlogn)算法。仍然使用mergesort的原因有两个。首先,这种选择算法在现场实现或多或少都很麻烦,并且还为常规快速排序添加了几个额外的操作,因此它并不像合并排序那样快,正如人们所期望的那样。
尽管如此,MergeSort还没有被使用,因为它的时间复杂性最差,实际上HeapSort实现了相同的最坏情况界限并且也已经到位,并且没有取代MergeSort,尽管它还有其它针对quicksort的缺点。 MergeSort幸存的主要原因是因为它是迄今为止最快的稳定排序算法。有几个应用程序对于拥有稳定的排序算法至关重要。这就是MergeSort的优势。
稳定排序使得相等的项目保留原始相对顺序。例如,当您有两个键时,这非常有用,并且您希望先按第一个键排序,然后按第二个键排序,保留第一个键顺序。
HeapSort针对quicksort的问题在于它缓存效率低,因为你在数组中交换/比较元素彼此相距太远,而quicksort比较后续元素,这些元素更可能在缓存中相同时间。