快速排序:是对冒泡排序的一种改进。
先说下快排的一个基本思想:
使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。
就是通过一躺排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一不部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
大喊一声,nb!
一个图:看懂很容易,想出来是真不简单

时间复杂度:
| 最坏时间复杂度 | |
|---|---|
| 最优时间复杂度 | |
| 平均时间复杂度 |
代码实现:
排序的算法:
/**
* 快速排序算法
*
* @param arr 待排序的数组
* @param low 排序数组的起始位置
* @param hight 排序的结束位置
*/
public static void quickSortV1(int[] arr, int low, int hight) {
if (low < hight) {
// 算出枢轴值
int pivot = partitionV1(arr, low, hight);
// 对小的数组进行递归排序
quickSortV1(arr, low, pivot - 1);
// 对大的数组进行递归排序
quickSortV1(arr, pivot + 1, hight);
}
}
// 简单的数组元素位置交换
private static void swap(int[] arr, int low, int hight) {
int t = arr[low];
arr[low] = arr[hight];
arr[hight] = t;
}
排序的关键算法:
/**
* 快速排序算法关键算法
*
* @param arr 排序的数组
* @param low 低位的下标
* @param hight 高位的下标
* @return 枢轴的下标索引
*/
private static int partitionV1(int[] arr, int low, int hight) {
// 枢轴(就是一个基数而以)
int pivotkey = arr[low];
while (low < hight) {
// 找到不比枢轴元素大的元素位置
while (low < hight && arr[hight] >= pivotkey) {
hight--;
}
// 交换元素位置,使得比枢轴大的元素位置都在右边
swap(arr, low, hight);
// 找到不比枢轴元素小的元素位置
while (low < hight && arr[low] <= pivotkey) {
low++;
}
// 交换元素位置,使得比枢轴小的元素位置都在左边
swap(arr, low, hight);
}
// 返回枢轴元素的下标位置。
return low;
}
对上面代码进行优化:
优化后的排序算法:
public static void quickSortV2(int[] arr, int low, int hight) {
int pivot;
// 在调用的函数递归的时候,这个low和hight是在动态的变化的
// 也就是说会出现,第一次插入排序完了之后,low和hight的值会变化,排序的长度小于这个数组阀值的话会进行快速排序。
// 所以,在数据个数并不是很多的情况下,就直接用quickSortV1 + partitionV2的实现就行了,加上还得额外判断,反而慢了
if ((hight - low) >= MAX_ARRAY_LENGTH) {
while (low < hight) {
// 算出枢轴值
pivot = partitionV2(arr, low, hight);
/*
* 如果待排序的序列划分的极端不平衡,递归的深度将趋近于n.
* 递归会耗费一定的栈空间,参数越多,耗费的空间也就越多.
* 通过减少递归,缩减堆栈的深度的,来提升整体性能.
*/
// 对小的数组进行递归排序
quickSortV2(arr, low, pivot - 1);
// 尾递归
low = pivot + 1;
}
} else {
// 当数组(元素个数)很小的时候,快速排序反而不如插入排序了。
// 这里得加1,因为参数2是待排序序列的结束下标位置 + 1
InsertSort.binInsertSort(arr, low, hight + 1);
}
}
优化后的快排关键算法:
/**
* partitionV1()的改进,优化不必要的交换
*
* @param arr 待排序的数组
* @param low 低位是下标索引
* @param hight 高位的下标索引
* @return 枢轴的下标位置
*/
private static int partitionV2(int[] arr, int low, int hight) {
// -------枢轴选取的改进,使用3数取中。-----------------
int mid = (low + hight) >>> 1;
// 保证左边元素为小的
if (arr[low] > arr[hight]) {
swap(arr, low, hight);
}
// 保证右边元素为大
if (arr[mid] > arr[hight]) {
swap(arr, mid, hight);
}
// 保证low为中间值下标
if (arr[mid] > arr[low]) {
swap(arr, mid, low);
}
// ---------------------------------------------
// 枢轴(就是一个基数而以)
int pivotkey = arr[low];
while (low < hight) {
// 找到不比枢轴元素大的元素位置
while (low < hight && arr[hight] >= pivotkey) {
hight--;
}
// 替换元素,使得比枢轴大的元素位置都在右边
arr[low] = arr[hight];
// 找到不比枢轴元素小的元素位置
while (low < hight && arr[low] <= pivotkey) {
low++;
}
// 替换元素,使得比枢轴小的元素位置都在左边
arr[hight] = arr[low];
}
arr[low] = pivotkey;
// 返回枢轴元素的下标位置。
return low;
}
本文介绍了快速排序的基本思想,使用分治法将序列分为两部分并递归排序。内容包括快排的直观理解、时间复杂度分析及Java代码实现,通过逐步优化展示排序过程。
&spm=1001.2101.3001.5002&articleId=89713896&d=1&t=3&u=b2930568368044e9887ad49f1779400c)
1万+

被折叠的 条评论
为什么被折叠?



