1,038
社区成员




这是我参加“朝闻道”知识分享大赛的第六十一篇文章。
给定先升后降(或先降后升)数组,使用二分检索思路和三分检索思路查找该数组的最大值(或最小值),并统计关键字比较的次数。
先升后降数组确定最大值:确定键值K,比较k前一项元素与k后一项元素与k的关系,有以下几种不同情况:当A[K]>A[k+1]并且A[K]>A[K-1]时,K即为最大值,A[K]>A[k+1]且A[K]<A[k-1]时,前一部分中有最大值,后一部分不会有最大值。A[K]<A[k+1]且A[K]>A[k-1]时最大值必然在后一部分。比较次数为键值与元素的比较次数和。
//折半查找最大,处理先升后降数组
int BinarySearch1(int &comparisons){
int l=0,r=n-1,mid;
while(l<r){
//cout<<"l:"<<l<<endl;
//cout<<"r:"<<r<<endl;
mid=(l+r)/2;
comparisons++;
if(arr[mid]<arr[mid+1]){
//说明最大在右侧
l=mid+1;
}else if(arr[mid]>arr[mid+1]){
//说明最大在左侧,但不能排除当前mid位置的元素
r=mid;
}
}
return l;
}
//三分检索查找最大,处理先升后降数组
int TernarySearch1(int &comparisons){
int l=0,r=n-1;
while(l<r){
int mid1 = l + (r - l) / 3;
int mid2 = r - (r - l) / 3;
//cout<<"mid1"<<mid1<<endl;
//cout<<"mid2"<<mid2<<endl;
//cout<<"l:"<<l<<endl;
//cout<<"r:"<<r<<endl;
comparisons++;
if (arr[mid1] > arr[mid1 + 1]) {
//在第一区域
r = mid1;
} else if (arr[mid2] > arr[mid2 - 1]) {
//在第三区域
l = mid2 ;
} else {
//在第二区域
l = mid1 + 1;
r = mid2;
}
}
return l;
}
//使用二分检索思路和三分检索思路查找该数组的最大值(或最小值)
void question6(){
//首先将arr变为先升序后降序
ascAndDesc();
cout<<"排序之后的数组:";
for(int i=0;i<n;i++){
cout<<arr[i]<<"\t";
}
cout<<endl;
int count[2]={0};
int res1=BinarySearch1(count[0]);
cout<<"二分检索 下标为:"<<res1<<",值为:"<<arr[res1]<<",比较次数:"<<count[0]<<endl;
int res2=TernarySearch1(count[1]);
cout<<"三分检索 下标为:"<<res2<<",值为:"<<arr[res2]<<",比较次数:"<<count[1]<<endl;
}
预排序查找数组中第k个最小元素:采用任意一种排序算法将原数组升序排序,直接输出第k个元素即为所需的第k个最小元素,关键字比较次数为1。
int PreSortedKthSmallest(int k, int &comparisons){
int *a=(int*)malloc(n*sizeof(int));
for(int i=0;i<n;i++){
a[i]=arr1[i];
}
//先进行排序
for(int i=0;i<n-1;i++){
for(int j=0;j<n-1;j++){
comparisons++;
if(a[j]>a[j+1]){
//交换
int temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
return a[k-1];
}