1.快排的基本原理:
第一步,完成相对一个数的有序
声明一个变量i
总共就有三种情况:
(1)arr[i]<num,arr[i]与<区域的右边的第一个数做交换,小于等于区域向右移动,i++
(2)arr[i]==num,小于num区域不移动,i++
(3)arr[i]>num,arr[i]与>区域左边第一个数做交换,大于等于向左移动,注意:i大小此时没有发生变化
循环以上过程,则可以达到这样的结果
数组经过这样的排序以后就完成相对一个数的有序【这里的排序只是指把小于num的数放左边,等于num的数放中间,大于num的数放右边,而在小于num的数的范围里并没有固定的次序,大于也一样】
而此时再将数组小于num的部分和大于num的部分分别递归就可以完成全部排序。
举例:
当num = 5的时候:
注意:只有a[i]<=num的时候,i++
最终就可以完成小于num的数在左边,等于num的数在中间,大于num的数在右边
2.现在的快排算法
再使用上面的递归算法之后,以前的快排算法是将整个数组的最后一位作为整个数组的num,再执行上面的递归算法。因为数组顺序的不确定性,当数组处于最坏的情况时,即从大到小的情况时【目前介绍的是从小到大排序,总之就是你需要排的顺序不一样】比如:5,4,3,2,1,此时选最后一个数的时间复杂度为O(N^2)。为了避免这种情况,最新的排序算法选择num采用了随机的方式,即在数组长度范围内随机生成一个i,交换a[i]和数组最后一位,然后再将最后一位作为num【即将a[i]的值当作num】
下面是举例代码:
import java.util.Scanner;
public class HeNanGuoQiWenTi{
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] a = new int[5];
for(int i=0;i<a.length;i++) {
a[i] = scanner.nextInt();
}
//输入5个数作为举例数组
quickSort(a,0,a.length-1);//L和R分别为数组的左边界和右边界
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
public static void quickSort(int[] a,int L,int R) {
if(L<R) {
swap(a,L+(int)(Math.random()*(R-L+1)) , R);//随机生成一个数i,假定这个随机数值为a[i],使得a[i]与数组的最后一位数做交换
int[] p = progress(a, L, R);
//返回的这个p数组即为相同的a[i]在经过排列后,相同a[i]所占的下标a[p[0]]=a[p[1]=...=a[p[p.length-1]]
quickSort(a,L,p[0]-1);//小于a[i]部分继续递归
quickSort(a, p[1]+1, R);//大于a[i]部分继续递归
}
}
private static int[] swap(int[] arr,int i,int j) {//交换值
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
return arr;
}
public static int[] progress(int[] a,int L,int R) {
int less = L-1;
int more = R;
//因为swap(a,L+(int)(Math.random()*(R-L+1)) , R);意思就是交换a[i]和a[R],就是说数组中最后一位就为上面的num,所以说大于区域是从R开始,而不是R+1开始
while (L<more) {//当L==more时候,刚好将需要的部分遍历完
if(a[L]<a[R]) {
swap(a, ++less, L++);
} else if(a[L]>a[R]) {
swap(a, --more, L);
}else {
L++;
}
}
swap(a, more, R);
return new int[] {less+1,more};
/*当相同的数只有一个时,less+1和more【less+1和more均为数组a的下标】是相等的,当相同的数有两个时,a[less+1]==a[more],
返回的两个下标刚好也是这两个相同的数的下标,最重要的是,无论你是什么数组,经过progress方法以后,返回的这两个数刚好就是排好序后中间那段相同的数的下标
*/
}
}