1、概述
快速排序算法中,采用分治思想,每次调用partition函数对当前规模的数组进行处理,如何处理呢:
(1)选择一个主元素,何为主元素,可以理解为电视中主角,此主角在这次调用partition(arr,left,right)后将会找到它的最终位置,使得它的左侧数据都比不大于它,右侧元素都不小于它(由此可知,此快速排序算法是原址排序,直接在原数组中进行排序),同时这个方法将会这个主元的下标位置k。
(2)然后循环调用partition(arr,left,k-1)和partition(arr,k+1,right),对下标k的左右两侧的数组分而治之。
(3)当分治到每个数组都是单个元素的时候,分治结束,因为是原址排序,整个数组已经排序结束,所以此算法也结束。
一般快速排序和快速排序的随机化版本基本相同,只是在partition方法中,选择主元的策略不同,一般快速排序选择最后一个元素作为主元;快速排序的随机化版本随机选择数组中的一个元素作为主元。
2、一般快速排序
import java.util.*;
public class Main {
public static void main(String[] args) {
int [] arr = {8,0,2,5,7,4,3};
quick_sort(arr,0,arr.length-1);
for(Integer fac : arr){
System.out.print(fac+" ");
}
}
static void quick_sort(int [] arr,int left,int right){
if(left < right){
int index = partition(arr,left,right);
quick_sort(arr,left,index -1);
quick_sort(arr,index+1,right);
}
}
static int partition(int [] arr,int left,int right){
// 接下来通过多次比较和交换,找到主元的位置,
//并把主元放到最终的位置,同时返回主要最终位置的下标
int leftIndex = left - 1;
int mainFactor = arr[right];
// 下标为right的不参与比较,j上界为right-1
for(int j = left; j <= right - 1;j++){
if(arr[j] < mainFactor){
// leftIndex标定的元素是目前所知的比主元小的最右面的元素
leftIndex++;
swap(arr,leftIndex,j);
}
}
// 下面这个交换是把主元放到最终的位置
swap(arr,leftIndex+1,right);
return leftIndex+1;
}
// 交换数组arr中下标为left和right位置的元素
static void swap(int [] arr,int left,int right){
int tem = arr[left];
arr[left] = arr[right];
arr[right] = tem;
}
}
结果:
3、速排序的随机化版本(哪里体现随机了?每次调用partition方法时,随机选择主元,一般快速排序中的主元默认是尾元素)
import java.util.*;
public class Main {
public static void main(String[] args) {
int [] arr = {1,1,8,7,6,7,4,1,8,7};
quick_sort(arr,0,arr.length-1);
for(Integer fac : arr){
System.out.print(fac+" ");
}
}
static void quick_sort(int [] arr,int left,int right){
if(left < right){
int index = random_partition(arr,left,right);
quick_sort(arr,left,index -1);
quick_sort(arr,index+1,right);
}
}
static int random_partition(int [] arr,int left,int right){
// 随机获取主元,可以是left到right之间的任意一个数,包括头尾
int randomIndex = getRandom(left,right);
// 随机获取的主元与最后一个元素交换位置
if(randomIndex != right){
swap(arr,randomIndex,right);
}
// 接下来通过多次比较和交换,找到主元的位置,
//并把主元放到最终的位置,同时返回主要最终位置的下标
int leftIndex = left - 1;
int mainFactor = arr[right];
// 下标为right的不参与比较,j上界为right-1
for(int j = left; j <= right - 1;j++){
if(arr[j] < mainFactor){
// leftIndex标定的元素是目前所知的比主元小的最右面的元素
leftIndex++;
swap(arr,leftIndex,j);
}
}
// 下面这个交换是把主元放到最终的位置
swap(arr,leftIndex+1,right);
return leftIndex+1;
}
// 交换数组中下标为left和right的元素
static void swap(int [] arr,int left,int right){
int tem = arr[left];
arr[left] = arr[right];
arr[right] = tem;
}
// 获取min到max之间的随机一个数,包括min和max
static int getRandom(int min,int max){
// 返回[0.0,1.0)的double型数值
return (int)(Math.random()*(max-min)+min);
}
}
结果: