二分和斐波
一直在家,無聊就看看.
二分搜索有O(1.5logn)的時間複雜度,斐波那契搜索可以進一步提升至O(1.4logn).
注:這兩種檢索方法都是針對有序集合的.
二分搜索
基本思路就是把集合分成兩部分,當然這裏是指有序集合。
把搜索目標與分界點元素作比較,從而決定去往哪一部分檢索目標。
二分搜索優解:單擊查看實現代碼
C代碼描述爲:
size_t Fibonacci(size_t number);
/** Fib搜索 傳入容器、區間和目標;返回<下標>\<-1> **/
template <typename T>
int FibSearch(vector<T> vec,size_t low,size_t high,T var)
{
/* 取集合兩部分的分界點爲mid */
size_t mid;
while(low<high){
mid = (high+low)/2;
if(var == vec[mid]) return mid;
else if(var<vec[mid]) high = mid;
else low = mid+1;
}
/* 沒有找到--返回-1 */
return -1;
}
斐波那契查找
斐波那契查找的思路可從於二分查找的思路領悟
二分查找總要根據mid位置和var的值的比較結果,在三件事:
1.返回mid
2.更新high
3.更新low
而根據判定結果選擇更新high或者low需要的操作次數是不同的(必然是其中一個只需要比較一次,而另一個需要比較兩次)
這就引發一種猜想:把更多的元素分到需要操作更少的那邊,就能夠減少總的操作次數,從降低時間複雜度,節省時間。
對於上面代碼所示的這種實現,我們更新high只需要:
else if(var<vec[mid]) high = mid;
這一次操作.
而更新low則需要:
else if(var<vec[mid]) high = mid;
else low = mid+1;
兩次操作.
故而按照前面的猜想,我們可以在選取分界點時稍往右偏些,把更多的元素分到左側。
也就是說,二分搜索是對半開,兩邊各佔0.5,現在讓左邊佔比略高於0.5,而右邊略低於0.5
分析發現,這個比值在大概0.6:0.4時使得這個思路得到的優化效果最佳.
也就是借用Fibonacci代替原代碼中的:
mid = (high+low)/2;
來更新mid的數值
Fibonacci搜索方法的一種實現如下
size_t Fibonacci(size_t number);
/** Fib搜索 傳入容器、區間和目標;返回<下標>\<-1> **/
template <typename T>
int FibSearch(vector<T> vec,size_t low,size_t high,T var)
{
/* 斐波那契數種子 */
size_t FibSeed = high-low;
/* 所謂mid */
size_t ptr = low + Fibonacci(FibSeed)-1;
while(low<high){
/* 更新mid */
while(Fibonacci(FibSeed) > high-low)
ptr = low + Fibonacci(--FibSeed)-1;
if(var == vec[ptr]) return ptr;
else if(var<vec[ptr]) high = ptr;
else low = ptr+1;
}
return -1;
}
其中Fibonacci的實現如下:
/* 斐波那契數列生成器 -- <傳入序號,返回對應位置數值>*/
size_t Fibonacci(size_t number)
{
/** 初始化數列種子 <Fo> and <Be> **/
size_t Fo=1,Be=0;
while(number--){
/* 暫且這樣規避上溢 ^_^ */
if(Fo>100000)
return -1;
Fo+=Be;
Be = Fo-Be;
}
return Fo;
}