进行二分搜索的数组要求是有序的,二分搜索通过持续跟踪数组中包含元素t的范围来解决问题。一开始,这个范围是整个数组,然后通过将t与数组的中间项进行比较并抛弃一半的范围来缩小范围。该过程持续进行,直到在数组中找到t或确定包含t的范围为空时为止,在有n个元素的表中,二分搜索大约需要执行log 2n次比较操作。
1. 最基础的二分查找
下面的的例子为升序情况的二分查找的情况。
示例:如有已排序数组有8个元素如下查找元素x = 5;
1  5  6  7  9  10  12 44
将数组分为两个子段(0+7)/2 = 3: 1  5  6   7    9   10  12 44
比较array[3] = 7与x = 5的大小由于数组为升序:
(1) 若分段点元素大于x,则不用查找分段点以后的元素;
(2) 若分段点元素小于x,则不用查找分段前之前的元素;
(3) 若分段点元素等于x表示已找到该元素,返回。
array[3]比x大,则查找array[4]之前的元素,将array[4]之前的看作一个子数组继续进行二分操作。
语法: result=search_bin( int  *t, int  k , int  n );
参数:
t[]:
待查找数组
k:
查找关键字
n:
数组元素个数
返回值:
如果k在t[]中存在,输出i:t[i]=k,否则输出-1
注意:
  数组元素从 0开始存储
 
要求查找数组是有序升序序列
源程序:
 
 
InBlock.gif
InBlock.gif int search_bin( int *t, int k, int n)
InBlock.gif{
InBlock.gif         int low=0,high=n-1,mid;
InBlock.gif         while (low<=high)
InBlock.gif                {
InBlock.gif                mid=(low+high)/2;
InBlock.gif                 if (k==t[mid]) return mid;
InBlock.gif                 else if (k<t[mid]) high=mid-1;
InBlock.gif                 else low=mid+1;
InBlock.gif                }
InBlock.gif         return -1;
InBlock.gif}
InBlock.gif
InBlock.gif
 
2.改进二分查找--若查找的元素出现多次查找第一次出现的位置
我们可以从第一次得代码中知道,上述代码不能确定查找到得元素的位置为第一次出现的位置。 怎么确定查找的元素在该序列中出现的是第一次呢,我们举一个例:
数组:1  2  3  3  3  3  3  5 ;8个元素,查找值为3的元素。
将数组分为两个子段(0+7)/2 = 3: 1  2  3   3   3  3  3  5 
此时已查找到3,一种简单的实现方法可以在从该位置开始向前搜索,找到直到不等于3的时候就停止,这个时候找到3的位置就是第一次出现的位置,同理我们也可以用这种方法找到最后出现的3的位置。
语法: result=search_bin( int  *t, int  k , int  n );
参数:
t[]:
待查找数组
k:
查找关键字
n:
数组元素个数
返回值:
如果k在t[]中存在,输出i ,i为k在t[]中第一次出现的位置 :t[i]=k,否则输出-1
注意:
  数组元素从 0开始存储
 
要求查找数组是有序升序序列
源程序:
 
 
InBlock.gif
InBlock.gif int search_bin( int *t, int k, int n)
InBlock.gif{
InBlock.gif         int low=0,high=n-1,mid;
InBlock.gif         while (low<=high)
InBlock.gif                {
InBlock.gif                mid=(low+high)/2;
InBlock.gif                 if (k==t[mid])    
InBlock.gif
InBlock.gif        {
InBlock.gif
InBlock.gif             while(t[mid] != k)
InBlock.gif
InBlock.gif             {
InBlock.gif
InBlock.gif                    mid--;
InBlock.gif
InBlock.gif             }
InBlock.gif
InBlock.gif                 return mid+1;
InBlock.gif
InBlock.gif        }                
InBlock.gif
InBlock.gif         else if (k<t[mid]) high=mid-1;
InBlock.gif                 else low=mid+1;
InBlock.gif                }
InBlock.gif         return -1;
InBlock.gif}
InBlock.gif
 
我们通过上面的代码也许可以知道,这样实现确实很简单,但是这样效率确实降低了,如果有一个极端的例子,即一个数组里面的元素全部相同,且我们要查找的元素就是该数组的元素此时在查找第一个出现位置的时候就比较消耗时间,这里我们可以深入一点,继续利用分治的方法查找它第一次出现的位置。
示例:数组:1  2  3  3  3  3  3  5 ;8个元素,查找值为3的元素。
将数组分为两个子段(0+7)/2 = 3: 1  2  3   3   3  3  3  5 
在查找到元素后记录该位置 flag ,由于搜索的是第一次出现的位置,所以 应该搜索左子数组,调整搜索上界为mid-1,即为high=2;
在此范围内继续进行二分查找,实际上就是在查找到元素的时候并不停止搜索,而是继续搜索直到搜索子数组不存在。
语法: result=search_bin( int  *t, int  k , int  n );
参数:
t[]:
待查找数组
k:
查找关键字
n:
数组元素个数
返回值:
如果k在t[]中存在,输出i ,i为k在t[]中第一次出现的位置 :t[i]=k,否则输出-1
注意:
  数组元素从 0开始存储
 
要求查找数组是有序升序序列
源程序:
 
 
InBlock.gif int search_bin( int *t, int k, int n)
InBlock.gif{
InBlock.gif         int low=0,high=n-1,mid;
InBlock.gif
InBlock.gif int    flag = -1;
InBlock.gif         while (low<=high)
InBlock.gif                {
InBlock.gif                mid=(low+high)/2;
InBlock.gif                 if (k==t[mid])    
InBlock.gif
InBlock.gif        {
InBlock.gif
InBlock.gif                flag = mid;
InBlock.gif
InBlock.gif                high = mid-1;
InBlock.gif
InBlock.gif                 //如果查找最后一次出现的位置
InBlock.gif
InBlock.gif                 //low = mid + 1;;
InBlock.gif
InBlock.gif        }
InBlock.gif                 else if (k<t[mid]) high=mid-1;
InBlock.gif                 else low=mid+1;
InBlock.gif                }
InBlock.gif
InBlock.gif if(flag == -1)
InBlock.gif         return -1;
InBlock.gif
InBlock.gif else
InBlock.gif
InBlock.gif return flag;
InBlock.gif}
InBlock.gif
 
         另外一种实现该改进的方法是按照《编程珠玑》第9.3节中所讲的进行改进,程序如下:
InBlock.gif int search_bin( int *t, int k, int n){    
InBlock.gif    
InBlock.gif int low=-1,high=n,mid;
InBlock.gif    
InBlock.gif while (low+1!=high)        
InBlock.gif {        
InBlock.gif    mid=(low+high)/2;            
InBlock.gif     if (t[mid]<k)    
InBlock.gif     low=mid;        
InBlock.gif     else            
InBlock.gif     high=mid;
InBlock.gif }
InBlock.gif    
InBlock.gif if(high>=n||t[high]!=k)    
InBlock.gif     return -1;
InBlock.gif else    
InBlock.gif     return high;    
InBlock.gif}
InBlock.gif
测试程序:
InBlock.gif#include <stdio.h>
InBlock.gif
InBlock.gif#include <stdlib.h>
InBlock.gif
InBlock.gif#include <math.h>
InBlock.gif
InBlock.gif#include<time.h>
InBlock.gif
InBlock.gif
InBlock.gif int     cmp     (     const     void     *a     ,     const     void     *b     )            
InBlock.gif
InBlock.gif
InBlock.gif{            
InBlock.gif
InBlock.gif
InBlock.gif return     *( int     *)a     -     *( int     *)b;            
InBlock.gif
InBlock.gif
InBlock.gif}    
InBlock.gif
InBlock.gif //在此加入二分搜索的程序search_bin
InBlock.gif
InBlock.gif
InBlock.gif int main( int argc, char **argv)
InBlock.gif
InBlock.gif{
InBlock.gif
InBlock.gif int array[100];
InBlock.gif
InBlock.gif int i,j;
InBlock.gif
InBlock.gif int p[2];
InBlock.gif
InBlock.gif int key;
InBlock.gif
InBlock.gifsrand(time(0));
InBlock.gif
InBlock.gif for(i = 0; i< 100; i++)
InBlock.gif
InBlock.gif{
InBlock.gif
InBlock.gifarray[i] = rand()%100;
InBlock.gif
InBlock.gif}
InBlock.gif
InBlock.gifqsort(array,100, sizeof(array[0]),cmp);
InBlock.gif
InBlock.gif for(i = 0; i< 10; i++)
InBlock.gif
InBlock.gif{
InBlock.gif
InBlock.gif for(j=0; j<10; j++)
InBlock.gif
InBlock.gif{
InBlock.gif
InBlock.gifprintf( " %d ", array[i*10+j]);
InBlock.gif
InBlock.gif}
InBlock.gif
InBlock.gifprintf( "\n");
InBlock.gif
InBlock.gif}
InBlock.gif
InBlock.gif while(1)
InBlock.gif
InBlock.gif{
InBlock.gif
InBlock.gifprintf( "key : ");
InBlock.gif
InBlock.gifscanf( "%d", &key);
InBlock.gif
InBlock.gifp[0] = search_bin(array,key,100);
InBlock.gif
InBlock.gifprintf( "%d \n",p[0]);
InBlock.gif
InBlock.gif}
InBlock.gif
InBlock.gif
InBlock.gif return 0;
InBlock.gif
InBlock.gif}
InBlock.gif