快速排序思想:
1.找基准:定义high,low,temp,先让tmp=low值,从high位置开始找比tmp小的值,没有就high–,有就让low值等于high值,然后从low位置开始找比tmp大的值,没有就low++,有就让high值等于low值,然后又从high位置开始找比tmp小的值,以此类推,直到high和low相遇跳出返回low下标(此时的基准)
找基准全程都是和tmp值(就是基准值)作比较,一次找基准后,基准左侧都是比基准小的数,基准右侧都是比基准大的数,但还是无需的。
2.根据基准判断是否需要继续排序:基准两侧只剩下一个元素时就不用找基准了(已有序)
快速排序时间复杂度 O(n*log2n) 最慢O(n^2)
快速排序的时间复杂性分析:排序的大体如下图所示,假设有1到8代表要排序的数,快速排序会递归log2(8)=3次,每次对n个数进行一次处理,所以他的时间复杂度为n*log2(n)。所以排序问题的时间复杂度可以认为是对排序数据的总的操作次数。
public class Fastsort {
public static int partion(int[] array,int low,int high){
int tmp = array[low];
while(low= tmp){
--high;
}
if(low >= high){
break;
}else{
array[low] = array[high];
}
while(low=high){
break;
}else{
array[high]=array[low];
}
}
array[low]=tmp;
return low;
}
找基准三种方法:
固定位置法:low值就是最后的基准值,万一low值刚好是所有元素最小值(或者元素刚好是有序),第一次找基准过程就相当于什么都没做
//1. 固定位置法
public static void Quick(int array[],int low,int high){
int par = partion(array,low,high);//基准的位置
if(par>low+1){//基准左边
Quick(array,low,par-1);
}
if(par
随机基准法:元素中随机找一个数,并赋给low,避免固定位置法的不足之处
//2.随机基准
public static void new_Quick1(int array[],int low,int high){
Random rand = new Random();
int randNumber = rand.nextInt(high-low+1) + low;
swap(array,low,randNumber);
int par = partion(array,low,high);//基准的位置
if(par>low+1){//基准左边
new_Quick1(array,low,par-1);
}
if(par
三分取基准:找出low和high下标的中值mid,mid值放在low位置,low值放在mid位置,这样就会尽可能的让一个中间大小的值成为了tmp值(基准值)
//3. 三分取基准
/*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
public static int med(int[] array,int low,int high) {
int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标
//使用三数取中法选择枢轴
if (array[mid] > array[high]) { //目标: array[mid] <= array[high]
swap(array,mid,high);
}
if (array[low] > array[high]) { //目标: array[low] <= array[high]
swap(array,low,high);
}
if (array[mid] > array[low]) { //目标: array[low] >= array[mid]
swap(array,mid,low);
}
//此时,array[mid] <= array[low] <= array[high]
return array[low];
//low的位置上保存这三个位置中间的值
//分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了 }
}
public static void new_Quick2(int[] array,int low,int high){
med(array,low,high);
int par = partion(array,low,high);
if(par > low+1){
new_Quick2(array,low,par-1);
}
if(par < high-1){
new_Quick2(array,par+1,high);
}
}
快排优化1:元素少时直接用直接插入
//优化1.元素少时用直接插入
public static void insrtSort(int[] array,int low,int high){
int temp = 0;
int j;
for(int i = low+1;i <=high;i++){
temp = array[i];//从i号位置开始进行排序。
for(j =i-1;j >= 0;j--){
if(array[j] > temp){
array[j+1]=array[j];
} else {//每次排序过后前面已经有序,找到第一个比temp小的。
break;
}
}
array[j+1] = temp;
}
}
public static void new_Quick3(int[] array,int low,int high){
if(high-low+1 < 10){
insrtSort(array,low,high);
return;
}else{
swap(array,low,(int)(Math.random())%(high-low)+low);
int par = partion(array,low,high);
if(par > low+1){
new_Quick3(array,low,par-1);
}
if(par < high-1){
new_Quick3(array,par+1,high);
}
}
}
快排优化2:聚集相同元素 将基准左右两侧和基准相同的元素聚集起来,接着给基准相同元素两末端以外的元素继续排序
//优化2.聚集相同的元素
public static void new_Quick4(int[] array,int low,int high){
int[] a;
int par = partion(array,low,high);
int left = par-1;
int right = par+1;
a=focusNum(array,low,high,par,left,right);
left = a[0];
right = a[1];
if(par > low+1){
new_Quick4(array,low,left);
}
if(par < high-1){
new_Quick4(array,right,high);
}
}
private static int[] focusNum(int[] array, int low, int high, int par,
int left, int right) {
//聚集
int tmp = 0;
int par_left = par-1;
int par_right = par+1;
//左边找
for(int i = par-1;i >= low;i--){
if(array[i] == array[par]){
if(i != par_left){
tmp = array[par_left];
array[par_left] = array[i];
array[i] = tmp;
par_left--;
}else{
par_left--;
}
}
}
left = par_left;
//右边找
for(int i = par+1;i <= high;i++){
if(array[i] == array[par]){
if(i != par_right){
tmp = array[par_right];
array[par_right] = array[i];
array[i] = tmp;
par_right++;
}else{
par_right++;
}
}
}
right = par_right;
int[] a = new int[2];
a[0] = left;
a[1] = right;
return a;
}