原理:
快速排序的本质就是把基准数大的都放在基准数的右边, 把比基准数小的放在基准数的左边,这样就找到了该数据在数组中的正确位置时间复杂度:
最好的情况是O(N*logN)
最坏的情况是O(N2),最左边或者最右边是边缘的数,即最大(1,2,3,4,5)或者最小(5,4,3,2,1)的, 因为每次分成两个区间时,只能确定一个数的位置
避免出现O(N2)
为了避免已经排好序的这种情况,可以随机取一个位置的数与数组最后一个数做交换在来排序下面是选取左边的数为基准数排序,然后递归
package leetcode.editor.cn;
import java.util.Arrays;
/**
* @description: 快速排序:
* 1.会先把数组中一个数当做基准数,一般把数组中最左边的数当做基准数,然后两边进行检索。
* 2.先从右边(j)检索比基准数小的,检索到了停下来,
* 3.再从左边(i)检索比基准数大的,检索到了停下来,
* 4.然后交换刚刚两个位置(j和i)的元素,
* 5.然后继续检索,如果i和j相遇了,把基准数放到i位置上面,基准数前面的数组都比它小,后面的数组都比它大,第一轮排序完成
* 6.在排基准数左的数组和右边的数组
*
* 时间复杂度:每一层的比较与交换是O(n),一共能分O(logN),时间复杂度为O(N*logN)
* 最坏的情况是已经排好序了,时间复杂度为O(N2),解决办法:可以随机取一个位置的数与数组最后一个数做交换在来排序
* 空间复杂读:logN
* @author: xt
* @create: 2022-04-03 23:47
**/
public class QuickSort2 {
public static void main(String[] args) {
int[] arr = {10,6, 8, 7, 4, 2, 6, 9, 3, 5};
sort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
static void sort(int[] arr, int left,int right){
//进行判断,左边的数组范围要小于右边
if(left>right){
return;
}
//定义基准数,默认以左边的数
int tmp=arr[left];
//i指向这个范围数组的最左边
int i=left;
//j指向这个范围数组的最右边
int j=right;
//当i和j不相遇的时候,进行检索
while(i!=j){
//因为是以左边为基准,所以先移动右边
//先从右往左检索,如果检索到比基准数小的,就停下,
// 如果检索到比基准数大或者等于的,就一直往右移动
//但 i不能大于j,如果大于
while(i<j && arr[j]>=tmp){
j--;
}
//先从左往右检索,如果检索到比基准数大的,就停下,
// 如果检索到比基准数小或者等于的,就一直往左移动
while(i<j && arr[i]<=tmp){
i++;
}
//i和j都停下了,交换对应的元素
swap(arr,i,j);
}
//但i和j相遇了,就交换基准数和相遇位置的元素
arr[left]=arr[i];
arr[i]=tmp;
//对基准数前面的元素进行排序
sort(arr, left,i-1);
//对基准数后面的元素进行排序
sort(arr, j+1,right);
}
static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
下面是选取右边的数,分治的思想
import java.util.Arrays;
/**
* @description: 快速排序
* @author: xt
* @create: 2021-04-04 20:05
**/
public class QuickSort {
public static void main(String[] args) {
int[] arr={1, 8, 7, 4, 2, 6, 9, 3, 5};
sort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
static void sort(int[] arr ,int leftBound ,int rightBound){
if(rightBound<=leftBound){
return;
}
int mid=partition(arr,leftBound,rightBound);
sort(arr,leftBound,mid-1);
sort(arr,mid+1,rightBound);
};
static int partition(int[] arr ,int leftBound ,int rightBound){
int pivot=arr[rightBound];
int right=rightBound-1;
int left=leftBound;
while(left<=right){
//为了防止最右边的数据是最大,一直加超过数组长度报错,加上left<=right
while (left<=right&&arr[left]<=pivot){
left++;
};
//为了防止最右边的数据是最小,一直减为-1报错,加上left<=right
while (left<=right&&arr[right]>=pivot){
right--;
}
if(left<right){
//左右指针还没有重合,把比基准数大的值,与比基准数小的值换个位置
//[1, 3, 7, 4, 2, 6, 9, 8, 5]
//[1, 3, 2, 4, 7, 6, 9, 8, 5]
swap(arr,left,right);
}
}
//经过一次比较,把基准数的left上,这样基准数右边的都是比基准数小的,左边都是大的
swap(arr,left,rightBound);
//第一次交换后,可以确定5的位置
//[1, 3, 2, 4, 5, 6, 9, 8, 7]
return left;
};
static void swap(int[] arr ,int i,int j){
int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
}