1. 程式人生 > >Algs4-2.3.23Java的排序庫函數

Algs4-2.3.23Java的排序庫函數

bsp -- 使用 private 切分 返回 ont ger 得出

2.3.23Java的排序庫函數。在練習2.3.22的代碼中使用Tukey‘s ninther方法來找出切分元素--選擇三組,每組三個元素,分別取三組元素的中位數,然後取三個中位數的中位數作為切分元素,且在排序小數組時切換到插入排序。
public class E2d3d23
{
public static void sort(Comparable[] a)
{
StdRandom.shuffle(a);
sort(a,0,a.length-1);
}

private static void sort(Comparable[] a,int lo,int hi)
{
//數組少於M個元素時使用插入排序
int M=8;
if (hi-lo+1<M)
{
InsertSort(a,lo,hi);
return;
}
//p的初值為lo+1,滿足lo~p-1的元素=v
//i的初值為lo+1,p~i-1為0長,滿足p~i-1的元素<v
//q的初值為hi,q+1~hi為0長,滿足q+1~hi的元素=v
//j的初值為hi,j+1~q為0長,滿足q+1~hi的元素>v
int p=lo+1,i=lo+1,q=hi,j=hi;
// StdOut.printf("lo=%d,i=%d,j=%d,hi=%d\n",lo,i,j,hi);
int newVIndex=TukeysNintherIndex(a,lo,hi,M);
exch(a,lo,newVIndex);
Comparable v=a[lo];

while(i<=j)
{
//當i<j時一定需要i位置元素與v對比,當出現數組只有兩個元素v,<v時,i=j,此時如果不進行對比排序後的結果就無序的,所以i=j時也需要對比。
//由於i=j時還需要對比,那麽可能會出現i越過j形成i>=j的情況。
while(i<=j)
{
int cmp=a[i].compareTo(v);
//StdOut.printf("ToRight i=%d,j=%d,cmp=%d,a[i]=%f,v=%f\n",i,j,cmp,a[i],v);
//當i位置元素<v時,i向右移動一個位置,此時p~i-1的元素<v
if (cmp<0) i++;
//當i位置元素=v時,交換i,p位置的元素,i,p指針向右移動一個位置,此時lo~p-1的元素=v,p~i-1的元素<v
else if (cmp==0) exch(a,i++,p++);
//當位置i的元素>v時,i指針暫停右移
else if(cmp>0) break;
}
//當i<j時一定需要j位置元素與v對比,
//當出現數組只有兩個元素v,>v時,i=j,由於在上一個while中i位置元素已與v進行過對比,如果j位置元素再與v進行一次對比就多比較一次了,所以j位置元素與v的比較必要性不強。
//所以i=j時可以不進行對比了,那麽意味著j向左移動時不可能會越過i位置形成i>j的情況,最多只可能是形成i=j的情況。
while(i<j)
{
int cmp=a[j].compareTo(v);
// StdOut.printf("ToRight i=%d,j=%d,cmp=%d,a[i]=%f,v=%f\n",i,j,cmp,a[i],v);
//當j位置元素<v時,j指針暫停左移
if (cmp<0) break;
//當j位置元素=v時,交換j,q位置的元素,j,q指針向左移動一個位置,此時q+1~hi的元素=v,j+1~q的元素>v
else if(cmp==0) exch(a,j--,q--);
//當j位置元素>v時,j向左移動一個位置,此時j+1~q的元素>v
else if(cmp>0)j-- ;
}
//i,j指針相遇或i越過j時形成i>=j的幾種具體排列
//1)v,<v 此情況時i>j,i-1位置(含i-1)左邊的元素<=v,右邊的元素>=v。
//2)v,v,此情況時i>j,i-1位置(含i-1)左邊的元素<=v,右邊的元素>=v。
//3)v,>v,此情況時i=j,i-1位置(含i-1)左邊的元素<=v,右邊的元素>=v。
//4)v,>v,<v此情況時i<j需要交換i,j位置元素,並將i,j向前移動一位,此時i>j,i-1位置(含i-1)左邊的元素<=v,右邊的元素>=v。
//5)v,<v,>v此情況時i=j,i-1位置(含i-1)左邊的元素<=v,右邊的元素>=v。

//當i,j 指針相遇或越過時,結束本輪比較
if (i>=j) break;
//StdOut.printf("Exch i=%d,j=%d\n",i,j);
//上述第4點。
exch(a,i,j);
i++;
j--;
}
//依據上述5點的結論,得出位置i和i右邊的元素>=v,保存i到j
j=i;
//左端=v元素與<v的元素段的右邊交換。具體
//從左端向右將所有=v的元素與i-1位置到左邊的元素交換,
//lo~i-1段,p無論是靠左或靠右或均分此段時,這種交換都將得到<v,=v的排列。
i--;
for (int k = lo; k < p; k++) exch(a, k, i--);
//右端=v端元素與>v的元素段的左端進行交換。
//從右端向左將所有=v的元素與j位置到右邊的元素交換,
//j~hi段,q無論是靠左或靠右或均分此段時,這種交負都將得到=v,>v的排列。
for (int k = hi; k > q; k--) exch(a, k, j++);
// StdOut.printf("Move lo=%d,i-1=%d,j+1=%d,hi=%d\n",lo,i-1,j+1,hi);
// StdOut.println("Left Sort");
//對<v的左子數組再排序,此時i處在最右邊的<v的位置上。
sort(a, lo, i);
//StdOut.println("Right Sort");
//對>v的右子數組再排序,此時j處在最左邊的>v的位置上。
sort(a, j, hi);
}


//返回Tukey‘s ninther取樣切分元素索引
private static int TukeysNintherIndex(Comparable[] a,int lo,int hi,int M)
{
//子數組少於4M個元素時,第一個元素作為切分元素
if((hi-lo+1)<4*M) return lo;
//子數組有4M個或以上元素時,取三個子數組中的中位數的中位數作為切分元素

////取第一個子數組
Integer[] firstArr={lo,lo+M/2,lo+M};
////按原數組的值對新數組進行排序。排序後的結果是原數組小中大值對應的索引
if(less(a[firstArr[1]],a[firstArr[0]])) exch(firstArr,0,1);
if(less(a[firstArr[2]],a[firstArr[1]])) exch(firstArr,1,2);
if(less(a[firstArr[1]],a[firstArr[0]])) exch(firstArr,0,1);

////取第二個子數組
Integer[] secondArr={(hi-lo)/2-M/2,(hi-lo)/2,(hi-lo)/2+M/2};
////按原數組的值對新數組進行排序。排序後的結果是原數組小中大值對應的索引
if(less(a[secondArr[1]],a[secondArr[0]])) exch(secondArr,0,1);
if(less(a[secondArr[2]],a[secondArr[1]])) exch(secondArr,1,2);
if(less(a[secondArr[1]],a[secondArr[0]])) exch(secondArr,0,1);

////取第三個子數組
Integer[] thirdArr={hi-M,hi-M/2,hi};
////按原數組的值對新數組進行排序。排序後的結果是原數組小中大值對應的索引
if(less(a[thirdArr[1]],a[thirdArr[0]])) exch(thirdArr,0,1);
if(less(a[thirdArr[2]],a[thirdArr[1]])) exch(thirdArr,1,2);
if(less(a[thirdArr[1]],a[thirdArr[0]])) exch(thirdArr,0,1);

////取三個數組中位數的中位數
Integer[] midArr={firstArr[1],secondArr[1],thirdArr[1]};
////按原數組的值對新數組進行排序。排序後的結果是原數組小中大值對應的索引
if(less(a[midArr[1]],a[midArr[0]])) exch(midArr,0,1);
if(less(a[midArr[2]],a[midArr[1]])) exch(midArr,1,2);
if(less(a[midArr[1]],a[midArr[0]])) exch(midArr,0,1);

return midArr[1];
}

private static void InsertSort(Comparable[] a,int lo,int hi)
{
for (int i=lo+1;i<hi+1;i++)
{
for (int j=i;j>0 && less(a[j],a[j-1]);j--)
exch(a,j,j-1);
}
}

private static boolean less(Comparable v,Comparable w)
{ return v.compareTo(w)<0;}

private static void exch(Comparable[] a,int i,int j)
{
Comparable t=a[i];
a[i]=a[j];
a[j]=t;
}

private static void show(Comparable[] a)
{
for (int i=0;i<a.length;i++)
StdOut.print(a[i]+" ");
StdOut.println();
}

public static boolean isSorted(Comparable[] a)
{
for (int i=1;i<a.length;i++)
if(less(a[i],a[i-1])) return false;
return true;
}

public static void main(String[] args)
{
int N=Integer.parseInt(args[0]);
Double[] a=new Double[N];
StdOut.println(a.length);
for(int k=0;k<N;k++)
a[k]=StdRandom.random();

sort(a);

StdOut.println("isSorted=" +isSorted(a));
// show(a);
}
}

Algs4-2.3.23Java的排序庫函數