基本思想:
首先将查找表进行排序
取中间数据元素进行比较
当给定值与中间数据元素的关键字相等时,查找成功
当给定值小于中间元素时, 在中间元素的左区间进行二分查找
当给定值大于中间元素时,在中间元素的右区间进行二分查找
当任意区间均无记录时,查找失败
两种实现方式:递归和非递归
/**
* low:数组的低坐标,high数组的高坐标,key要查找的值
**/
int binary_search( int a[], int low, int high, int key )
{
int ret = -1;
if( a[low] <= key && key <= a[high])
{
if( low <= high )
{
int mid = ( low + high ) / 2;
if( a[mid] == key )
{
ret = mid;
}
else if( key < a[mid] )
{
ret = binary_search( a, low, mid-1, key);
}
else
{
ret = binary_search( a, mid+1, high, key);
}
}
}
return ret;
}
int binary_search2(int a[], int low, int high, int key)
{
int ret = -1;
if( a[low] <= key && key <= a[high] )
{
while( low <= high )
{
int mid = ( low + high ) / 2;
if( a[mid] == key )
{
ret = mid;
break;
}
else if( a[mid] > key )
{
high = mid -1;
}
else if( a[mid] < key )
{
low = mid + 1;
}
}
}
return ret;
}
时间复杂度均是O(logn),但是非递归方式避免了大量的压栈出栈操作,对于数据量比较大时,节省了不少时间
对二分法查找的改进:插值查找
二分法查找时对于中间值mid的求取是:mid = ( low + high ) / 2; 可以变换为 mid = low + 1/2( high - low );对于1/2的选取是默认要查找的值在中间值到左右两个区间的概率各占50%。但是有些特殊情况,要查找的值接近最低端,或者接近最高端时,这样查找的次数就会增多。所以动态的选择这个概率因子可以减少查找的次数。
计算公式:( key - a[low] ) / ( a[high] - a[low] ) ; 即key值的左区间占整个区间的概率, 在概率值附近选取mid更加接近key,所以mid值为:
mid = low + ( high - low ) * ( ( key - a[low] ) / ( a[high] - a[low] ) );
实现代码:
int interpolation_search(int a[], int low, int high, int key)
{
int ret = -1;
if( a[low] <= key && key <= a[high] )
{
while( (low <= high) )
{
float fx = 1.0f * ( key - a[low] ) / ( a[high] - a[low] );
int mid = low + fx*( high - low );
if( a[mid] == key)
{
ret = mid;
break;
}
else if( a[mid] > key )
{
high = mid - 1;
}
else if( a[mid] < key )
{
low = mid + 1;
}
}
}
return ret;
}
时间复杂度还是O(logn),但是该算法用到较多的除法运算和浮点型数值,这样时间上也会耗费不少的时间,所以要考虑设备硬件对浮点型的支持性。