跳转二进制搜索有直观的解释吗?

时间:2019-05-13 08:17:13

标签: c++ arrays binary-search

我正在阅读《竞争程序员手册》:https://cses.fi/book/book.pdf

在第32页及以上(PDF pp 42)上,提到了二进制搜索方法2,我不确定我是否完全理解。然后,他们对其稍加修改以找到最小值,以使函数ok()为true,然后尝试在数组中找到最大值。我不直观地了解这里发生了什么。有什么直观的解释吗?

int k = 0;
for (int b = n/2; b >= 1; b /= 2) {
    while (k+b < n && array[k+b] <= x) k += b;
}
if (array[k] == x) {
    // x found at index k
}

找到适用于ok函数的最小值

int x = -1;
for (int b = z; b >= 1; b /= 2) {
    while (!ok(x+b)) x += b;
}
int k = x+1;

找到先增大然后减小的函数的最大值

int x = -1;
for (int b = z; b >= 1; b /= 2) {
    while (f(x+b) < f(x+b+1)) x += b;
}
int k = x+1;

1 个答案:

答案 0 :(得分:1)

书中的解释非常好!我将以它们为起点。

假设您有一本字典,在第一页(int k = 0;)上打开它,然后在字典(x)中寻找单词。

不变的假设是:

    字典中的
  1. 单词按不降序排列(对于每个i,0 <{i <narray[i-1] <= array[i]),
  2. 您当前在上找到的单词array[k])永远不会比您在上找到的单词array[k] < = x始终为真)。

b是您对答案有多少页的猜测。在二进制搜索中,您总是会猜测最大可能距离的一半。最初,最大可能的距离是字典n的长度。因此,最初,您将字典长度的一半作为猜测-int b = n/2;

只要可以,即只要满足假设2,就将当前位置k移到页面b的猜测数之前。然后您再次猜测,将猜测距离b减半。

b变为1时,您已经在所需的字典中找到该页面。 array[k] == x-词典包含页面k上的单词,或者词典中没有此类单词。


后面带有!ok(x+b)f(x+b) < f(x+b+1)的示例与带有array[k+b] <= x的示例基本相同。

想象一下,您有一个数组,其中包含!ok(i)array[i]的所有可能值(或f(i) < f(i+1)array[i]的所有可能值)。然后,以与array相同的方式对array[k+b] <= x进行二进制搜索。

请注意,该书假定ok(i)f(i)适用于任何i,而数组大小是有限的,必须检查:k+b < n,其中{{1 }}是数组大小。


请注意本书中的代码样式:

在竞争性编程中,您只有很有限的时间来解决大量算法问题,并且再也不需要看代码,因此可以使用短变量名,不加注释等形式。许多n指令-例如参见https://gist.github.com/kodekracker/e09f9d23573f117a5db0

我知道这可能会令人惊讶。在长期专业项目的世界中,为了实现速度而以极大的可读性交易代码是不可接受的。