java 排序库_Algs4-2.3.23Java的排序库函数

该博客详细介绍了如何在Java中实现快速排序算法,并使用Tukey's Ninther方法选取中位数作为切分元素。在小数组情况下切换到插入排序以提高效率。代码包括了Tukey's Ninther中位数选择的逻辑以及整个排序过程的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

{

InsertSort(a,lo,hi);

return;

}

//p的初值为lo+1,满足lo~p-1的元素=v

//i的初值为lo+1,p~i-1为0长,满足p~i-1的元素

//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

//由于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位置元素

if (cmp<0) i++;

//当i位置元素=v时,交换i,p位置的元素,i,p指针向右移动一个位置,此时lo~p-1的元素=v,p~i-1的元素

else if (cmp==0) exch(a,i++,p++);

//当位置i的元素>v时,i指针暂停右移

else if(cmp>0) break;

}

//当i

//当出现数组只有两个元素v,>v时,i=j,由于在上一个while中i位置元素已与v进行过对比,如果j位置元素再与v进行一次对比就多比较一次了,所以j位置元素与v的比较必要性不强。

//所以i=j时可以不进行对比了,那么意味着j向左移动时不可能会越过i位置形成i>j的情况,最多只可能是形成i=j的情况。

while(i

{

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位置元素

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,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,j,i-1位置(含i-1)左边的元素<=v,右边的元素>=v。

//5)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的元素与i-1位置到左边的元素交换,

//lo~i-1段,p无论是靠左或靠右或均分此段时,这种交换都将得到

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");

//对

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

{

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

StdOut.print(a[i]+" ");

StdOut.println();

}

public static boolean isSorted(Comparable[] a)

{

for (int i=1;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

a[k]=StdRandom.random();

sort(a);

StdOut.println("isSorted=" +isSorted(a));

// show(a);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值