快速排序的思想:
快速排序的基本思想是基于分治法的:在待排序表L[1…n]中任取一个元素pivot作为基准,通过一趟排序将待排序表划分为独立的两个部分L[1…k-1]和L[k+1…n],使得L[1…k-1]中的所有元素小于pivot,L[k+1…n]中的所有元素大于等于pivot,则pivot放在了其最终位置L[k]上,这个过程称为一次划分。然后分别递归地对两个子表重复上述过程,直至每部分都内只有一个元素或空为止,即所有元素放在了其最终位置上。
C++实现:
//定义一次划分的方法
int Partition(vector<int>& data, int left, int right) {
int pivot = data[left]; //把第一个元素定义为基准
while (left < right) { //循环跳出条件
while (left < right && pivot <= data[right]) --right;
data[left] = data[right]; //比基准小的移到左侧
while (left < right && pivot >= data[right]) ++left;
data[right] = data[left]; //比基准大的移到右侧
}
data[left] = pivot; //基准元素放到最终位置
return left; //返回存放最终基准的位置
}
//递归排序左右两子表
void QuickSort(vector<int>& data, int left, int right) {
if (left < right) { //递归跳出条件
int pivotpos = Partition(data, left, right);
QuickSort(data, left, pivotpos - 1); //依次对两个子表进行递归排序
QuickSort(data, pivotpos + 1, right);
}
}
时空复杂度及稳定性:
- 空间效率:由于快速排序是递归的,需要借助一个递归工作栈来保存每层递归调用的必要信息,其容量应与递归调用的最大深度一致。最好情况下为O( l o g 2 n log_2n log2n);最坏情况下,因为要进行n-1次递归调用,所以栈的深度为O(n);平均情况下,栈的深度为O( l o g 2 n log_2n log2n)。
- 时间效率:快速排序的运行时间与划分是否对称有关,快速排序的最坏情况发生在两个区域分别包含n-1个元素和0个元素时,这种最大程度的不对称性若发生在每层递归上,即对应于初始排序表基本有序或基本无序时,就得到最坏情况下的时间复杂度O( n 2 n^2 n2)。在最理想的状态下,即Partition()可能做到最平衡的划分,得到两个子问题的大小都不可能大于n/2,在这种情况下,快速排序的运行速度将大大提升,此时,时间复杂度为O( n l o g 2 n nlog_2n nlog2n)。好在快速排序平均情况下的运行时间与其最佳情况下的运行时间很接近,而不是接近其最坏情况。快速排序是所有内部排序算法中平均性能最优的排序算法
- 稳定性:不稳定