快速排序和归并排序一样,都是应用了分治法的排序算法
一. 算法思想
划分:选定一个记录作为轴值,以轴值为基准将整个序列划分为两个子序列
r
1
r_1
r1…
r
i
−
1
r_{i-1}
ri−1和
r
i
+
1
r_{i+1}
ri+1…
r
n
r_n
rn,轴值的位置i在划分的过程中确定,并且前一个子序列中的记录都小于或等于轴值,后一个子序列中的记录都大于或等于轴值
求解子问题:分别对划分后的每一个子序列递归处理
合并:由于对子序列
r
1
r_1
r1…
r
i
−
1
r_{i-1}
ri−1和
r
i
+
1
r_{i+1}
ri+1…
r
n
r_n
rn的排序是就地进行的,所以合并不需要执行任何操作
二. 算法过程
- 首先对待排序记录序列进行划分,以第一个记录为轴值进行划分
- 以轴值为基准将排序序列划分为两个子序列后,对每一个子序列分别递归进行处理
三. 图例
一次划分的过程图例(红色代表轴值)
四. 算法实现
C++
int Partition(int r[], int first, int end)
{
int i = first, j = end;
while (i < j)
{
while (i < j && r[i] <= r[j]) j--;
if(i < j)
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
i++;
}
while (i < j && r[i] <= r[j]) i++;
if(i < j)
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
j--;
}
}
return i;
}
void QuickSort(int r[], int first, int end)
{
int pivot;
if (first < end)
{
pivot = Partition(r, first, end);
QuickSort(r, first, pivot - 1);
QuickSort(r, pivot + 1, end);
}
}
Java
public int partition(int r[], int first, int end) {
int i = first, j = end;
while (i < j)
{
while (i < j && r[i] <= r[j]) j--;
if(i < j)
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
i++;
}
while (i < j && r[i] <= r[j]) i++;
if(i < j)
{
int temp = r[i];
r[i] = r[j];
r[j] = temp;
j--;
}
}
return i;
}
public void quickSort(int r[], int first, int end) {
int pivot;
if (first < end)
{
pivot = partition(r, first, end);
quickSort(r, first, pivot - 1);
quickSort(r, pivot + 1, end);
}
}
五. 算法分析
- 时间复杂度:最好情况下的时间为 O ( n ) O(n) O(n),最坏情况下的时间为 O ( n 2 ) O(n^2) O(n2),所以平均时间复杂度为 O ( n l o g 2 n ) O(nlog_2{n}) O(nlog2n)
- 空间复杂度:最好情况下要进行 l o g 2 n log_2{n} log2n次递归调用,栈的深度为 O ( l o g 2 n ) O(log_2{n}) O(log2n);最坏情况下要进行 n − 1 n-1 n−1次递归调用,栈深度为 O ( n ) O(n) O(n),平均情况下,栈深度为 O ( l o g 2 n ) O(log_2{n}) O(log2n)
- 稳定性:快速排序在合并过程中,相同元素的前后顺序发生改变,所以快速排序是一种不稳定排序算法