3*n/2 - 2
求區(qū)間范圍最小值最大值
用分治法(Divide and Conquer)求n元數組最小元與最大元,當n=1時,不用比較,最大元和最小元都是這個數;當n=2時,一次比較就可以找出兩個數據元素的最大元和最小元;當n>2時,可以把n個數據元素分為大致相等的兩半,一半有n/2個數據元素,而另一半有n/2個數據元素。先分別找出各自組中的最大元和最小元,然后將兩個最大元進行比較,就可得n個元素的最大元;將兩個最小元進行比較,就可得n個元素的最小元。
在規(guī)模為n的數據元素集合中找出最大元和最小元, 至少需要3n/2-2次比較,即3n/2-2是找最大最小元算法的下界。當n=2k,或當n≠2k時,若n是若干2的整數冪之和,則算法的時間復雜度仍可達到下界3n/2-2。
a.為一個分治算法編寫偽代碼,該算法同時求出一個n元數組的最大元素和最小元素的值。
b.請拿該算法與解同樣問題的蠻力算法做一個比較。
?
解答:
a.同時求出最大值和最小值,只需要將原數組一分為二,再使用相同的方法找出這兩個部分中的最大值和最小值,然后經過比較就可以得到整個問題的最大值和最小值。
算法 minmax_element(A[l..r], min, max)
// 該算法利用分治技術得到數組A中的最大值和最小值
// 輸入:數值數組A[l..r]
// 輸出:最小值min和最大值max
if(r<0) return;????? // 空數組,沒有最大最小元
if(r==0) max=min=A[0]; // 只有一個元素時
if(r==1) {min=A[0]<=A[1]?A[0]:A[1]; max=A[0]<=A[1]?A[1]:A[0];} ?// 有兩元素時
else
{ ?
m=int((l+r)/2);?? // 去中間值,把數組分成兩個部分
minmax_element(l, m,?fMin,?fMax);?? // 遞歸解決前一部分
minmax_element(m+1, r, sMin,?sMax); // 遞歸解決后一部分
max= std::max(fMax, sMax); // 從兩部分的兩個最大值中選擇大值
min= std::min(fMin, sMin); // 從兩部分的兩個最小值中選擇小值
}
?
為了數據類型一般話,我們采用 C++ 的模板。將最小最大數對存儲在 std::pair 類型中。
template<class ForwardIt, class Compare> std::pair<ForwardIt, ForwardIt> minmax_element(ForwardIt first, ForwardIt last, Compare comp) {std::pair<ForwardIt, ForwardIt> result(first, first);if(first == last) return result;if(++first == last) return result;if(comp(*first, *result.first))result.first = first;elseresult.second = first;while(++first != last){ForwardIt i = first;if(++first == last){if(comp(*i, *result.first))result.first = i;else if (!(comp(*i, *result.second)))result.second = i;break;}else{if(comp(*first, *i)){if(comp(*first, *result.first))result.first = first;if(!(comp(*i, *result.second)))result.second = i;}else{if(comp(*i, *result.first))result.first = i;if(!(comp(*first, *result.second)))result.second = first;}}}return result; }?
時間復雜度為:
t(n)=2*t(n/2)+2 n>2
t(1)=0 t(2)=1
設n=2^k,則n/2=2^(k-1)
t(n)=t(2^k)=2*t[2^(k-1)]+2
=2[2*t(2^(k-2))+2]+2
=2^2*t[2^(k-2))]+2^2+2
=2^2[2*t[2^(k-3)]+2]+2^2+2
=2^3*t[2^(k-3)]+2^3+2^2+2
=...
=2^(k-1)*t(2)+2^(k-1)+2^(k-2)+...+2?? // t(2)=1
=2^(k-1)+2^(k-1)+2^(k-2)+...+2 // 后面部分為等比數列求和
=2^(k-1)+2^k-2??? // 2^(k-1)=n/2, 2^k=n
=n/2+n-2
=3*n/2-2
?
b.蠻力法的算法如下:
算法 simple_minmax(A[0..n])
// 用蠻力法得到數組A的最大值和最小值
// 輸入:數值數組A[l..r]
// 輸出:最小值min和最大值max
max=min=A[0];
for(i=0; i<n; ++i)
{
if(A[i]>max) max=A[i];
if(A[i]<min) min=A[i];
}
蠻力算法的時間復雜度t(n)=2*(n-1)
C++ 的頭文件 <algorithm>包含了上面兩種算法。
3*n/2-2 對應 std::minmax_element
2*(n-1) 對應 std::min_element + std::max_element
算法?minmax_element?的時間復雜度為3*n/2-2,simple_minmax?的時間復雜度為2n-2,都屬于Θ(n)復雜度。
但比較可得,minmax_element 減少了不必要的比較,速度上比 simple_minmax?的快一些。
?
轉載于:https://www.cnblogs.com/Martinium/p/minmax_element.html
總結
- 上一篇: Java 图片处理——如何生成高清晰度而
- 下一篇: 文顶顶 iOS开发UI篇—UITabBa