二分和斐波
一直在家,无聊就看看.
二分搜索有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;
}