排序方法 | 平均情况 | 最好情况 | 最坏情况 | 空间 | 稳定性 |
---|---|---|---|---|---|
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2). | O(n^2) | O(1) | 不稳定 |
插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(nlogn)~O(n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 稳定 |
快速排序 | O(n^2) | O(nlogn) | O(n^2) | O(1) | 不稳定 |
快速排序和堆排序:
堆排序每次取一个最大值的时候,会把堆底部的X提上来,然后重新调整成一个堆。而X有很大可能是依旧调整到堆的底部(堆的底部X显然是比较小的数,才会在底部),然后再次和堆顶最大值交换,再调整下来,可以说堆排序做了许多无用功。
总结起来就是,快排的最坏时间虽然复杂度高,但是在统计意义上,这种数据出现的概率极小,而堆排序过程里的交换跟快排过程里的交换虽然都是常量时间,但是常量时间差很多。
选择排序改进:
void qSort(int *data, int begin, int end){
int pivot, i, j;
if(begin>=end)
return;
i = begin;
j = end;
pivot = data[i];
while(i<j){
while(i<j && data[j]>=pivot)
j--;
data[i] = data[j];
while(i<j && data[i]<=pivot)
i++;
data[j] = data[i];
}
data[i] = pivot;
qSort(data, begin, i-1);
qSort(data, i+1, end);
}
1.对于大规模数据来说,前期采用的快速排序已经将一些元素放到了正确的位置上,因此当规模降低到一定程度时,可以认为一些元素已经基本有序了。对基本有序的序列进行排序,插入排序是最好的选择,不光比较次数少,还免去了递归调用的过程。
2.中轴元素的选取。如果简单的只是选择第一个或最后一个作为中轴元素,这样当待排序序列基本有序的时候,它就退化为O(n^2)的时间复杂度。因此,第二中改进方法为:
可以取最左边、最右边、中间这三个位置的元素中的中间值作为中轴元素,来避免这种情况。