转载请注明出处:http://blog.csdn.net/ns_code/article/details/28735533
求一个数组中的最大值和最小值,我们一般的做法是扫描一遍数组求的最大值,扫描一遍数组求最小值,这样做需要比较2N次才能求解。而实际上我们可以比较1.5N次即可得到结果。考虑如下几种方法。
方法一:
我们可以把数组分成两部分,首先按照顺序将数组中的相邻的两个数分在同一组,接着比较同一组中奇数位上的值和偶数位上的值,将较大的放在偶数位上,较小的放在奇数位上,这样经过0.5N次比较后,最大数肯定在偶数位上,最小的数肯定在奇数位上,而后分别扫描一遍数组的偶数位和奇数位,便可得到最大值和最小值。这样,真个算法只需比较1.5N次。代码很简单,不再给出。
方法二:
方法一会破坏原数组的结构,要避免这个问题,我们给出方法二。首先仍按照顺序将相邻的两个元素划为一组,而后利用两个变量max和min保存当前的最大值和最小值,同一组的数比较之后,不再交换位置,而是将其中较小的数与min作比较,如果小于min则更新min,同理将其中较大的数与max作比较,如果大于max则更新max。这样依然共有0.5N组,每一组的两个元素比较,要比较0.5N次,max与该组较大者比较,共比较0.5N次,min与该组最小者比较,共比较0.5N次,一共也是1.5N次。代码同样很简单,不再给出。
方法三:
可以用分治的思想,只需分别求出数组前后N/2个数中的最大值和最小值,而后取两个大值中最大值最为max,去两个小值中的最小值为min,该方法同样要比较N/2次。实现代码如下:
/* 分治法求最大最小值 */ void SearchMaxAndMin(int *arr,int start,int end,int *min,int *max) { if(arr == NULL) return; if(end-start <=1) { if(arr[start]>arr[end]) { *max = arr[start]; *min = arr[end]; } else { *max = arr[end]; *min = arr[start]; } return; } int maxL,minL; int maxR,minR; SearchMaxAndMin(arr,start,(start+end)>>1,&minL,&maxL); //求左边最大最小值 SearchMaxAndMin(arr,((start+end)>>1)+1,end,&minR,&maxR); //求右边最大最小值 if(maxL>maxR) *max = maxL; else *max = maxR; if(minL<minR) *min = minL; else *min = minR; }
延伸
求数组中的第二大的数,如果我们先扫描一遍数组,求的最大值,而后将其放到数组的最后,再求剩下元素的最大值,这样依然要比较2N-1次。
我们可以通过设置两个变量max1和max2分别保存最大值和次大值,将数组的前两个值中大的赋给max1,小的赋给max2,遇到某个元素大于max1,则更新max1,如果某元素大于max2,小于max1,则更新max2,这样到最后遍历一遍便可以得出次大值,但这样因为每个元素要与两个值比较,因此比较次数依然为2N。
同样可以利用解法二类似的方法,将比较次数降到1.5N次,将min改为max2,改变max2的更新条件即可。
依然也可以用分治的策略,比较前后N/2个数中的最大值和次大值,二者均取最大的那个,这样比较次数依然为1.5N.
而要求数组中的第k大的数,可以参考我的这篇博文:http://blog.csdn.net/ns_code/article/details/26966159
最大数和最小数