【演算法拾遺】最大數和最小數

蘭亭風雨發表於2014-06-06

轉載請註明出處: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

    

相關文章