1.猜数
(以下故事纯属虚构,如有雷同,不胜荣幸)
小海:“小涵,你现在心里想一个1000以内的数,信不信我最多只要问你十个问题,我就能猜出这个数是什么?”
小涵:“真的么? 我不信。”
小海:“不信? 那就来试一试怎么样?”
小涵:“哟,还来劲了,来啊。”
小海:“那现在给你十秒钟时间想这个数字。”
小涵:“.......(沉默)”
小海:“10,9,8,...”
小涵:“别点啦,我已经想好了。”
小海:“这么快啊,不多想会儿? 不然等下你又说我作弊。”
小涵:“我.......(-_-||),快点开始吧。”
小海:“OK,那现在开始了,你想的数比500大吗?”
小涵:“嗯,对,比500大。”
小海:“嗯,那好,这个数比750大吗?”
小涵:“没有。”
小海:“比625大吗?”
小涵:“没有呢。”
小海:“比562大吗?”
小涵:“没有,你怎么老是问同样的问题,能不能换个有趣一点的。”
小海:“这个问题怎么就无趣了,继续,这个数比531大吗?”
小涵:“没有,你不能换个有新意的问法吗? emmmmm”
小海:“奥,要有新意啊,那这个数比428加87更大吗?”
小涵:“这。。。428加87.......,我...,等我算一下。”
小涵:“428加87等于515,比515更大,你还是用原来的问法吧。-_—”
小海:“哈哈哈哈哈哈,你不是要有趣的问法吗,那这个数比523大吗?”
小涵:“这个叫有趣...(小声),额,没有,比523更小。”
小海:“昂,就要接近真像了,这个数比519更大吗?”
小涵:“嗯嗯,比他更大。”
小海:“这个数有比521更大吗?”
小涵:“不会做真的能猜出来吧。。。(心想),嗯,没。”
小海:“这个数有比520更大吗?”
小涵:“没有。(假装镇定)”
小海:“奥,这样啊。这个数是520”
(场面突然升温)
小涵:“嗯呢,(3秒的沉默),520。”
(小海凝望着小涵)
小海:“怎么样,我厉害吧。”
小涵:“(石化4秒)?????????????????? 我 ..... , 你....(老娘话都到这儿了,你........)”
小海:“嘿嘿,想学吗??”
小涵:“(死亡微笑)再见。”
(小涵转身走了)
小海:“嗯? 喂! 不学就不学呗,干嘛走啊??? 我是说错了什么吗???(默默追上了小涵)”
......
.....
....
...
2.情侣的毁灭能手:二分
不管你信不信,上面小海跟小涵玩的小游戏就是二分查找的核心。
在这个游戏中,小涵心中想的数其实就是我们要在有序数字序列中查找的x,而小海说的1000内任意数字其实就是序列的长度。
这个算法的核心思想就是不断地用当前序列区间中点的值value与x比较,若x比中间值value大,则在当前区间的右半区间继续查找x,否则在当前区间的左半区间查找,直到x被找出来。
每一次操作,都能减少当前区间一半的查找量。 这样也就使得查找的效率大大提高。
举个栗子:
假设有序数字序列a为: 1 5 14 21 29 31 34 35
需要查找的数x为: 14
假设该数字序列下标从1开始,则序列区间为[1,8]
设l为区间左端点,r为区间右端点。
初始情况l = 1, r = 8,中点mid = (l+r)/ 2 = (1+8)/ 2 = 4 (C语言中用int直接取整)
将中点的值a[mid] = a[4] = 21 与 x = 14进行对比
x < a[mid] 成立
则在当前区间的左半边进行查找,令l = l = 1,r = mid-1 = 3
那现在的区间是[1,3]
序列为:1 5 14
重复上述过程
mid = (l+r) / 2 = (1+3) / 2 = 2
a[mid] = 5
x = 14
x < a[mid] 不成立
x > a[mid] 成立
所以令l = mid + 1 = 3, r = r = 3
新缩小后的区间为[3,3]
序列为:14
mid = (l+r) / 2 = (3+3)/2 = 3
a[mid] = 14
x = 14
x < a[mid] 不成立
x > a[mid] 不成立
x == a[mid] 成立
令position = mid = 3
所以最后寻找得到x的位置是3
3.C语言代码
#include<stdio.h>
int main()
{
int a[100],i,x,n;
scanf("%d",&n);
for(i = 1; i <= n; i++)
scanf("%d",&a[i]);
scanf("%d",&x);
int l = 1,r = n,mid,pos = -1;
do{
mid = (l+r)/2; //序列下标中点计算
if(x < a[mid])
r = mid-1; // 缩小区间,在当前区间左边查找
else if(x > a[mid])
l = mid+1; //在当前区间右边查找
else { //找到就退出循环
pos = mid;
break;
}
}while(l <= r);
if(pos == -1)printf("Not find!
"); //pos初始化的时候是-1,如果该变量没有被改变过,则序列中没有这个元素
else printf("position is %d
",pos);
return 0;
}
该程序的输入是序列长度n,有序序列a,以及待查元素x。