算法 第二章–快速排序
基本思想:
当两个子数组都有序时,(两个数组分界点则为 数组1< key, key, 数组2>key)整个数组也自然有序了。
public class Quick {
//打印数组a的元素
public static void print(Comparable[]a){
for(Comparable j:a ){
System.out.print(j+" ");
}
System.out.println("-----------------------");
}
//交换a[i] 和a[j]
public static void exch(Comparable[] a,int i, int j){
Comparable t =a[i]; a[i] = a[j]; a[j] = t;
}
public static boolean less(Comparable v, Comparable m ){
return v.compareTo(m)<0;
}
private static int partition(Comparable[] a,int lo, int hi){
Comparable x = a[lo];//标尺
//指针 这样写为了 在程序执行之前 lo++; hi-- 到比较元素的开始地方
int i = lo;//左
int j = hi+1;//右
while(true){
if(lo >= hi) break;//首先去数组是否合法
while(less(a[++i] ,x)) if(i==hi)break; //从数组的最左端起,只要 元素小于标尺时,则向左移动;直到元素大于或等于 标尺时,停止
while(less(x,a[--j])) if(j==lo)break; //同理得。再交换。
if(i >= j) break;//检查是否j,i为同一个函数
exch( a, i,j);
}
exch( a, lo,j);//使a的 标尺 放在 的位置;
return j;//跳出程序
}
public static void sort(Comparable[]a){
StdRandom.shuffle(a);//消除对输入的依赖
//sort(a, 0,a.length-1);
sort2(a, 0,a.length-1);
}
private static void sort(Comparable[]a, int lo, int hi){
if(hi<= lo)return;
int k = partition(a,lo,hi);
sort(a,lo,k-1);
sort(a,k+1,hi);
}
//三向切分快速排序
private static void sort2(Comparable[] a,int lo,int hi){
if(hi<lo)return;
int lt = lo;
int i = lo+1;
int gt = hi;
Comparable v = a[lo];
while(i<=gt){
int cmp = a[i].compareTo(v);
//比标尺小
if(cmp < 0) exch(a,i++,lt++);
else if(cmp > 0) exch(a,i,gt--);
else i++;
}
sort(a,lo,lt-1);
sort(a,lt+1,hi);
}
public static void main(String[] args) {
Comparable[]a = {1,3,44,32,34,45,67,43,2,3,12,32,13,145};
print(a);
sort(a);
print(a);
}
}
- 基本算法
以为sort()是递归,把数组分成左右两个部分,则它只需要数组两边有序即可。(两个数组分界点则为 数组1< key, key, 数组2>key)
private static int partition(Comparable[] a,int lo, int hi){
Comparable x = a[lo];//标尺
//指针 这样写为了 在程序执行之前 lo++; hi-- 到比较元素的开始地方
int i = lo;//左
int j = hi+1;//右
while(true){
if(lo >= hi) break;//首先去数组是否合法
while(less(a[++i] ,x)) if(i==hi)break; //从数组的最左端起,只要 元素小于标尺时,则向左移动;直到元素大于或等于 标尺时,停止
while(less(x,a[--j])) if(j==lo)break; //同理得。
if(i >= j) break;//检查是否j,i为同一个元素
exch( a, i,j);
}
exch( a, lo,j);//使a的 标尺 放在 的位置;
return j;//跳出程序
}
exch( a, lo,j)时,此数组以形成a[lo,…j-1] <= a[j] <=a[j+1,…hi]
三向切分
见算法p299示意图。
它其实就是把数组分为四个部分。
a【[< key],[=key],[未知的元素],[>key]】
然而一开始,全都是未知的即a【未知】,一步步进行排序,未知越来越少,从而达到了有序。
a【[lo 小于key lt],[lt+1 等于key gt],[gt+1 大于key hi]】//三向切分快速排序 private static void sort2(Comparable[] a,int lo,int hi){ if(hi<lo)return;//(1)跳出递归的条件和防止非法的数组进行排序 int lt = lo;//等于key的引索的其实点 int i = lo+1;//未知的数组部分的开始引索 int gt = hi;//gt为等于key的结束引索,即gt+1位大于key的引索 Comparable v = a[lo];//key //i---gt之间为未知元素,i<=gt 为未知元素还没结束 while(i<=gt){ int cmp = a[i].compareTo(v); //相当于a[i]-v //a[i] 小的时候, 即需要交换。因为它的原则,最左边都必须要比key小,交换后 ,第一个位置就确定了。同时++ if(cmp < 0) exch(a,i++,lt++); //a[i] 大的时候, 即需要交换。因为它的原则,最右边都必须要比key大,交换后 ,最后的位置就确定了。注意:此时无法判断交换的a[gt]的大小,所以i不用++,它仍是一个未知数。 else if(cmp > 0) exch(a,i,gt--); else i++; //当等于的时候,则其它的索引无需变动,只要i++即可 } sort(a,lo,lt-1); sort(a,lt+1,hi); }