快速排序
1 基本原理
核心思想:快速排序是一种 划分交换排序 ,其采用分治的策略思想 。
算法思路:
1. 首先从待排序序列中随机取出一个数作为基准数。
2. 分区过程,将比基准数大的数全放到它的右边,小于或等于基准数的数全放到它的左边。
3. 对左右区间重复第二步,直到各区间只有一个数。
2 实例说明
如上图所示,参考《算法导论》中给出的示例,对快速排序进行算法演示,待排序序列为A[2,8,7,1,3,5,6,4]:
- 第一轮:将数组A分为两个子数组,左数组中数均小于等于基准数,右数组中数均大于基准数。具体步骤如下:
1. 数组中选择一数为基准数,此处选择尾数4为基准数(建议随机选择)
2. 选择参数 i, j来决定两个子数组如何划分。
3. 从数组第一位开始,依次与基准数进行比较,若小于等于4,i与j均右移一位,反之i不动,j右移一位。如此A[0,i]均小于等于4,A[i+1,j]均大于4。
4. 参考图例,a)中,2<4,i和j均右移一位;b)8>4,i不变,j右移;到了h),A[0,i]均小于等于4,A[i+1,j]均大于4。
5. 将基准数4交换至正确的位置,原数组被划分为左数组和右数组。 - 第二轮:分别对左右子数组重复第一轮操作,直到各数组只剩一个元素。
3 代码实现
// 快速排序(C++)
void swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int partition(vector<int> &vi, int low, int up)//划分数组,并返回基准数在数组中位置
{
int pivot = vi[up];
int i = low - 1;
for (int j = low; j < up; j++)
{
if (vi[j] <= pivot)
{
i++;
swap(vi[i], vi[j]);
}
}
swap(vi[i + 1], vi[up]);
return i + 1;
}
void quickSort(vector<int> &vi, int low, int up)
{
if (low < up)
{
int mid = partition(vi, low, up);
quickSort(vi, low, mid - 1);
quickSort(vi, mid + 1, up);
}
}
4 性能分析
- 1 时间复杂度:
快速排序的时间性能取决于快速排序递归的深度,递归过程中,子序列越平衡,则性能越好
(1)最优情况下时,递归过程形成的递归树是一课平衡树,快速排序算法的时间复杂度为O(nlogn)。
(2)最坏情况下时,递归过程形成的递归树是一课斜树,快速排序算法的时间复杂度为O(n2)。
(3)平均情况下,时间复杂度为O(nlogn)。 - 2 空间复杂度:
就空间复杂度来说,主要是递归造成的栈空间的使用。
(1)最好情况,递归树的深度为log2n,其空间复杂度也就为O(logn)。
(2)最坏情况,需要进行n‐1递归调用,其空间复杂度为O(n)。
(3)平均情况,空间复杂度也为O(logn)。 - 3 算法稳定性:
快速排序在排序过程中,由于基准数的比较和交换是跳跃进行的,因此,快速排序是一种不稳定的排序算法。