005-二分搜索-分治法-《算法设计技巧与分析》M.H.A学习笔记
2016-06-27 16:30
260 查看
二分搜索又称折半查找,用于在排序好的序列表中进行搜索,搜索效率高,可在最坏的情况下用O(log n)完成搜索任务。
果x<a[n/2],则我们只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果x>a[n/2],则我们只要在数组a的右
半部继续搜索x。
plain copy
int binSearch(const int *Array,int start,int end,int key)
{
int left,right;
int mid;
left=start;
right=end;
while(left<=right)
{
mid=(left+right)/2;
if(key==Array[mid]) return mid;
else if(key<Array[mid]) right=mid-1;
else if(key>Array[mid]) left=mid+1;
}
return -1;
//找不到就返回-1
}
lower_bound
给定长度为n的单调不下降数列a0,a1,…,an−1和一个数k,求满足ai≥k条件的最小的i。不存在的情况下输出 n。
upper_bound
给定长度为n的单调不下降数列a0,a1,…,an−1和一个数k,求满足ai >k条件的最小的i。不存在的情况下输出 n。
1.
[cpp] view
plain copy
while( rb > lb )
{
int m = (lb + rb) / 2;
if( ok(m) ) rb = m;
else lb = m + 1;
}
// 答案为: lb == rb
2.
[cpp] view
plain copy
while( rb - lb > 1 )
{
int m = (lb + rb) / 2;
if( ok(m) ) rb = m;
else lb = m;
}
// 跳出循环时 lb + 1 == rb
// 答案为 rb<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
[cpp] view
plain copy
// 在arr的[sl, sr)下标范围内查找左起第一个>=target的元素,找到返
// 回所在下标, 否则返回sr(区间最右元素下标+1)
int LowerBound(int *arr, int sl, int sr, int target) {
int l = sl, r = sr - 1, mid;
while (l <= r) {
mid = (l +r) >>1;
if (arr[mid] < target) l = mid + 1;
else r = mid;
}
return (l == r ? r : sr);
}
[cpp] view
plain copy
// 在arr的[sl, sr)下标范围内查找左起第一个>target的元素,找到返
// 回所在下标, 否则返回sr(区间最右元素下标+1)
int UpperBound(int *arr, int sl, int sr, int target) {
int l = sl, r = sr - 1, mid;
while (l <= r) {
mid = (l +r) >>1;
if (arr[mid] <= target) l = mid + 1;
else r = mid;
}
return (l == r ? r : sr);
}
这里的j就是搜索树的高度,即查找的复杂度为O(log n)。
基本思想:
将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果x>a[n/2],则我们只要在数组a的右
半部继续搜索x。
伪代码:
C++代码:
[cpp] viewplain copy
int binSearch(const int *Array,int start,int end,int key)
{
int left,right;
int mid;
left=start;
right=end;
while(left<=right)
{
mid=(left+right)/2;
if(key==Array[mid]) return mid;
else if(key<Array[mid]) right=mid-1;
else if(key>Array[mid]) left=mid+1;
}
return -1;
//找不到就返回-1
}
“最小化最大值”:
这一算法运用在stl的两个函数中:lower_bound
给定长度为n的单调不下降数列a0,a1,…,an−1和一个数k,求满足ai≥k条件的最小的i。不存在的情况下输出 n。
upper_bound
给定长度为n的单调不下降数列a0,a1,…,an−1和一个数k,求满足ai >k条件的最小的i。不存在的情况下输出 n。
C++代码:
两种写法(区别在判断截止的条件,本质上并没有分别):
1.[cpp] view
plain copy
while( rb > lb )
{
int m = (lb + rb) / 2;
if( ok(m) ) rb = m;
else lb = m + 1;
}
// 答案为: lb == rb
2.
[cpp] view
plain copy
while( rb - lb > 1 )
{
int m = (lb + rb) / 2;
if( ok(m) ) rb = m;
else lb = m;
}
// 跳出循环时 lb + 1 == rb
// 答案为 rb<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
贴两个常用的代码:
[cpp] viewplain copy
// 在arr的[sl, sr)下标范围内查找左起第一个>=target的元素,找到返
// 回所在下标, 否则返回sr(区间最右元素下标+1)
int LowerBound(int *arr, int sl, int sr, int target) {
int l = sl, r = sr - 1, mid;
while (l <= r) {
mid = (l +r) >>1;
if (arr[mid] < target) l = mid + 1;
else r = mid;
}
return (l == r ? r : sr);
}
[cpp] view
plain copy
// 在arr的[sl, sr)下标范围内查找左起第一个>target的元素,找到返
// 回所在下标, 否则返回sr(区间最右元素下标+1)
int UpperBound(int *arr, int sl, int sr, int target) {
int l = sl, r = sr - 1, mid;
while (l <= r) {
mid = (l +r) >>1;
if (arr[mid] <= target) l = mid + 1;
else r = mid;
}
return (l == r ? r : sr);
}
浮点数的二分搜索
关键在于截止条件,我们需要比较的是两个数的接近程度而不是大小abs(l-r)>=1e-10,当然我们可以直接指定循环次数,如100次,可以达到2−100≈10−30 的精度范围。二分搜索的算法分析:
书中这一段写得很清楚,就直接截屏了:这里的j就是搜索树的高度,即查找的复杂度为O(log n)。
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- 算法详解之分治法具体实现
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法