目录
本文主要是对快速排序的进行说明,以及快速排序的一种优化方式
交换排序
1.冒泡排序
核心思想:相邻两个元素比较,如果前面 > 后面,就交换;每一轮把最大的元素 "冒泡" 到数组末尾,加上 flag 优化可以提前结束。
示例数组:
[3, 1, 4, 2]目标:排成
[1, 2, 3, 4]
冒泡排序的特性总结:
冒泡排序是一种非常容易理解的排序
时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:稳定
冒泡排序的步骤:
获取数组长度 n;
- 外层循环
i从 0 到n-2:- 初始化标记
flag = false(标记本轮是否交换)- 内层循环
j从 0 到n-1-i-1:- 如果
array[j] > array[j+1](升序):交换两个元素,设置flag=true- 一轮内层结束后:
- 如果
flag == false:本轮没有交换,数组已有序,break 跳出外层循环- 循环结束,排序完成。
代码示例:
java
/**
* 冒泡排序
* 时间复杂度:O(N^2)
* 空间复杂度:O(1)
* 稳定性:稳定
* @param array
*/
public static void bubbleSort(int[] array){
for(int i = 0; i < array.length - 1; i++){
boolean flag = false;
for(int j = 0; j < array.length -1-i;j++){
if(array[j] > array[j+1]){
swap(array,j,j+1);
flag = true;
}
}
if(!flag){
break;
}
}
}
2.快速排序
快速排序的特性总结:
- 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
- 时间复杂度:O(N*logN)
- 空间复杂度:O(logN)
- 稳定性:不稳定
1.快速排序>>霍尔版
Hoare 是快排原始版本,挖坑法、Lomuto 前后指针不一样。 核心思路:
- 选一个基准(一般选最左 / 最右)
- 左指针从左往右找大于基准 的;右指针从右往左找小于基准的
- 找到之后交换两个指针的值
- 直到左右指针相遇,相遇点就是划分边界,递归左右两个区间
图例:

代码示例:
java
public static void quickSort(int[] array){
quick(array,0,array.length - 1);
}
private static void quick(int[] array,int start,int end){
if(start >= end){
return;
}
int pivot = partitionHoare(array,start,end);
quick(array,start,pivot-1);
quick(array,pivot+1,end);
}
//快速排序>>霍尔法
private static int partitionHoare(int[] array, int left, int right) {
int temp = array[left];
int templeft = left;
while(left < right){
while(left < right && array[right] >= temp){
right--;
}
while(left < right && array[left] <= temp){
left++;
}
swap(array,left,right);
}
swap(array,left,templeft);
return left;
}
2.快速排序>>挖坑法
核心思想:先把基准挖出来,形成一个坑;右指针找比基准小的填到坑里,右指针位置变成新坑;左指针找比基准大的填到新坑,循环直到左右相遇,最后把基准放进这个坑。
特点:基准最后落在相遇位置,返回的 pivot 就是基准的最终下标
递归:
quick(l, pivot-1)和quick(pivot+1, r)(和 Lomuto 一样,和 Hoare 霍尔不一样!)
图例:

代码示例:
java
public static void quickSort(int[] array){
quick(array,0,array.length - 1);
}
private static void quick(int[] array,int start,int end){
if(start >= end){
return;
}
int pivot = partitionDighole(array,start,end);
quick(array,start,pivot-1);
quick(array,pivot+1,end);
}
//快速排序>>挖坑法
private static int partitionDighole(int[] array, int left, int right) {
int temp = array[left];
while(left < right){
while(left < right && array[right] >= temp){
right--;
}
array[left] = array[right];
while(left < right && array[left] <= temp){
left++;
}
array[right] = array[left];
}
array[left] = temp;
return left;
}
3.快速排序>>前后指针法
核心思想:用两个指针,
prev(慢指针,小于基准区域的最后一个位置)、cur(快指针,遍历扫描) 基准一般选最左边元素;cur 不断向后走,遇到比基准小的数,prev 先 ++,再交换 cur 和 prev; 遍历完之后,把基准和 prev 位置交换,prev 就是基准最终下标递归写法:
quick(l, pivot-1)、quick(pivot+1, r),和挖坑法一致,和 Hoare 霍尔不一样
图例:

代码示例:
java
public static void quickSort(int[] array){
quick(array,0,array.length - 1);
}
private static void quick(int[] array,int start,int end){
if(start >= end){
return;
}
int pivot =partitionFbpointer(array,start,end);
quick(array,start,pivot-1);
quick(array,pivot+1,end);
}
//快速排序>>前后指针法
private static int partitionFbpointer(int[] array, int left, int right) {
int prev = left;
int cur = left + 1;
while(cur <= right){
if(array[cur] < array[left] && array[++prev] != array[cur]){
swap(array,cur,prev);
}
cur++;
}
swap(array,prev,left);
return prev;
}
3.快速排序的优化
在快速排序中,我们的理想的状态是将数据分成一个完全二叉树,而不是一个单列二叉树,这样的效率会大大折扣,所以我们会对快速排序进行一定的优化。
我们找到一组数据的第一元素和最后一个数据,利用这两个数据的下标来求中间值的下标,将这三个数中间大的数作为基准值。
代码示例:
java
public static void quickSort(int[] array){
quick(array,0,array.length - 1);
}
private static void quick(int[] array,int start,int end){
if(start >= end){
return;
}
int midlleIndex = getMidlle(array,start,end);
swap(array,start,midlleIndex);
int pivot = partitionHoare(array,start,end);
quick(array,start,pivot-1);
quick(array,pivot+1,end);
}
//三数取中法
public static int getMidlle(int[] array,int left,int right){
int mid = (left + right)/2;
if(array[left] < array[right]){
if(array[mid] < array[left]){
return left;
}else if(array[mid] > array[right]){
return right;
}else{
return mid;
}
}else{
if(array[mid] > array[left]){
return left;
}else if(array[right] > array[mid]){
return right;
}else{
return mid;
}
}
对于上面多种快速排序的写法,其中挖坑法考的最多,所以挖坑法一定要学会,其他作为理解,但是不能不会