二分查找的理解
对于二分查找,我们首先得明白以下几点:
- 二分查找是一种查找算法
- 被查找的序列是有序的
- 如果查找的元素在集合中则返回元素的位置,否则返回NULL
下面我们举例说明二分查找的思想:
小明和小红玩游戏,小明手握一张写有数字3的纸片,让小红猜这个纸片上的数字,小明不断提示。这就类似于给定一个数组,里面有序地放着100个元素,分别是1~100,要求小红以二分查找的方式找到小明手里的数字是多少?
针对上面的问题,我们可以一个一个地猜,但是这种方式效率实在是太低。所以我们试试二分查找:
- 小红猜50-----------小明提示“大了”
- 小红猜25-----------小明提示“大了”
- 小红猜13-----------小明提示“大了”
- 小红猜7-------------小明提示“大了”
- 小红猜4-------------小明提示“大了”
- 小红猜2-------------小明提示“小了”
- 小红猜3-------------小明提示“回答正确”
这就是二分查找的整个过程,使用二分查找时,每次都排除一半的数字,逐渐地缩小查找范围,直到找到为止。
二分查找的完整实现
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#define MAXSIZE 10
#define NotFound 0
typedef int ElementType;
typedef int Position;
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
Position last;
};
List ReadInput();
Position BinarySearch( List L, ElementType X );
int main()
{
List L;
ElementType X;
Position P;
L = ReadInput();
scanf("%d", &X);
P = BinarySearch( L, X );
printf("%d\n", P);
system("pause");
return 0;
}
/*建立查找序列*/
List ReadInput()
{
int i, n;
List a; //创建结构体。
scanf("%d", &n);
a = (List)malloc(n * sizeof(struct LNode));
for ( i=1; i<=n; i++ )
{
scanf("%d", &(a->Data[i])); //输入结构体Data的值
}
a->last = n; //结构体成员last赋值
return a; //返回这个结构体,也就是查找序列。
}
/*经典二分查找*/
Position BinarySearch( List L, ElementType X ) {
Position left, right, mid;
left = 1, right = L->last;
while ( left <= right ) { //这里必须是 <= ,否则“偶数个,正中间找到”会报错
mid = (left + right) / 2;
if ( L->Data[mid] == X )
return mid;
else if ( L->Data[mid] > X )
right = mid - 1;
else
left = mid + 1;
}
return NotFound;
}
总结一下
一定要注意,二分查找针对的是一个有序的集合(排好序的数组)。每一次查找就可以排除一半的元素,也就是将查找范围缩小一半。那么对于一个包含N个元素的集合,整个查找过程比较次数大约为log以2为底的N次方。