【问题标题】:Binary search using iterators, why do we use "(end - begin)/2"? [duplicate]使用迭代器进行二分搜索,为什么我们使用“(end - begin)/2”? [复制]
【发布时间】:2016-11-28 08:54:54
【问题描述】:

我正在研究迭代器,并且在弄清楚我们为什么要使用迭代器上被困了 3 天:

auto mid = text.begin() + (end - beg) / 2;

代码:

int main()

{
    vector<int> text{ 10,9,8,7,6,5,4,3,2,1 };
    int sought = 3;
    // text must be sorted
    // beg and end will denote the range we're searching
    auto beg = text.begin(), end = text.end();
    auto mid = text.begin() + (end - beg) / 2; // original midpoint
                                               // while there are still elements to look at and we haven't yet found sought
    while (mid != end && *mid != sought) {
        if (sought < *mid) // is the element we want in the first half?
            end = mid; // if so, adjust the range to ignore the second half
        else // the element we want is in the second half
            beg = mid + 1; // start looking with the element just after mid
        mid = beg + (end - beg) / 2;// new midpoint
    }

    system("pause");
}

为什么

auto mid = text.begin() + (end - beg) / 2;

而不是:

auto mid = text.begin() + text.size() / 2;

请帮忙。

【问题讨论】:

  • 我们是否使用“(end - begin)/2”?你在哪里找到的?
  • @Wolf - c++ 入门第 5 版。这有点误导,因为第 3.4 章的书说这是一个“经典算法”,所以我认为这是一种常见的情况(如果我错了,请纠正我)
  • 之所以令人困惑,是因为该示例在 main 函数中实现了二分查找。如果它被正确地提取到一个只需要一个迭代器范围来搜索的函数中,那么为什么你不能在容器上调用 size 就很清楚了——因为你无法引用容器。

标签: c++ algorithm iterator binary-search


【解决方案1】:

二进制搜索传统上是这样写的。这种写作形式有助于编码人员理解二分搜索,因为标准二分搜索中只使用开始、结束、中间。

可以使用size()而不是end-star在循环之前,但是你必须在while循环中使用end-start,因为end-start会改变。您应该避免使用size() 以保持一致性。

【讨论】:

  • 所以它更像是一种形式?
  • @jibzoiderz 可以,但是while循环中的end-start不能修改。
  • 顺便说一下,我个人更喜欢 (beg+end)/2 而不是 beg+(beg-end)/2 ,它既正式又节省代码。
  • 哦,你不应该使用 beg+end ehen beg 和 end 是指针,因为它可能会溢出。
  • 感谢您的提示!
【解决方案2】:

这样做是为了避免在添加两个非常大的整数时可能发生的溢出,其中加法结果可能会变得大于最大整数限制并产生奇怪的结果。

Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken

来自博客:

So what's the best way to fix the bug? Here's one way:
 6:             int mid = low + ((high - low) / 2);

Probably faster, and arguably as clear is:
 6:             int mid = (low + high) >>> 1;

In C and C++ (where you don't have the >>> operator), you can do this:
 6:             mid = ((unsigned int)low + (unsigned int)high)) >> 1;

【讨论】:

  • 指针根本不支持加法;大整数索引很少溢出(数组的大小通常远小于整数的限制)。
  • 好吧,我说的是一种通用技术,与指针无关。问题表明 OP 只是在问为什么不 (beg + end)/2?请阅读我的回答中的链接(谷歌研究博客)以了解更多详细信息。
猜你喜欢
  • 1970-01-01
  • 2017-10-29
  • 2020-10-14
  • 2010-09-15
  • 1970-01-01
  • 2015-01-18
相关资源
最近更新 更多