学过数据结构的人都应该知道二分查找算法,n个数据线性查找不不得花费(n/2)的时间,而二分查找可以在log(n)次数内完成,在对巨量的数据进行处理的时候,这种方法应该是神来之笔!其实在我门生活中无处不存在二分思想到处可见,记得有个猜数据的游戏,告诉你 数字的范围,让你在规定的次数内将数据猜出,比如1000以内的数据,你肯定首先会猜500,别人说底了,你肯定又会说250.......如果n=1000最多猜10次就可以猜到数据!
下面引入编程珠玑第二章的第一个问题:
给定一个包含32位整数的顺序文件,你至多只能够包含40亿个这样的数字,并且整数的次序是随机的,请查找一个此文件中不存在的32位整数(至少必有一个遗漏,为什么?)在有足够的主存情况下,你会如何解决?如果你可以使用若干外部临时文件但主存却只有百字节,你会如何处理这个问题?
首先解决这个问题: 至少必有一个遗漏,为什么,很容易(pow(2,32) > 40亿的,所以肯定是有遗漏!
首先我不引入他的算法,我首先将问题简化,假定一个范围内的数n个数,现在有n-1个数,而且不重复,要你找出这个数.我会有几种想法
1 将n-1个数进行排序,然后一一对照,直到找到不对应的为止
2 将这个范围内的数想加减去那n-1个数的和
在n很小的时候,而且内存足够的情况下,1,2方法都是可以的,特别是2可以在o(n)的时间内找到,但是对于作者提出的问题就显得很无奈了1进行排序的时间太长,查找的时间也很长 2虽然不要进行排序,也不要进行比较但是当数据很大的时候,必须自己写超精度的加减法,时间和空间复杂度都会增加,在有几个临时文件,几百个字节的条件下似乎很难找到时间和空间都满意的方法,看看作者怎么做的把!
"我们应该使用一个至少包含一个遗漏数据的序列作为范围,实际上我们是使用包含所有整数的文件来表示范围.关键在于我们可以通过计数中点上下元素个数的方法来探测某一范围;上下范围至多包含总范围内的元素的一半.因为总范围有一个元素遗漏,所以较小的一半范围内必定包含遗漏元素.这些就是对二分查找算法的大部分要素."
其实二分思想在编程应用方面是很广的,求根程序使用的是二分查找,通过连续插入中间值的方式求解一元方程;她的其他用法还有树数据结构以及程序调试.从这些例子中的每一个都可以看出,可将每个程序看作是对基本二分法的润色.这样就为我们程序员提供了一种"万金油"算法.
以前看书看过人工神经网络是"万金油",今天又碰到了一个"万金油"算法.可见他的应用之广和作用之大,博大啊!
下面是我用二分算法得到的求数的平方根的代码:
#include " stdlib.h "
#include " math.h "
#define errorNum 10e-7
int isFind( double low , double high, double parent)
{
double middleValue = (low + high) / 2.0 ;
if ( fabs (middleValue * middleValue - parent) < errorNum )
return 0 ;
else if ( middleValue * middleValue > parent)
return 1 ;
else if ( middleValue * middleValue < parent )
return - 1 ;
}
double sqrtOfNum( double number)
{
double high = number ;
double low = 0 ;
while ( 1 )
{
if ( isFind (low,high,number) == 0 )
return (low + high) / 2.0 ;
else if ( isFind (low,high,number) == - 1 )
low = (low + high) / 2.0 ;
else
high = (low + high) / 2.0 ;
}
}
int main ()
{
double number ;
printf( " please input the number : " );
scanf( " %lf " , & number);
printf( " the sqrt of %g is %g " ,number,sqrtOfNum(number));
printf( " sqrt(number) is %g " ,sqrt(number));
return 0 ;
}