随机选择算法,求一列数中第K大的数

BUG代码

#include<iostream>		 
using namespace std;

//比快排还要简化  肯定比排序的时间复杂度低


int Partition(int A[],int left,int right){
	int temp=A[left];

	while(left<right){
		while(left<right&&A[right]>=temp) right--;
		A[left]=A[right];
		while(left<right&&A[left]<temp) left++;
		A[right]=A[left];
	}
	A[left]=temp;
	return left;
}

//随机选择算法,从A[left,right]中返回第K大的数
int randSelect(int A[],int left,int right,int K){
	if(left==right) return A[left];//left==right肯定是边界 此时返回边界重合值 可能是可能不是
	int p=Partition(A,left,right);
	int M=p-left+1;//p是第M大的数
	/*********************************/
	for(int i=0;i<6;i++){
		cout<<A[i]<<" ";
	}
	cout<<endl<<"M="<<M<<" p="<<p<<endl;
	/*********************************/


	if(M==K) {
		cout<<"答案:"<<A[p]<<"\n";
		return A[p];
	}

	if(K<M){
		randSelect(A,left,p-1,K);//左侧找第k大的数
	}else{
		randSelect(A,p+1,right,K-M);//右侧找第K-M大的数
	}
}


int main(){

	int A[]={5,12,7,2,9,3};
	/*for(int i=1;i<=6;i++){
		cout<<randSelect(A,0,5,i)<<" ";
	}*/
	cout<<randSelect(A,0,5,5);
	/*int B[]={7,9,12};
	cout<<Partition(B,0,2);*/
	cout<<endl;
	return 0;
}

4.7 随机选择算法

函数返回没错,确实找到了第5大的是9,但是randSelect()函数返回输出0

 

抄代码都抄错了,纠结这么久还

此处递归调用的返回值到一直传递下去,所以此处每次要return randSelect(A,left,p-1,K);//左侧找第k大的数

即:

if(K<M){
        randSelect(A,left,p-1,K);//左侧找第k大的数
}else{
        randSelect(A,p+1,right,K-M);//右侧找第K-M大的数
}

改成

if(K<M){
        return randSelect(A,left,p-1,K);//左侧找第k大的数
}else{
        return randSelect(A,p+1,right,K-M);//右侧找第K-M大的数
}

好好一个一个地与书上代码对照,就能发现这个错误了

 

正确代码:

#include<iostream>		 
using namespace std;

//比快排还要简化  肯定比排序的时间复杂度低
int Partition(int A[],int left,int right){
	int temp=A[left];

	while(left<right){
		while(left<right&&A[right]>=temp) right--;
		A[left]=A[right];
		while(left<right&&A[left]<temp) left++;
		A[right]=A[left];
	}
	A[left]=temp;
	return left;
}

//随机选择算法,从A[left,right]中返回第K大的数
int randSelect(int A[],int left,int right,int K){
	if(left==right) return A[left];//left==right肯定是边界 此时返回边界重合值 可能是可能不是
	int p=Partition(A,left,right);
	int M=p-left+1;//p是第M大的数
	if(M==K) return A[p];
	if(K<M){
		return randSelect(A,left,p-1,K);//左侧找第k大的数
	}else{
		return randSelect(A,p+1,right,K-M);//右侧找第K-M大的数
	}
}


int main(){

	int A[]={5,12,7,2,9,3};
	for(int i=1;i<=6;i++){
		cout<<"第"<<i<<"大的数是"<<randSelect(A,0,5,i)<<endl;
	}
	return 0;
}

 

 

 

给定一个整数集合,将集合切分为两部分,两部分元素个数相差尽可能小时两部分各自的和s1,s2差的绝对值尽可能大。

分析:n/2拆分元素个数差最小(0或1),排序后相减差绝对值最大。同样排序最短时间复杂度O(nlogn)

然而:随机选择第n/2大的数即可,时间复杂度也为O(n)

#include<iostream>		 
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;

const int N=13;

int randPatition(int A[],int left,int right){
	//随机产生主元
	int p=rand()%(right-left+1)+left;
	swap(A[left],A[p]);

	int temp=A[left];
	while(left<right){
		while(left<right&&A[right]>=temp) right--;
		A[left]=A[right];
		while(left<right&&A[left]<temp) left++;
		A[right]=A[left];
	}
	A[left]=temp;
	return left;
}

void randSelect(int A[],int left,int right,int K){
	if(left==right) return;
	int p=randPatition(A,left,right);
	int M=p-left+1;
	if(M==K) return;
	if(K<M){
		randSelect(A,left,p-1,K);		
	}else{
		randSelect(A,p+1,right,K-M);
	}
}

void displayArray(int A[]){
	for(int i=0;i<N;i++){
		cout<<A[i]<<" ";
	}
	cout<<endl;
}

int main(){
	srand(time(0));
	int A[N]={1,6,33,18,4,0,10,5,12,7,2,9,3};
	/*int A[N];
	for(int i=0;i<N;i++){
		A[i]=rand()%101;
	}*/
	displayArray(A);
	int sum=0,sum1=0;
	for(int i=0;i<N;i++){
		sum+=A[i];
	}
	randSelect(A,0,N-1,N/2);
	for(int i=0;i<N/2;i++){
		sum1+=A[i];
	}
	cout<<(sum-sum1)-sum1<<endl;	
	return 0;
}

4.7 随机选择算法

 

相关文章: