#include
#include "Fib.h "
using namespace std;
int binSearch_A (int* A, int e, int lo, int hi);
int binSearch_B (int* A, int e, int lo, int hi);
int binSearch_C (int* A, int e, int lo, int hi);
int fibSearch ( int* A, int const& e, int lo, int hi);
int main()
{
int A[]= {1, 2, 3, 4, 5, 6, 7, 8};
cout << binSearch_C( A, 6, 0, 9);
cout << fibSearch(A, 5, 0, 9);
}
//二分查找(版本A)
int binSearch_A (int* A, int e, int lo, int hi){
while( lo < hi){
int mi = (lo + hi) >> 1;
if ( A[mi] < e) lo = mi + 1;
else if ( A[mi] > e) hi = mi;
else return mi;
}
return -1;// 查找失败
}
//斐波拉契查找(版本A)
int fibSearch ( int* A, int const& e, int lo, int hi)
{
Fib fib ( hi - lo);
while ( lo < hi){
while ( hi - lo < fib.get()) fib.prev();
int mi = lo + fib.get() - 1;
if (e < A[mi]) hi = mi;
else if (A[mi] < e) lo = mi + 1;
else return mi;
}
return -1;//查找失败
}
//二分查找(版本B)
int binSearch_B (int* A, int e, int lo, int hi){
// 结束条件为只剩一个元素 A[lo]
while( 1 < hi -lo ){
int mi = (lo + hi) >> 1;
(e < A[mi]) ? hi = mi: lo = mi;//[lo, hi)--[lo, mi) or [mi, hi) 减而治之
}
return ( e == A[lo]) ? lo : -1;
}//查找不到不能指示失败的位置
//二分查找(版本C)
int binSearch_C (int* A, int e, int lo, int hi){
// 结束条件为只剩一个元素 A[lo]
while( lo < hi ){
int mi = (lo + hi) >> 1;
(e < A[mi]) ? hi = mi: lo = mi + 1;//[lo, hi)--[lo, mi) or [mi, hi) 减而治之
}
return --lo;//lo-1是不大于e的最后一个元素
}//查找不到不能指示失败的位置
//A[0, lo)中元素不大于e, A[hi, n)中的元素大于e
//A[mi]等于e的时候, lo = mi + 1,这使得[lo, mi)的元素都是不小于e的
//二分查找(版本A)
int binSearch_A (int* A, int e, int lo, int hi){
while( lo < hi){
int mi = (lo + hi) >> 1;
if ( A[mi] < e) lo = mi + 1;
else if ( A[mi] > e) hi = mi;
else return mi;
}
return -1;//查找失败
}
//斐波拉契查找(版本A)
int fibSearch ( int* A, int const& e, int lo, int hi)
{
Fib fib ( hi - lo);
while ( lo < hi){
while ( hi - lo < fib.get()) fib.prev();
int mi = lo + fib.get() - 1;
if (e < A[mi]) hi = mi;
else if (A[mi] < e) lo = mi + 1;
else return mi;
}
return -1;//查找失败
}
class Fib{//Fibonacci数列类
private:
int f,g;
public:
Fib ( int n)
{f = 1;g = 0; while ( g < n) next();}
int get() { return g;}
int next() { g += f; f = g - f; return g;}//转至下一项,O(1)时间
int prev() { f = g - f; g -=f; return g;}//转至上一项,O(1)时间
};
//二分查找(版本B)
int binSearch_B (int* A, int e, int lo, int hi){
// 结束条件为只剩一个元素 A[lo]
while( 1 < hi -lo ){
int mi = (lo + hi) >> 1;
(e < A[mi]) ? hi = mi: lo = mi;//[lo, hi)--[lo, mi) or [mi, hi) 减而治之
}
return ( e == A[lo]) ? lo : -1;
}//查找不到不能指示失败的位置
//二分查找(版本C)
int binSearch_C (int* A, int e, int lo, int hi){
// 结束条件为只剩一个元素 A[lo]
while( lo < hi ){
int mi = (lo + hi) >> 1;
(e < A[mi]) ? hi = mi: lo = mi + 1;//[lo, hi)--[lo, mi) or [mi, hi) 减而治之
}
return --lo;//lo-1是不大于e的最后一个元素
}//查找不到不能指示失败的位置
从三种版本的二分查找以及斐波那契查找可以看出,改进二分查找是一个非常细致的工作。各个版本其实区别不大,但是小小的改变能够导致语义与设计思想的完全不同。版本A的不变性在于不断比较A[mi],直到区间长度为0;版本B的不变性在于使得e包含在[lo,hi)中,直到区间长度减小为1,通过比较A[lo]来确定返回值;版本C的不变性在于每次的比较将一部分元素归于左边(小于等于e)或者右边(大于e)中去,最后结束于最后的一个元素被分配,区间长度变为0,此时的A[–lo]就是满足语义的那个元素。