刚刚学习了排序这一章,看到了书中最后的一个总结表:
心想从表上来看,堆排序不该是最好的排序算法么?不管最好、最坏还是平均情况,时间复杂度都是O(nlogn),而且还不像快排和归并排序那样占空间,为什么说快速排序是最好的算法呢?
其实经过实验,会发现相同的数据规模,快速排序比堆排序的效率高很多,并且随着数据规模的扩大,二者的差距不断扩大,快速排序的优势越来越明显。快速排序的时间复杂度近似线性增长,堆排序则要大很多。究其原因,应该有以下几个方面:
在堆排序(小根堆)的时候,每次总是将最小的元素移除,然后将最后的元素放到堆顶,再让其自我调整。这样一来,有很多比较将是被浪费的,因为被拿到堆顶的那个元素几乎肯定是很大的,而靠近堆顶的元素又几乎肯定是很小的,最后一个元素能留在堆顶的可能性微乎其微,最后一个元素很有可能最终再被移动到底部。在堆排序里面有大量这种近乎无效的比较。随着数据规模的增长,比较的开销最差情况应该在(线性*对数)级别,如果数据量是原来的10倍,那么用于比较的时间开销可能是原来的10log10倍。
堆排序的过程中,需要有效的随机存取。比较父节点和字节点的值大小的时候,虽然计算下标会很快完成,但是在大规模的数据中对数组指针寻址也需要一定的时间。而快速排序只需要将数组指针移动到相邻的区域即可。在堆排序中,会大量的随机存取数据;而在快速排序中,只会大量的顺序存取数据。随着数据规模的扩大,这方面的差距会明显增大。在这方面的时间开销来说,快速排序只会线性增长,而堆排序增加幅度很大,会远远大于线性。
在快速排序中,每次数据移动都意味着该数据距离它正确的位置越来越近,而在堆排序中,类似将堆尾部的数据移到堆顶这样的操作只会使相应的数据远离它正确的位置,后续必然有一些操作再将其移动,即“做了好多无用功”。
就像标准库中的sort,是通过 先快排,递归深度超过一个阀值就改成堆排,然后对最后的几个进行插入排序来实现的。
--------------------------------------------------------
</article>