强大的二分查找法(Binary Search)

今天帮助David 调程序。他在做Windows下程序分析,使用一个数组存放目标程序heap中所有的数据结构(地址和Size),然后扫描该程序全局数据段所有内容,如果某个指针指向的值落在heap中某个数据结构地址范围内,就建立从全局数据段到该数据结构的路径。

David给我演示时, 说运行Toy program 没问题,但运行一个比较大的真实程序时,就会出现性能问题,果然,我们等了二十多分钟,还是没有算完。于是我检查了他的代码,告诉他问题可能出在检查指针是否指向有效数据结构时,他是用的线性查找方法。我说,考虑到他的数组已经排序, 使用二分查找法,会快很多,因为算法复杂度从O(N)降到了O(logN)。没多久,他就写好了新的程序, 他很兴奋地告诉我:同样的大程序,不到一分钟就算好了,而之前的程序需要1个小时才能算完,我再次检查他的程序,发现目标程序比较大时,heap中的数据结构有几千个, 难怪二分查找的性能好如此之多。

我于是想到经典书籍《编程珠玑(Programming Pearls)》, 该书花了大量篇幅来讲二分查找,2, 4, 9, 11, 13章都有直接讲到二分查找,可见二分查找的重要性。第二章有段话精确地描述了我今天碰到的例子:“程序员一开始可使用简单的顺序查找数据结构。顺序查找通常也够快了。如果程序变得太慢了,那么对表进行排序然后使用二分查找往往可以排除这个瓶颈。”

第二章提出了三个典型二分查找问题,问题A如下:“给定一个包含32位整数的顺序文件,它至多只能包含40亿个这样的整数,并且整数的次序是随机的。请查找一个此文件中不存在的32位整数。在有足够主存的情况下,你会如何解决这个问题?如果你可以使用若干外部临时文件但可以用主存却只有上百字节, 你会如何解决这个问题?”

如果我们有足够内存,当然很简单,不需要使用二分查找法。但如果只有上百字节内存, 线性查找就无法使用了。我们使用二分查找,设定2^32 / 2 为中点M(假设都为正整数,无负数),然后遍历文件中所有整数,把大于M的放一个临时文件,小于M的放另一个临时文件,并计算每个文件中整数个数,如果小于2^32 / 2 个,那么该文件的整数中至少有一个漏洞,重复以上过程就能找到一个文件中不存在的32位整数了。二分查找法让这个问题突然变得简单了好多。就如书中所说“看起来很困难的问题解决起来可能很简单,并且还很可能出人意料... ... 只有经过广泛的研究之后才能对算法具备那种出神入化的理解力。 ”

感谢David的程序和《编程珠玑》, 让我对二分查找有了更为深入的理解。

原文地址:https://www.cnblogs.com/guyufei/p/3096902.html