9.1-1 证明:在最坏情况下,找到n个元素中第二小的元素需要n+向上取整lgn-2次比较。
我们对于查找第2小元素分成2步。
step1:我们先将数组中的元素两两成对比较,共需n/2次比较,那么就有n/2个元素是较小的元素,然后再将这些较小的元素再次两两成对比较,又淘汰一半,重复这样的循环,每次淘汰一半元素直到只剩下1个元素,该元素就是最小元素。经过的比较次数为S=n/2+n/4+...(n/(2^k)=1) k=lgn S=n-1次。
step2:经过以上比较,就形成了一个二叉树,那么第2小的元素肯定与最小元素比较过,所以我们采取的方法是,从根结点也就是最小元素开始沿着根向叶子结点开始查找等于根节点的子结点A,第二小的元素就应该在与A结点属于同一个父结点的另外一个子结点B上,将B结点上的值给予第二小元素second,这样经过以上方式最坏lgn-1次比较,只要小于second值的元素,second就被覆盖成该元素,最终总能找到第2小元素。所以总比较次数为n-1+lgn-1=n+lgn-2。但是具体实现我还未想出来。
9.1-2 证明:在最坏情况下,同时找到n个元素中最大值和最小值的比较次数的下界是向上取整3n/2-2
我们将输入元素两两相互进行比较,然后把较小的与当前最小值比较,较大的与当前最大值比较,所以2个元素每次循环要比较3次,但是仅仅需要进行n/2次循环,所以总的比较次数为(向上取整)3n/2-2次。
以下是代码:
//同时求最小与最大值,只需要3n/2次比较
#include <iostream>
#include <time.h>
using namespace std;
const n=10;
void max_min(int A[],int &max,int &min)//同时找出最大值和最小值。
{
for (int i=0;i<n;i+=2)
{
if (A[i]>A[i+1])
{
if (A[i]>max)
{
max=A[i];
}
if (A[i+1]<min)
{
min=A[i+1];
}
}
else
{
if (A[i+1]>max)
{
max=A[i+1];
}
if (A[i]<min)
{
min=A[i];
}
}
}
}
void main()
{
//数组A max min全部置0
int A[n]={0},max=0,min=0;
//随机输入数组
srand( (unsigned)time( NULL ) );
for (int i=0;i<n;i++)
{
A[i]=rand()%100;
cout<<A[i]<<" ";
}
cout<<endl;
//max与min初始化
if (n%2!=0)
{
max=A[0];
min=A[0];
}
else
{
if (A[0]>A[1])
{
max=A[0];min=A[1];
}
else
{
max=A[1];min=A[0];
}
}
//求数组A的max与min
max_min(A,max,min);
//输出max与min
cout<<"max="<<max<<endl;
cout<<"min="<<min<<endl;
}
9.2节代码:
#include <iostream>
#include <time.h>
using namespace std;
const n=8;
int PARTITION(int A[],int p,int r);
int RANDOM(int p,int r)
{
int t=rand()%(r-p+1)+p;
return t;
}
int RANDOMIZED_PARTITION(int A[],int p,int r)
{
int i=RANDOM(p,r);
swap(A[r],A[i]);
return PARTITION(A,p,r);
}
int PARTITION(int A[],int p,int r)
{
int x=A[r];
int i=p-1;
for (int j=p;j<=r-1;j++)//O(n)
{
if (A[j]<=x)
{
i++;
swap(A[i],A[j]);
}
}
swap(A[i+1],A[r]);
return i+1;
}
int RANDOMIZED_SELECT(int A[],int p,int r,int i)
{
if (p==r)
{
return A[p];
}
int q=RANDOMIZED_PARTITION(A,p,r);
int k=q-p+1;
if (i==k)
{
return A[q];
}
else if(i<k)