怎样写出一个正确的二分搜索
来源:互联网 发布:淘宝的客户关系管理 编辑:程序博客网 时间:2024/05/04 22:38
最近在做二分搜索的题目,可是正如在编程珠玑里面所说的一样,正确的二分搜索只有10%的程序员才能够写出来。
去google搜索了一下:如何写出正确的二分搜索,开头就看见了Hacker News上面的文章:
https://news.ycombinator.com/item?id=1277459
于是花了几个小时研究了一下二分搜索。
1:当然最简单的情形是从给定范围内找到指定的数字,下面我所说的各种情况范围两边都是闭区间的,即[low , high],(范围包括low 和 high)
当你要指定其余查找范围的时候可以很容易的转化为两端闭区间,
如(low, high) -> [low + 1, high - 1] (low, high] -> [low + 1, high] [low, high) -> [low, high + 1]
那么要查找该范围内的,首先[low, high] (当low == high的时候表示只有一个点的区间,low > high的时候表示空区间)
所以我们的循环条件就应该如此写: while (low <= high) (因为是闭区间表示法,不能够写成low < high),当只有一个点的区间查找的时候显然是错误的。
那么查找一个数的二分查找条件就很容易写
当 array[mid] == number_to_find的时候直接返回。
当array[mid] < number_to_find的时候,查找区间就应该更新为low = mid + 1;
当array[mid] > number_to_find的时候,查找区间就应该更新为high = mid - 1;
那么一个简单正确的查找一个数的二分搜索就出来了:
int binarySearchOneNumber(int number_to_find, int low, int high, int *array) { int mid; while (low <= high) { mid = (low + high) / 2; if (array[mid] == number_to_find) { return array[mid]; } else if (array[mid] > number_to_find) { high = mid - 1; } else { low = mid + 1; } } return -1;}
2和3是同样的情况,即有多个满足条件的数,返回最小的那个,或者最大的那个(以数组元素查找为例子,返回数组下标最小的,或者下标最大的)
下标最小的:
循环条件还是不变,因为我们采取的是闭区间的形式为while(low <= high)
那么当找到一个数满足条件的时候,如array[mid] == number_to_find的时候不能够直接返回。因为有可能存在比mid下标还小的,并且元素值等于number_to_find的元素。
所以我们必须更新high。如果high更新为mid的话,即high = mid;会发生死循环。为什么呢?
(1)假设不再存在满足条件的元素了,那么low一定会逐渐向上更新,更新到和high一样的大小,那么此时就会发生死循环。
(2)如果还存在的话,会被继续划分区间,直到划分成[low, high]里面不存在满足条件的元素,根据(1)会发生死循环。
所以我们应该更新high = mid - 1;
low的更新是毫无疑问的low = mid + 1;
那么我们最后应该返回的是什么呢?
假设我们找到了array[mid] == number_to_find,此时更新high = mid - 1,如果mid就是最小元素的话,那么下一次分的时候一定会逐渐的增加low的值,一直到high - 1,发现
array[high - 1]仍然比number_to_find小,low就会更新为high + 1 = mid,即找到的满足条件的下标。
如果还有满足条件元素的话,同理又会在一次找到一个mid,一直找到最小下标,然后再分为没有满足条件的区间,low一定会被更新为满足条件最小元素下标
所以我们最终返回low即可。
代码:
int binarySearchSmallestNumber(int number_to_find, int low, int high, int *array) { int mid; while (low <= high) { mid = (low + high) / 2; if (array[mid] >= number_to_find) { high = mid - 1; } else { low = mid + 1; } } return low;}
同理找到最大元素:
int binarySearchBiggestNumber(int number_to_find, int low, int high, int *array) { int mid; while (low <= high) { mid = (low + high) / 2; if (array[mid] <= number_to_find) { low = mid + 1; } else { high = mid - 1; } } return high;}
顺便说一句:
如果没有找到元素的话,那么找最小下标的二分就会返回一个下标k,此时如果将查找数插入K,并且将array[k], array[k + 1].... array[high]依次向后移动的话仍然是一个有序数组。
同理找最大下标的返回下标K,将array[k], array[k - 1].....array[0]向前移动的话仍然是一个有序数组。
- 怎样写出一个正确的二分搜索
- 90%的计算机专家不能在2小时内写出完全正确的二分搜索算法
- 如何正确的写出二分查找算法
- 如何写出正确的二分查找?
- 编程珠玑读书笔记之------>一个正确的二分搜索代码
- 正确的二分搜索代码
- 二分查找的三个版本,据说90%的计算机专家不能在2小时内写出完全正确的二分搜索算法。
- 写好正确的二分搜索
- 二分搜索的3种正确写法
- “二分查找”——Jon Bentley:90%以上的程序员无法正确无误的写出
- 《编程珠玑》---编写正确的二分搜索程序
- 利用循环不变式写出正确的二分查找及其衍生算法
- 怎样写出较好的代码
- 怎样写出优秀的代码
- 怎样正确构造一个auto_ptr?
- 怎样写一个基本正确的单例模式?
- 二分查找的一个不算完美但正确的写法
- 怎样正确的工作
- 连接4
- 连接5
- java extends 继承的一些小结。
- Eclipse下如何导入jar包
- codeforce 67D - Optical Experiment(dp)
- 怎样写出一个正确的二分搜索
- Antiarithmetic?
- STM32系统时钟的配置
- Android App开发记录—sd Card 读写
- NYOJ 68
- JAVA多线程基础(一)
- LAN9221网卡驱动分析之一 发送数据
- 三大范式
- 一个面试官对面试问题的分析