快速排序
小弟初来咋到,面对算法一脸懵逼,希望各位大神能够给予指点,在此谢过。
普通快速排序
思路:升序排列时,数组被其中的一个key值切成两部分,保证左边的数据都比key小,右边的数据比key值大,当左右两边都有序时,整个数组也会有序
import java.util.Arrays;
/**
* Created by Fearless on 2017/3/29.
*/
public class Quick {
private static Comparable[] a={5,87,96,44,58,32,25,1,77,69,36,44};//测试数组
/***
* 测试算法
* @param args
*/
public static void main(String ... args){
quickSort(a);
System.out.println(Arrays.toString(a));
}
public static void quickSort(Comparable[] a) {
sort(a, 0, a.length - 1);
}
/***
* 排序
* @param a 排序数组
* @param i 起始索引
* @param i1 结束索引
*/
public static void sort(Comparable[] a, int i, int i1) {
//如果起始索引大于等于结束索引,返回
if (i >= i1) return;
//对数组进行切割
int j = partition(a, i, i1);
//对切割后的数组分别再做切割
sort(a,i,j);
sort(a,j+1,i1);
}
/***
* 对数组进行切割,返回切割位置的索引
* @param a 数组
* @param i 起始位置的索引
* @param i1 结束位置的索引
* @return 切割位置的索引
*/
private static int partition(Comparable[] a, int i, int i1) {
//初始化从左往右的索引
int index1 = i;
//初始化从右往左的索引
int index2 = i1+1;
//选取第一个值为key值
Comparable key = a[i];
//通过循环找在key左边比key大,在key右边比key小的值,并交换二者的位置
//使用++index1 和--index2 可以保证最后得到的索引值就是最终索引
//第一个位置是key值,所以index1从++index1开始
while (true) {
//从左往右找大于等于key的值
while (less(a[++index1],key)) {
if (index1 == i1) break;
}
//从右往左找小于等于key的值
while (less(key,a[--index2])) {
if (index2 == i) break;
}
//如果左索引位置大于右索引位置,跳出循环
// 要保证在找到大小值的情况下大值在小值的左边
if(index1>=index2) break;
//交换大小值位置
exch(a,index1,index2);
}
//把小值和切割数的位置做交换
//如果没有找到比key小的值,index2会停在最前面
/*如果有找到比key小的值,index2会停在小值处,此时index1找到合适数据时,可交换数据。
如果没有找到合适的数据,说明index2之前的数据没有比key大的值了
可以放心的把key的值放到index2处*/
exch(a,index2,i);
return index2;
}
//a是否小于b
private static boolean less(Comparable a, Comparable b) {
return a.compareTo(b) < 0;
}
/***
* 交换索引 i j 处的数据
* @param a
* @param i
* @param j
*/
private static void exch(Comparable[] a,int i,int j){
Comparable temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
三向切分的快速排序
在普通快速排序时,当遇到相同数据的情况下,排序算法依旧会对其进行数据交换操作,这样大大降低了排序的效率,所以在有很多重复数据的情况下,我们可以使用改进后的三向切分的快速排序,
思路:将重复数据很多的数组取key值,并将该数组划分成小于key的区域,等于key的区域和大于key的区域,并通过递归对小于和大于key的区域分别做相同的排序操作。
import java.util.Arrays;
/**
* Created by Fearless on 2017/3/29.
*/
public class Quick3way {
private static Comparable[] a={19,18,20,20,21,21,19,20,19,21,18,19,18,18,20};//测试数组
/***
* 测试算法
* @param args
*/
public static void main(String ... args){
System.out.println(Arrays.toString(a));
quickSort(a);
System.out.println(Arrays.toString(a));
}
public static void quickSort(Comparable[] a) {
sort(a, 0, a.length - 1);
}
/***
* 三向切分的快速排序
* @param a 排序数组
* @param i 起始索引
* @param i1 结束索引
*/
public static void sort(Comparable[] a, int i, int i1) {
if(i>=i1) return;
int li=i;
int ri=i1;
Comparable key=a[i++];
while(i<=ri){
//key 和a[i]做比较
int j=key.compareTo(a[i]);
//如果a[i]>key,交换索引i和ri处的数据,ri索引减1,把大的放到后面
// 因为无法确定调换后的i处的数据的大小,所以i的索引保持不变,在轮进行比较
if(j<0) exch(a,i,ri--);
//如果a[i]==key,不做任何操作,i的索引后移
else if(j==0) i++;
//如果a[i]<key,交换索引i和ri处的数据,把小的放前面,两个索引都向后移
else exch(a,i++,li++);
System.out.println(Arrays.toString(a));
}
//对小于key的区域做排序
sort(a,i,li-1);
//对大于key的区域做排序
sort(a,ri+1,i1);
}
/***
* 交换索引 i j 处的数据
* @param a
* @param i
* @param j
*/
private static void exch(Comparable[] a,int i,int j){
Comparable temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}