【问题标题】:Loop condition works well with raw iterator but not with iterator dereferencing循环条件适用于原始迭代器,但不适用于迭代器解引用
【发布时间】:2020-10-22 15:28:00
【问题描述】:

在下面的sn-p中, while(litr < = ritr) 效果很好,但是当尝试搜索向量中不存在的元素时, while(*litr < *ritr) 无法满足并超出范围并崩溃。 我明白,循环可以使用原始迭代器,但为什么迭代器取消引用不能满足循环条件

bool binarySearch(std::vector<int> sorted_list, int item)
{
    if(sorted_list.empty())
    {
        return false;
    }
    
    auto litr = sorted_list.begin();
    auto ritr = sorted_list.end()-1;

    while(litr <= ritr)
    {
        int leftindex = std::distance(sorted_list.begin(), litr);
        int rightindex = std::distance(sorted_list.begin(), ritr);

        int mid = (leftindex + ((rightindex-leftindex)/2));

        if(sorted_list.at(mid) == item)
        {
            return true;
        }

        if(item < sorted_list.at(mid))
        {
            ritr = sorted_list.begin() + mid-1;
        }
        else
        {
            litr = sorted_list.begin()+ mid+1;

        }
    }

    return false;
}

【问题讨论】:

  • 你好。一方面,您想迭代向量while(litr &lt;= ritr) 的其他所有项目。另一方面,您创建一个取决于实际向量值while(*litr &lt; *ritr) 的条件。是什么让您认为第二个版本会起作用?它取决于它们本身的向量值。我并不奇怪这会以糟糕的方式结束。条件完全不同。
  • 你认为扣除是什么意思?你的意思是取消引用?就像 Jean-Marc 评论的那样,while(litr &lt;= ritr)while(*litr &lt; *ritr) 没有任何相似之处
  • 如果item小于sorted_list中最小的item,函数会崩溃,因为ritr会超出sorted_list的范围。你必须在一开始就检查这种可能性。
  • 谢谢。更专注于取消引用部分。所以只是粘贴代码而不进行测试。但我现在明白了,为什么取消引用不起作用。

标签: c++ c++11 while-loop iterator


【解决方案1】:

我不明白您所说的“迭代器推导”是什么意思。我想你的意思是“取消引用”?

无论如何,您询问的是while(litr &lt;= ritr)(有效)与while(*litr &lt; *ritr)(失败)的比较。有几个不同之处。

LessThanOrEqual 与 Equal

工作代码使用&lt;= 而不仅仅是&lt;,正确操作需要等号部分。

考虑一个只有三个元素(0,10,20)的序列,搜索项是20。那么leftindex = 0,mid = 1,rightindex = 2。搜索项大于mid,所以下一个index值是leftindex = 2,rightindex = 2。如果比较中没有equals,则循环到此结束,函数返回false,不正确。循环条件必须为&lt;=,以便循环再次执行并找到该项目。

迭代器比较与取消引用迭代器

当使用&lt;= 作为循环条件时,在某些情况下取消对 end() 迭代器的引用是一个问题。

考虑一个只有两个元素(0, 10)的序列,搜索项是20。那么leftindex = 0,mid = 0,rightindex = 1。搜索项大于mid,所以接下来的值为leftindex = 1,rightindex = 1。在这个循环中,搜索项仍然大于mid,所以接下来的值是leftindex = 2,rightindex = 1。注意leftindex为2,等于end()。如果循环条件使用litr &lt;= ritr,则可以。但如果循环条件使用*litr &lt;= *ritr,则取消引用结束迭代器的尝试是未定义的行为。

begin() 之前的迭代器

和上面类似,考虑一个只有两个元素(0, 10)的序列,搜索项是-10。那么leftindex = 0,mid = 0,rightindex = 1。搜索项小于mid,所以接下来的值为leftindex = 0,rightindex = -1。仅将迭代器设置为此值是未定义的行为。显然,取消引用它也是未定义的行为。

请注意,即使您的“工作”变体while(litr &lt;= ritr) 也存在此问题。您将需要一些其他代码来防止这种情况发生。

其他

您的代码执行auto ritr = sorted_list.end()-1;,因此它假定排序列表中至少有一个元素。您应该修改代码以处理空列表的情况。

【讨论】:

  • 谢谢。明白了。照顾空列表部分。但是,我更专注于解引用部分,并在没有太多测试的情况下粘贴了代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
  • 2017-09-10
  • 2013-09-12
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多