随机选择算法,求一列数中第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;
}
函数返回没错,确实找到了第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;
}