## 分治法之线性时间选择问题
以前没写过博客,这学期开设了一门算法设计与分析的课程,老师给我们讲了CSDN的重要性,是我们IT人士共享交流的平台,在上面可以看到很多大神的经验分享,所以我也来加入这个行列啦 哈哈哈
这几天都在学习分治算法,何为分值算法呢,其主要的思想就是将一个问题规模为N的问题,然后将其划分为k个相同的子问题,使每个子问题都具有最优子结构,子问题是相互独立的。然后我们就递归的解决这些子问题,然后自底向上合并每个子问题的解,最后得到的一个解就是我们问题所求的解了。
divide-and-conquer(P){
if(|p|<=n) //|P|是问题规模,n是出口,表示问题规模不超过n时,问题 容易解决
adhoc(P); //问题规模不超过n时,直接用算法adhoc(P)解决
divide P into smaller subinstances P1,P2,..Pk;
for(i=1;i<=k;i++){
yi=divide-and-conquer(Pi);
}
return merge(y1,y2,...yk); //merge()合并子问题的解
}
好啦,讲了分治法的基本思想,那我们就来看看线性时间选择问题吧
问题描述:找一个数组中第k小元素。
例子:数组a={2,20,7,1,9,3,10,15,8,4}
输入:k=6
输出:8
问题分析:这道题沿用了快速排序的思想,(这里小周周就当你们学会了快速排序啦) 只不过只对一个子序列操作。当k比左边子序的长度小时,说明要找的元素在左子序列,然后就舍去右子序列,只对左子序列继续同样的操作,否则,如果K大于左边子序列的长度时。说明要找的元素在右子序列中,然后就舍去左子序列,只对右子序列继续同样的操作。对右子序列操作时,我们要更改k,将k变为在右子序列中第几小元素。比如数组a包含1到10,10个自然数,然后要查找的k=6时,因为k大于左边子序列长度(10/2=5),所以在右边子序列查找,但是k就要变为在右子序列中第1小元素了(k=k-5=6-5=1)。当序列只剩一个元素时,这个元素就是我们要查找的第K小元素了。
import java.util.*;
public class XianXing {
static int k; //要查找的第几小元素 设置为静态的(共享的) 可以在任何地方修改值
static int z=1; //统计sort函数调用次数
static int y=1; //统计partition函数调用次数
public static void main(String[] args) {
Scanner s=new Scanner(System.in);
System.out.print("请输入要查找第几小元素:");
k=s.nextInt();
int []a= {
12,38,1,3,89,100,2,7,29,28,43,78,28,11,4};
sort(a,0,a.length-1);
}
public static void sort(int []a,int l,int r) {
System.out.println("这是第 "+z+" 次调用sort函数 进来的l是:"+l+"进来的r是:"+r);
z++;
if(l==r) {
//当只剩一个元素时,该元素就是要查找的第几最小元素
System.out.println("该元素为:"+a[l]);
}
if(l<r) {
int mid=partition(a,l,r);
if(k<=mid-l+1) {
//(mid-l+1)是左边子序列的长度,当K<=左边子序列的长度时,说明第几最小元素在左边子序列
sort(a,l,mid);
}else {
//当K>左边子序列的长度时,说明第几最小元素在右边子序列
k=k-(mid-l+1); //并且k变为了在右边子序列中第k-(mid-l+1)最小元素
sort(a,mid+1,r);
}
}
}
public static int partition(int []a,int l,int r) {
int i=l;
int j=r+1;
int x=a[l]; //基准元
System.out.println("这是第 "+y+" 次调用partition函数 进来的l是:"+l+"进来的r是:"+r);
y++;
while(true) {
//java中只能是true
while(a[++i]<x&&i<r); //寻找左边比基准元大的元素
while(a[--j]>x); //寻找右边比基准元小的元素
if(i>=j) {
//i对应左半部分,j对应右半部分
break;
}
swap(a,i,j); //交换左边比基准元素大的元素和右边比基准元素小的元素
}
a[l]=a[j]; //更改基准元 使得基准元左边的数都比基准元小,右边的数都比基准元大
a[j]=x;
return j; //返回基准元下标
}
public static void swap(int []a,int i,int j) {
int temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
测试数组a={12,38,1,3,89,100,2,7,29,28,43,78,28,11,4} k=7
好啦,线性时间选择问题我们就聊到这啦,有什么不懂得话记得私聊小周周我呢。
如果你们喜欢的话,别忘了给小周周点个赞哦,小公举们的满意,是小周周无尽的动力!❥(^_-)
【无名之辈 我是谁 小小的天 也有大大的梦想】