前奏
前奏:是一种交换式且高效的分治排序算法 简称:快速排序
快速的总体运行结构是:先排序一遍然后在进行回溯分治
快速排序是排序一次在回溯一次
课外 仅供参考
如果与一组8000个数据的数组排序的情况下 时间差不多4毫秒不到
如果与一组80000个数据的数组排序的情况下 时间差不多50毫秒不到
如果与一组800000个数据的数组排序的情况下 时间差不多180毫秒不到
如果与一组8000000个数据的数组排序的情况下 时间差不多1.5秒不到
如果与一组80000000个数据的数组排序的情况下 时间差不多13秒不到
注意
注意中的注意:如果是接近于有序的列表千万不要用快速排序递归的原因很容易出现栈溢出现象
快速排序右2种方法 提示:使用了回溯思想、每回溯一次就比较排序一次
左右指针交替法
思路
1: 创建一个中心轴,并创建2个指针一个是左指针一个是右指针如果是以最左边元素为中心轴,就要先移动右指针在移动左指针
2: 当2个指针没有相撞(相撞)并停止了移动说明这时候就要对该2指针的元素相互的交换,直到指针相撞,然后将中心轴值与当前任意指针(最好以左指针)索引位置元素进行交换
3: 然后使用递归将中轴值左边区域的索引元素进行分区排列左边分区排列结束后将当前中轴值右边区域的索引元素进行分区排列
4: 什么情况下退出递归,就是当左指针>=右指针 如果没这一步会出现栈溢出
图解
图解2![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b250fd2f1634d94315df782590a7aecb.gif)
注意
如以最左/右为中心轴 移动当前的指针一定要是刚相反的指针索引 如:中心轴(最左) 就一定要先移动右指针 在移动左指针
如果以左为中心轴,又先移动左指针到时候会出现排序后的元素还是乱序的,所以一定要小心谨慎
注意图解
中心索引与中轴值替换的时候先将中心索引赋值给中轴值索引上,然后在将中心索引赋值为中轴值元素
代码
//左右指针法
public static void quickSortTheLeftAndRight(int [] arrray,int left,int right){
//指定回溯的结束条件
if(left>=right){
return; //已经分组成唯一元素,无序排序及再次拆分
}
//指定当前中心值 已最左边的元素为中心值
int pivot=arrray[left];
//创建左右移动指针
int moveLeftPoint=left;
int moveRightPoint=right;
while(moveLeftPoint<moveRightPoint){
//先移动右指针
while(moveLeftPoint<moveRightPoint&&arrray[moveRightPoint]>=pivot){
moveRightPoint--;
}
//移动左指针
while(moveLeftPoint<moveRightPoint&&arrray[moveLeftPoint]<=pivot){
moveLeftPoint++;
}
if(moveLeftPoint<moveRightPoint){
//由于相互没有碰撞所以将2个对应的指针元素进行调换位置
int temp=arrray[moveLeftPoint];
arrray[moveLeftPoint]=arrray[moveRightPoint];
arrray[moveRightPoint]=temp;
}
}
//指针碰撞与中心元素进行交换元素
if(moveLeftPoint==moveRightPoint){
arrray[left]=arrray[moveLeftPoint];
arrray[moveLeftPoint]=pivot;
}
//本次排序后左边的moveLeftPoint-1的元素都比pivot小 右边的moveRightPoint+1的元素都不小于pivot
//进行分治回溯
quickSortTheLeftAndRight(arrray,left,moveLeftPoint-1);
quickSortTheLeftAndRight(arrray,moveRightPoint+1,right);
}
数据挖坑法
图解
思路
1: 以最左/右未中心轴
2: 如果以最左为中心轴 就一开始移动右指针
如果以最右为中心轴 就一开始移动右指针
3: 移动指针结束并且指针没有碰撞(相对)就将当前指针元素赋值到对方指针索引位置上
4: 当前左右指针相撞(相等) 将中心轴值赋值在当前左右指针相等的索引位置上
所以当前中轴值以左边都是小于中轴值的元素,右边都是大于等于中轴值的元素(这就是从小到大排序)
5: 然后使用递归将中轴值左边区域的索引元素进行分区排列
左边分区排列结束后将当前中轴值右边区域的索引元素进行分区排列
6: 什么情况下退出递归,就是当左指针>=右指针 如果没这一步会出现栈溢出
注意
如以最左/右为中心轴 移动当前的指针一定要是刚相反的指针索引 如:中心轴(最左) 就一定要先移动右指针 在移动左指针
如果以左为中心轴,又先移动左指针到时候会出现右边的一些索引元素会被覆盖,所以一定要小心谨慎
代码
//快速排序之数据挖坑法 版本3我以最左元素为中轴值
public static void quickSortPitFillDataVersion3(int []arr ,int left,int right){
//判断2个指针是否右指定区域可以排序,> 还是=取决于 是先移动左指针还是右指针 2个判断都不能少所以就是大于等于
if(left>=right)return; //没有指定区域可以分区比较排序
//定义一个中轴值变量(已最左元素)为中心轴值
int pivotValue=arr[left];
//创建2个移动左右指针
int moveLeftPoint=left;
int moveRightPoint=right;
//循环当前2个指针范围下的可以排序比较区域
while(moveLeftPoint<moveRightPoint){
//注意:由于是最左元素为中心轴值一开始一定要是先移动右指针,同理如果是最右为中心轴值 就要先移动左指针
//先移动右指针
while(moveLeftPoint<moveRightPoint&&arr[moveRightPoint]>=pivotValue){
//符合当前条件,将当前右指针往前移动一位以此类推
moveRightPoint--;
}
//将当前右指针的元素小于中轴值,就将右指针索引元素赋值给左指针索引上
if(moveLeftPoint<moveRightPoint){
arr[moveLeftPoint]=arr[moveRightPoint];
}
//移动左指针
while(moveLeftPoint<moveRightPoint&&arr[moveLeftPoint]<pivotValue){
//符合当前条件,将当前左指向后移动一位, 以此类推
moveLeftPoint++;
}
//将当前左指针元素大于等中轴值 赋值给当前右指针索引上
if(moveLeftPoint<moveRightPoint){
arr[moveRightPoint]=arr[moveLeftPoint];
}
}
//当2个指针相撞(索引相等)将中轴值元素赋值给当前索引上,这样中轴值左边区域都是小于中轴值的元素 右边区域都是大于等于中轴值元素 这是从小到大排列
if(moveLeftPoint==moveRightPoint){
arr[moveLeftPoint]=pivotValue;
}
//将当前中轴值左边区域进行分区排序
quickSortPitFillDataVersion3(arr,left,moveLeftPoint-1);
//将当前中轴值右边区域进行分区排序
quickSortPitFillDataVersion3(arr,moveRightPoint+1,right);
}
//快速排序值数据挖坑法 以最右元素为中轴值
public static void quickSortPitFillDataVersion4(int []arr ,int left,int right){
//判断当前是否有可比较排序区域,> 还是=取决于 是先移动左指针还是右指针 2个判断都不能少所以就是大于等于
if(left>=right)return;
//创建一个中轴值 以最右元素为中轴值
int pivoteValue=arr[right];
//创建2个可移动指针
int moveLeftPoint=left;
int moveRightPoint=right;
//循环当前可比较排序区域
while(moveLeftPoint<moveRightPoint){
//由于当前是最右元素为中心轴所有先移动 左指针
//移动左指针
while(moveLeftPoint<moveRightPoint&&arr[moveLeftPoint]<pivoteValue){
//指针想后移动一位 以此类推
moveLeftPoint++;
}
//将当前左指针元素赋值给右指针索引上
if(moveLeftPoint<moveRightPoint){
arr[moveRightPoint]=arr[moveLeftPoint];
}
//移动右指针
while(moveLeftPoint<moveRightPoint&&arr[moveRightPoint]>=pivoteValue){
//将当前右指针向前移动一位 依次类推
moveRightPoint--;
}
if(moveLeftPoint<moveRightPoint){
arr[moveLeftPoint]=arr[moveRightPoint];
}
}
//当前2个指针相撞(相等)
if(moveLeftPoint==moveRightPoint){
//将当前中轴值元素赋值给当前索引上
arr[moveRightPoint]=pivoteValue;
}
//指针当前中轴值元素索引左边区域进行分区排序
quickSortPitFillDataVersion4(arr,left,moveLeftPoint-1);
//指针当前中轴值元素索引右边区域进行分区排序
quickSortPitFillDataVersion4(arr,moveRightPoint+1,right);
}
//快速排序之挖坑填数法 中轴值为区域中的中心
public static void quickSortPitFillDataVersion5(int arr[],int left,int right){
//判断当前2个指针对应的区域是否可以执行排序分区,> 还是=取决于 是先移动左指针还是右指针 2个判断都不能少所以就是大于等于
if(left>=right) return;
//创建一个中轴值
int pivoteValue=arr[(left+right)/2];
//创建2个可移动指针
int moveLeftPoint=left;
int moveRightPoint=right;
int flag=true;
//循环当前区域的的指针信息
while(moveLeftPoint<moveRightPoint){
//这里默认先移动左指针,
while(moveLeftPoint<moveRightPoint&&arr[moveLeftPoint]<pivoteValue){
//符合条件将左指针往后移动一位
moveLeftPoint++;
}
if(moveLeftPoint<moveRightPoint){
if(flag){
//默认第一次是将左索引数据添加在中心值对应索引的位置上
arr[(left+right)/2]=arr[moveLeftPoint]
flag=false;
}else{
arr[moveRightPoint]=arr[moveLeftPoint];
}
}
//移动右指针
while(moveLeftPoint<moveRightPoint&&arr[moveRightPoint]>=pivoteValue){
moveRightPoint--;
}
if(moveLeftPoint<moveRightPoint){
arr[moveLeftPoint]=arr[moveRightPoint];
}
}
//当前2个指针相撞(相等)
if(moveLeftPoint==moveRightPoint){
//将当前中轴值元素赋值给当前索引上
arr[moveRightPoint]=pivoteValue;
}
//指针当前中轴值元素索引左边区域进行分区排序
quickSortPitFillDataVersion5(arr,left,moveLeftPoint-1);
//指针当前中轴值元素索引右边区域进行分区排序
quickSortPitFillDataVersion5(arr,moveRightPoint+1,right);
}
//数据挖坑法。。。
//注意:第一个先移动的指针用< > 、第二个用>= <=
//原因:因为有可能出现相同的数值,如果没有=比较2个指针无法移动导致死循环,而且位置如果第一个用>= <= 第二用 > < 也有会有问题小编也不清楚没有去仔细研究 如果有人知道可以评论下一起探讨 哈哈
public static void quikSortVersion3(int [] orderByArray,int left,int right){
if(right<left){return;}
//创建存储第一个中间索引和对应的值
int midIndex=(left+right)/2;
int midValue=orderByArray[midIndex];
//创建移动指针
int moveLeftPoint=left;
int moveRightPoint=right;
//移动当前2个指针
while(moveLeftPoint<moveRightPoint){
//先移动左指针
while(moveLeftPoint<moveRightPoint&&orderByArray[moveLeftPoint]<midValue){
moveLeftPoint++;
}
//将当前指针的索引元素存储到对应的midIndex中 并将当前的moveLeftPoint记录给midIndex中
if(moveLeftPoint<moveRightPoint){
orderByArray[midIndex]=orderByArray[moveLeftPoint];
midIndex=moveLeftPoint;
}
//移动右指针
while(moveLeftPoint<moveRightPoint&&orderByArray[moveRightPoint]>=midValue){
moveRightPoint--;
}
if(moveLeftPoint<moveRightPoint){
orderByArray[midIndex]=orderByArray[moveRightPoint];
midIndex=moveRightPoint;
}
}
//将当前midValue赋值给对应midIndex中
orderByArray[midIndex]=midValue;
quikSortVersion3(orderByArray,left,midIndex-1);
quikSortVersion3(orderByArray,midIndex+1,right);
}