**
二分查找
//在有序表中二分查找某个值,若找到,则返回该元素在表中的位置。
二分查找法又称 折半查找法。
1.对查找列表的两个要求:
- 必须采用顺序存储结构。
- 必须按关键字大小有序排列(从大到小或者从小到大排列)。
2.算法思想:定义left为顺序表最左端元素位置,right为顺序表右端元素位置。定义mid=(left+right)/2,即为顺序表的中间位置。然后用查找的值与mid所在位置记录的值比较,如果相等,则返回当前值所在位置(表示查找成功)。由于表有序,那么就可以利用中间位置记录将表分成前后两个子表,若所查找的值比mid小,则只需在表的前半部分查找,否则只需要在表的后半部分查找。重复以上过程,直到查找到所寻找的值,使查找成功,或确定所查找的值不在该列表(查找失败)。
3.算法框架:
int bin_search(int arr[],int key)
{
int left=0;
int right=arr.length-1;//注意
while(left<=right)
{ int mid=(right+left)/2;//中间下标
if(arr[mid]==key)
return key;//找到了
else if(arr[mid]<key)//目标值在右半部分
{
left=mid+1;
}
else if(arr[mid]>key)//目标值在左半部分
{
right=mid-1;
}
}
return -1;//找不到
}
另外声明一下,计算mid时需要技巧,有三种方法,
- 第一种:mid=left+(right-left)/2.(可防止溢出)
- 第二种:mid=(left+right)/2;
- 第三种:mid=left+((right-left)>>1);(右移相当于除2)
- 第四种:mid=(left&right)+((left^right)>>1);
(相同的保留,不同的分)
最完美的是第四种,不会发生溢出。
4.需要注意的细节问题:
(1)为什么while循环条件是<=?
答:因为初始化right的赋值是arr.length-1,即最后一个元素的下标,而不是数组的长度。
(2)while(left<=right)的终止条件是left==right+1,即[right+1,right],可见这时候搜索区间为空。便终止循环,返回-1。而while(left<right)的终止条件是leftright,即[left,right],此时就会出现当只有一个元素时,就会将其漏掉。
5.完整代码如下:
#include<stdio.h>
#include<windows.h>
#include<string.h>
int bin_search(int arr[],int num, int key)
{
int left = 0;
int right = num - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (key<arr[mid])
{
right = mid - 1;
}
else if (key>arr[mid])
{
left = mid+1;
}
else
return mid;
}
return -1;
}
int main()
{
int a[] = { 2, 4, 7, 9, 11, 56, 99, 100, 521 };
int k = 0;
int target = 9;
int num = sizeof(a) / sizeof(a[0]);//求数组中元素的个数
k = bin_search(a,num,target);
printf("%d\n", k);
system("pause");
return 0;
}
运行结果:
注:
在编写代码中需要注意的点:
不要在函数体内用sizeof来求传入参数arr的大小。