從零基礎學三分查找


轉載請注明:http://www.cnblogs.com/ECJTUACM-873284962/

今晚是我們學長第二次講課,講了一個三分!認真聽了一下,感覺不是很難,可能會比二分還簡單些!我就把上課講的內容歸納為一篇文章概述吧!以后也會重點講解的!

簡單點說二分是查找區間,相當於一次函數,三分就是二次函數了,求它的極值,怎么做,數學常用的是求導,計算機就用查找咯,那么請看下面的簡單概述吧!

一. 概念

在二分查找的基礎上,在右區間(或左區間)再進行一次二分,這樣的查找算法稱為三分查找,也就是三分法。
三分查找通常用來迅速確定最值。
二分查找所面向的搜索序列的要求是:具有單調性(不一定嚴格單調);沒有單調性的序列不是使用二分查找。
與二分查找不同的是,三分法所面向的搜索序列的要求是:序列為一個凸性函數。通俗來講,就是該序列必須有一個最大值(或最小值),在最大值(最小值)的左側序列,必須滿足不嚴格單調遞增(遞減),右側序列必須滿足不嚴格單調遞減(遞增)。如下圖,表示一個有最大值的凸性函數:

二、算法過程

(1)、與二分法類似,先取整個區間的中間值mid。
 
mid = (left + right) / 2;

 

(2)、再取右側區間的中間值midmid,從而把區間分為三個小區間。
 
midmid = (mid + right) / 2; 

 

(3)、我們mid比midmid更靠近最值,我們就舍棄右區間,否則我們舍棄左區間?。
比較mid與midmid誰最靠近最值,只需要確定mid所在的函數值與midmid所在的函數值的大小。當最值為最大值時,mid與midmid中較大的那個自然更為靠近最值。最值為最小值時同理。 
if (cal(mid) > cal(midmid))  
     right = midmid;  
else  
      left = mid;  
(4)、重復(1)(2)(3)直至找到最值。
(5)、另一種三分寫法
 1 double three_devide(double low,double up)
 2 {
 3     double m1,m2;
 4     while(up-low>=eps)
 5     {
 6         m1=low+(up-low)/3;
 7         m2=up-(up-low)/3;
 8         if(f(m1)<=f(m2))
 9             low=m1;
10         else
11             up=m2;
12     }
13     return (m1+m2)/2;
14 }
算法的正確性:
1、mid與midmid在最值的同一側。由於凸性函數在最大值(最小值)任意一側都具有單調性,因此,mid與midmid中,更大(小)的那個 數自然更為靠近最值。此時,我們遠離最值的那個區間不可能包含最值,因此可以舍棄。
2、mid與midmid在最值的兩側。由於最值在中間的一個區間,因此我們舍棄一個區間后,並不會影響到最值
 1 const double EPS = 1e-10;
 2 double calc(double x)
 3 {
 4     // f(x) = -(x-3)^2 + 2;
 5     return -(x-3.0)*(x-3.0) + 2;
 6 }
 7 
 8 double ternarySearch(double low, double high)
 9 {
10     double mid, midmid;
11     while (low + EPS < high)
12     {
13         mid = (low + high) / 2;
14         midmid = (mid + high) / 2;
15         double mid_value = calc(mid);
16         double midmid_value = calc(midmid);
17         if (mid_value > midmid_value)
18             high = midmid;
19         else
20             low = mid;
21     }
22     return low;
23 }

調用ternarySearch(0, 6),返回的結果為3.0000

我們都知道 二分查找 適用於單調函數中逼近求解某點的值。

如果遇到凸性或凹形函數時,可以用三分查找求那個凸點或凹點。

下面的方法應該是三分查找的一個變形。

如圖所示,已知左右端點L、R,要求找到白點的位置。

思路:通過不斷縮小 [L,R] 的范圍,無限逼近白點。

做法:先取 [L,R] 的中點 mid,再取 [mid,R] 的中點 mmid,通過比較 f(mid) 與 f(mmid) 的大小來縮小范圍。

         當最后 L=R-1 時,再比較下這兩個點的值,我們就找到了答案。

1、當 f(mid) > f(mmid) 的時候,我們可以斷定 mmid 一定在白點的右邊。

反證法:假設 mmid 在白點的左邊,則 mid 也一定在白點的左邊,又由 f(mid) > f(mmid) 可推出 mmid < mid,與已知矛盾,故假設不成立。

所以,此時可以將 R = mmid 來縮小范圍。

2、當 f(mid) < f(mmid) 的時候,我們可以斷定 mid 一定在白點的左邊。

反證法:假設 mid 在白點的右邊,則 mmid 也一定在白點的右邊,又由 f(mid) < f(mmid) 可推出 mid > mmid,與已知矛盾,故假設不成立。

同理,此時可以將 L = mid 來縮小范圍。

 

 1 int SanFen(int l,int r) //找凸點
 2 {
 3     while(l < r-1)
 4     {
 5         int mid  = (l+r)/2;
 6         int mmid = (mid+r)/2;
 7         if( f(mid) > f(mmid) )
 8             r = mmid;
 9         else
10             l = mid;
11     }
12     return f(l) > f(r) ? l : r;
13 }
 
 日后會以例題的形式進行詳細的講解,這個也就是入門級!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM