考虑两个k位数字(二进制表示):
$$A = A_1 A_2 A_3 A_4 ... A_k $$
$$B = B_1 B_2 B_3 B_4 ... B_k $$
比较我们从左向右扫描寻找0
的出现并检查相反的数字,如果该数字也是0
(两个数字),注意到如果这样的情况是然后发现0
的来源小于1
的来源。但如果数字是:
111111111111
111111111110
显然,这需要扫描整个数字,如果我们没有提前告知数字,那么只需给出它们:
比较花费$O(k)$
时间。
因此,当我们查看排序方法的代码时,例如高性能快速排序:
HPQuicksort(list): T(n)
check if list is sorted: if so return list
compute median: O(n) time (or technically: O(nk))
Create empty list $L_1$, $L_2$, and $L_3$ O(1) time
Scan through list O(n)
if element is less place into $L_1$ O(k)
if element is more place into $L_2$ O(k)
if element is equal place into $L_3$ O(k)
return concatenation of HP sorted $L_1$, $L_3$, $L_2$ 2 T(n/2)
因此:T(n) = O(n) + O(nk) + 2*T(n/2) ---> T(n) = O(nklog(n))
这意味着快速排序比基数排序慢。
为什么我们仍然使用它?
答案 0 :(得分:2)
这里似乎有两个独立的问题:
为什么我们声称在分析排序算法时比较花费时间O(1),实际上它们可能不会?
为什么我们会在大整数上使用quicksort而不是基数排序?
对于(1),通常,排序算法的运行时分析是根据所进行的比较的数量而不是根据所执行的操作的总数来测量的。例如,着名的排序下限在比较次数方面给出了下限,并且快速排序,堆垛,选择排序等的分析都通过计数比较来起作用。出于几个原因,这很有用。首先,通常,排序算法将通过给定一个数组和一些用于比较它们的比较函数来实现(例如,C的qsort
或Java的Arrays.sort
)。从排序算法的角度来看,这是一个黑盒子。因此,通过尝试最小化对黑盒子的调用次数来分析算法是有意义的。其次,如果我们通过计算比较来执行对排序算法的分析,则可以通过将比较数乘以比较成本来确定总体运行时间。例如,您正确地确定了使用快速排序对n个k位整数进行排序将花费预期时间O(kn log n),因为您可以将比较次数乘以比较的成本。
对于你的第二个问题 - 我们为什么要在大整数上使用快速排序而不是基数排序? - 通常,您实际上会在此上下文中使用基数排序,而不是快速排序,因为您指出了特定的原因。 Quicksort是一个很好的排序算法,用于排序可以相互比较的对象,并且具有出色的性能,但基数排序在大型字符串或整数的大型数组上经常优于它。
希望这有帮助!