折半查找即二分查找,前提是序列是有序的,既然二分,时间复杂度O(logn)很容易理解。
C++ STL 二分查找
c++在STL中封装了有关二分的函数:在序列有序的前提下,lower_bound(a, a + n, val)与upper_bound(a, a + n, val),下面就来介绍这两个函数用法。
lower_bound(a, a + n, val)
a:数组名
n:数组长度
val:要查找的值
返回结果:大于等于val的元素地址,否返回最后一个元素下一个位置的地址
应用范例:
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10050;
int a[maxn];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int val;
cin >> val;
cout << lower_bound(a, a + n, val) - a << endl;
return 0;
}
upper_bound(a, a + n, val)
参数规则与lower_bound相同,返回值为大于val元素地址,否则返回最后一个元素下一个位置的地址。
应用范例:
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10050;
int a[maxn];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int val;
cin >> val;
cout << upper_bound(a, a + n, val) - a << endl;
return 0;
}
折半查找/二分查找
我们先采用分治的写法来实现二分:
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10050;
int a[maxn];
int Find(int left, int right, int x)
{
if (right - left > 1)
{
int mid = (right + left) / 2;
if (x == a[mid]) return mid;
if (x > a[mid]) return Find(mid, right, x);
if (x < a[mid]) return Find(left, mid, x);
}
return right;
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int val;
cin >> val;
cout << Find(0, n, val) << endl;
return 0;
}
我们进行分析:时间复杂度:O(logn),空间上递归多次,貌似不是最优,我进来对其空间进行优化。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 10050;
int a[maxn];
int Find_S(int left, int right, int x)
{
int i = left, j = right;
while (i < j)
{
int mid = (i + j) / 2;
if (a[mid] == x) return mid;
if (a[mid] > x) j = mid - 1;
else i = mid + 1;
}
return right + 1;
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++) cin >> a[i];
int val;
cin >> val;
cout << Find_S(0, n - 1, val) << endl;
return 0;
}
这样空间上被优化到了O(1),但是注意,此时的left与right是左闭右闭区间,与之前分治时不同。