第k大的数 java_分治策略 - 选择第k大数 - Java实现

该博客介绍了如何运用分治法解决寻找数组中第k大元素的问题。通过BFPRT算法,将数组划分为较小的子数组,找出中位数的中位数,并以此为基准进行划分,递归地在小于或大于基准的子数组中查找,最终找到第k大的数。代码示例展示了Java实现这一算法的过程。
摘要由CSDN通过智能技术生成

题目要求:

编写程序,对任意输入的若干个不相同的整数,输出其第k大的数

解析:

我们采用分治法解决这道题。

把这些数放在一个数组中,用分治法的话,我们可以想到,怎样分治?

把一个数组分成若干个大小相等的子数组,然后在这些子数组中取中位数,再取这些中位数的中位数,用这个数就可以把数组划分为一个比它大的和比它小的数组。通过用这个数和我们要求的数进行比较,若等于它,则直接返回这个数,若小于,则递归的对这个数前面的数组的这些数进行分治策略,若大于,则递归的对这个数后面的数组的这些数进行分治策略。

\(main()\)里只有一个\(SelectK()\)方法,中包含有两个主要的方法,分别为取中位数\(Median()\)和划分\(Divide()\)方法。

\(Median()\):

首先,我们把数组分为5个一组(听说经过证明,5个一组划分最科学),然后取每组的中位数,这时用的是\(Median()\)方法。具体的对每5个连续的数进行排序,然后把每组中的中位数即第3个数交换到数组的最左边,如果这些转移的数的个数多于5个,就再次调用\(Median()\)方法,直到最左边的数是这个数组的中位数的中位数。

\(Divide()\):

介绍划分方法,当求得中位数的中位数后,我们就以这个数为基准,把当前进行排序的数组的段落进行划分,小于基准数的交换到基准数的左边,大于的交换至右边,然后比较要求的那个数和基准数是否相等,如果相等,则返回;若小于基准数,则递归左边的子数组;若大于基准数,则递归右边的子数组。

到这里,就是简单介绍一下这道题,这道题的主要算法在网上叫BFPRT算法,有兴趣的同学可以去搜一下,如果不想搜的话,可以直接看我之前写的具体讲这道题分治算法背后的算法思想的文章分治策略-选择问题。

Java代码:

static void swap(int[]arr,int i,int j){

int temp = arr[i];

arr[i] = arr[j];

arr[j] = temp;

}

static void sortArr(int[] arr,int a,int b){

for(int i=a;i

for(int j=i+1;j<=b;j++){

if(arr[i]

swap(arr,i,j);

}

}

}

//找中位数的中位数

static int Median(int[] arr,int a,int b){

if(a==b)

return a;

int i=0;

int n=0;

for(i=a;i

sortArr(arr,i,i+4);

n = i - a;

swap(arr,a+n/5,i+2);

}

//下面是剩余的数

int last = b-i+1;

if(last>0){

sortArr(arr,i,i+last-1);

n = i - a;

swap(arr,a+n/5,i+last/2);

}

n/=5;

if(n==a)

return a;

return Median(arr,a,a+n);

}

//划分

static int Divide(int[]arr,int a,int b,int m){

swap(arr,m,a);

int i = a;

int j = b;

int flag = arr[a];

while (i

while (arr[j]<=flag && i

j--;

arr[i] = arr[j];

while (arr[i]>=flag && i

i++;

arr[j] = arr[i];

}

arr[i] = flag;

return i;

}

static int SelectK(int[] arr,int a,int b,int k){

int m = Median(arr,a,b);

int i = Divide(arr,a,b,m);

int x = i-a+1;

if(x==k)

return arr[i];

if(x>k)

return SelectK(arr,a,i-1,k);

return SelectK(arr,i+1,b,k-x);

}

public static void main(String[] args) {

Scanner in = new Scanner(System.in);

System.out.println("请输入要求的第k大的k:");

int k = in.nextInt();

int[] arr = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,100,99,98,97,96,95,94,93,92,91,

90,89,88,87,86,85,84,83,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54,

53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26};

// System.out.println(arr.length);

System.out.println("第"+k+"大为:"+SelectK(arr,0,arr.length-1,k));

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值