N个元素中选最大最小
问题描述:从N个元素中,选出最大元素和最小元素。分析复杂度。
方法:
方法有三种。
方法一:
最笨的方法,循环一次找出最大的算素。再循环一下找到最小的。这里2次循环可以放在一起,作为小小的优化。比较次数:2* (N – 1) = 2N – 2。
代码:
void select_Max_Min_1(int *a,int n,int &Max,int &Min)
{
int i;
int kmax,kmin;
kmax=kmin=0;
for(i=1; i<n; ++i)
{
if(a[i]>a[kmax]) kmax=i;
if(a[i]<a[kmin]) kmin=i;
}
Max=a[kmax];
Min=a[kmin];
}
方法二:
取前两个元素比较出大小,取较大的元素与其余元素比较,得出最大值;取较小的元素与其余元素比较,得出最小值。
比较次数:1 + 2* (N – 2 + 1 – 1) = 2N – 3。
从这里我们可以看出,N个元素比较最大,需要N-1次比较。找出最小也需要N-1次比较。如果2个问题分开看,这是基本的需求。不过,当2个问题放到一起,原先每个问题中解决的子问题是有关系的。即,如果是将2个问题单独的存在时的方法简单的合到一起时(如方法1),里面会有很多重复的操作。如果我们能尽可能的减少这样的操作,方法的复杂度就会降低(如方法2)。
显然,方法2还可以优化。
代码:
void select_Max_Min_2(int *a,int n,int &Max,int &Min)
{
int i;
int kmax,kmin;
if(a[0]>a[1])
{
kmax=0;
kmin=1;
}
else
{
kmax=1;
kmin=0;
}
for(i=2; i<n; ++i)
{
if(a[i]>a[kmax]) kmax=i;
if(a[i]<a[kmin]) kmin=i;
}
Max=a[kmax];
Min=a[kmin];
}
方法三:
每相邻2个元素比较,较大的放后面,较小的放前面。在较大的元素中,找最大的。在较小的元素中找最小的。
odd:o((3n-3)/2) N为奇数
even:o(3n-4)/2) N为偶数
代码:
///这里注意序号的关系,其余都很好理解。
void select_Max_Min_3(int *a,int n,int &Max,int &Min)
{
int i,temp;
int kmin=0,kmax=1;
if(n%2) ///奇数
{
for(i=0; i<n-1; i+=2)
{
if(a[i]>a[i+1])
{
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
for(i=3; i<n-1; i+=2)
{
if(a[i]>a[kmax]) kmax=i;
if(a[i-1]<a[kmin]) kmin=i-1;
}
if(a[kmax]<a[n-1]) kmax=n-1;
if(a[kmin]>a[n-1]) kmin=n-1;
Max=a[kmax];
Min=a[kmin];
}
else ///偶数
{
for(i=0; i<n; i+=2)
{
if(a[i]>a[i+1])
{
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
for(i=3; i<n; i+=2)
{
if(a[i]>a[kmax]) kmax=i;
if(a[i-1]<a[kmin]) kmin=i-1;
}
Max=a[kmax];
Min=a[kmin];
}
}
分析:
N为偶数好分析,就先说偶数情况。
N为偶数时,相邻元素比较N/2次,在每个N/2个元素中分别找最大最小,2* (N/2-1)。
共计:N / 2+ 2 * (N/ 2 – 1) =3N/2 – 2。
N为奇数时,N-1为偶数,用偶数方法得出N-1个元素中的最大最小,带入上面的式子。3(N-1) / 2 – 2。剩下一个元素分别与得出的最大最小比较,得出最终的最大最小值。
共计:3(N-1 )/ 2 – 2 + 2 = (3N – 3 ) / 2。