注:该篇文章已与我的个人博客同步更新。欢迎移步https://cqh-i.github.io/体验更好的阅读效果。
快速排序的思想
快速排序通过将一个数组划分成两个子数组, 然后通过递归调用自身为每一个子数组进行快速排序来实现.
如何进行划分
设定关键字(基准数), 将比关键字小的放在一组, 比关键字大的放在另一组.
下面将以数组[6,1,2,7,9,3,4,5,10,8]为例, 演示排序过程
步骤
- 先把数组中的一个数当做基准数, 一般会把数组中最左边的数当做基准数, 然后从两边进行检索. 先从数组的右边检索比基准数小的, 再从左边检索比基准数大的. 如果检索到了, 就停下, 然后交换这两个元素, 然后再继续检索.
- i和j一旦相遇, 就停止检索, 把基准数和相遇位置的元素交换
- 基准数和相遇位置的元素交换完成后, 表示第一轮排序结束, 此时数组的特点: 基准数左边的元素都比它小, 右边的元素都比它大.
- 接下来, 先排基准数左边的数组, 排完之后再排基准数右边的数组, 方式和第一轮一样, 整个过程如下图
时间复杂度
最坏:O(n^2)
平均: O(nlogn)
稳定性
不稳定, 比如序列为 (5, 3, 3, 4, 3, 8, 9, 10, 11), 第一轮中, 基准数5和第5位置的3交换, 就会破坏稳定性
Java版代码
public class QuickSort {
/**
* @Description: 快速排序
* @param arr 待排序的数组
* @param left 从什么位置开始排序
* @param right 排到哪个位置
* @return: void
*/
public static void quickSort(int[] arr, int left, int right) {
// 数组合法性检测, 递归出口
if (left > right)
return;
// 定义基准数
int base = arr[left];
// 定义变量i, 指向最左边
int i = left;
// 定义变量j, 指向最右边
int j = right;
// 当i和j不相遇的时候, 在循环中检索
while (i != j) {
// 向量j从右往左检索比基准数小的, 如果检索到比基准数小的, 就停下.
while (arr[j] >= base && i < j) {
j--; // j从右往左移动
}
// i 从左往右检索
while (arr[i] <= base && i < j) {
i++; // i 从左往右移动
}
// i停下了, j也停下, 交换两个位置的元素
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 如果i和j相遇了, 就交换基准数和相遇位置的元素
arr[left] = arr[i];
arr[i] = base;
// 基准数在这里就归位了, 左边的数字都比它小, 右边的数字都比它大.
// 排基准数左边的数组
quickSort(arr, left, i - 1);
// 排基准数右边的数组
quickSort(arr, j + 1, right);
}
public static void main(String[] args) {
int[] arr = new int[] { 6, 1, 2, 7, 9, 3, 4, 5, 10, 8 };
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
}
C语言版
int Partition(int L[], int low, int high)//对子表进行一趟排序,返回枢轴位置
{//L[0]闲置或用作哨兵单元
L[0] = L[low];
int pivotkey = L[low];
while(low < high)
{
while(low < high && L[high] >= pivotkey) --high;
L[low] = L[high];
while(low < high && L[low] <= pivotkey) ++low;
L[high] = L[low];
}
L[low] = L[0];
return low;
}
void Qsort(int L[], int low, int high)
{//L[0]闲置,调用前置初值 low = 1, high = L的length;
if(low < high)
{
int pivotloc = Partition(L, low ,high);//pivotloc是枢轴位置
Qsort(L, low, pivotloc - 1);
Qsort(L, pivotloc + 1, high);
}
}
如果L[0]上面有数字(不闲置),稍微改动一下就可以了
int Patition(int L[], int low, int high)
{
int temp = L[low];
while(low < high)
{
int pivotkey = L[low];
while(low < high && L[high] >= pivotkey)high--;
L[low] = L[high];
while(low < high && L[low] <= pivotkey)low++;
L[high] = L[low];
}
L[low] = temp;
return low;
}
void Qsort(int L[], int low, int high)
{//调用前置low = 0, high = L.length - 1
if(low < high)
{
int pivotloc = Patition(L, low, high);
Qsort(L, low, pivotloc - 1);
Qsort(L, pivotloc + 1, high);
}
}