编程之美 2.10寻找数组中的最大最小值
数组是最简单的一种线性数据结构,当得到一个数组,需要找出最大最小值的时候,通过什么样的方法可以高效的,找出最大最小值呢。对于一个N个整数组成的数组,需要比较多少次呢。
现在有一个N=8的数组{5,6,8,3,7,9,1,2}。
解法一:
将找最大和最小数看成2个独立的问题,分别求解,需要遍历数组2次,共需要2N次操作。
1 #include "iostream" 2 using namespace std; 3 void Search_max_and_min(int* a,int N){ 4 int max,min; 5 max=min=a[0]; 6 for(int i=0;i<N;i++){ 7 if(a[i]>max) 8 max=a[i]; 9 else if(a[i]<min) 10 min=a[i]; 11 } 12 cout<<"max="<<max<<endl; 13 cout<<"min="<<min<<endl; 14 } 15 int main(){ 16 int data[] = {10, 8, 9, 7, 4, 5}; 17 int length=sizeof(data)/sizeof(data[0]); 18 Search_max_and_min(data,length); 19 }
解法二:
通常情况最大和最小数不会是一个数,除非N=1或者数组所以元素相等。
首先将相邻的2个数放在同一个组里面(概念上的组),{(5,6)(8,3)(7,9)(1,2)},然后比较相邻的数,将较小的放在基数位,较大的放在偶数位,{(5,6)(3,8)(7,9)(1,2)},比较了N/2次,得到的新数组,我们分别比较所有基数位元素和所有偶数位元素,Max只可能在偶数位上,Min只可能在基数位上。然后分别比较{5,3,7,1}和{6,8,9,2}各N/2次,max=9,min=1,整个算法共比较1.5N次;
注意:此方法必须满足条件,N为偶数,N为基数的时候可能会得不到正确答案如N=5,{3,4,3,4,5},基数{3,3,5},偶{4,4},max=4,min=3。解法二三都没有分技术情况,在实际过程中是需要考虑的。
解法三:
解法二中破坏了原数组,我们使用新方法,在不破坏原数组的情况下, 进行遍历,仍将相邻的2个数放在同一个组里面(概念上的组),{(5,6)(8,3)(7,9)(1,2)},然后使用变量Max和Min存放当前最大最小的数,首先比较第一个第二个数,将大数存入Max,小数存入Min,接下来第二组(8,3)进行比较知道a[3]=8大,a[4]=3小,将小数与min比较,小于当前Min则更新,Max同理。
1 #include "iostream" 2 using namespace std; 3 void Search_max_and_min(int* a,int N){ 4 int max,min,tmax,tmin; 5 6 if(N%2==0){ 7 max=(a[0]>a[1])?a[0]:a[1]; 8 min=(a[0]<a[1])?a[0]:a[1]; 9 } 10 else 11 max=min=a[0]; 12 for(int i=1;i<N/2;i++){ 13 if(a[2*i-1]>a[2*i]){ 14 tmax=a[2*i-1]; 15 tmin=a[2*i]; 16 } 17 else{ 18 tmax=a[2*i]; 19 tmin=a[2*i-1]; 20 } 21 if(tmax > max) 22 max = tmax; 23 if(tmin < min) 24 min = tmin; 25 26 } 27 cout<<"max="<<max<<endl; 28 cout<<"min="<<min<<endl; 29 } 30 int main(){ 31 int data[] = {10, 8, 9, 7, 4, 5}; 32 int length=sizeof(data)/sizeof(data[0]); 33 Search_max_and_min(data,length); 34 }
比较次数仍为1.5N,相当于a[2k]和a[2k+1]先进行了一次比较,确定了大小,然后分别和max,min比较,节约了0.5N次比较。
解法四:
采用分治的思想,在N个数中求max和min,分别求出前后N/2个数的max和min,然后取较小的min和较大的max。比较次数同样为1.5N。