二分查找是一个比较高效的查找算法,相比于O(n)时间复杂度的线性查找算法,二分查找可以将时间复杂度缩短到o(logn),在大量数据的情况下,节省了相当一部分的时间。
它查找的基础建立在一个已经有序的序列,通过每次与左右界值的中间相比较,每次将数据规模缩小到二分之一,从而缩短查找时间,代码如下
template <typename T>
int Binary_Search(T* A, T const& e, int left, int right)
{
int mid;
while(left < right){
mid = (left + right) / 2;
if(e < A[mid]) right = mid;
else if(A[mid] < e) left = mid + 1;
else return mid;
}
return -1;//未查找到指定数据
}
从代码可以看到,如果查找数据在序列的左边,则只需比较一次即可转入相应序列,如果查找数据在右边,则需要两次比较才可转入相应序列。因此,对于转入左右所消耗的时间是不一样的。
而针对这个首先想到的改进第一就是让出现右边的概率更小,就是让右边的序列比左边的序列短,而这样就引申出了Fibonacci查找,然而这种查找方法对于数据的数量有要求,因此在这不做讨论。
我们可以看出,之所以会有两次比较,是因为需要判断A[mid]和x的大小关系,如果等于则返回,而如果我们只进行一次比较,e<A[mid]的时候进入左边,另一种情况进入右边的序列则不就可以了
template <typename T>
int Binary_Search(T* A, T const& e, int left, int right)
{
int mid;
while(1 < right - left){
mid = (left + right) >> 1;
(e < A[mid]) ? right = mid : left = mid;
}
return (e == A[left]) ? left : -1;
}
对比之下不难发现,相比较之前的版本,这个版本在一定条件下缩减了时间,然后在另一些情况下增加了时间,这个版本只是在最好和最坏的条件下时间复杂度相差更小。另外,很多时候,我们需要返回不大于当前查找数据的最大数据以便于进行下一步操作,因此,就有了接下来的版本
template <typename T>
int Binary_Search(T* A, T const& e, int left, int right)
{
int mid;
while(left < right){
mid = (left + right) >> 1;
(e < A[mid]) ? right = mid : left = mid + 1;
}
return --left;
}
参考:
数据结构(学堂在线)