C++ 带迭代器和自定义步长的循环结束条件

C++ 带迭代器和自定义步长的循环结束条件,c++,C++,我正在向以前构建的代码添加一些功能。我必须循环一个列表,这是2个步骤中的一个,并以不同的方式处理元素 这是我的尝试 for(auto list_it = std::next(list.begin()); list_it != list.end() ; std::advance(list_it,2)){ // Do something } 我正在使用next(list.begin())初始化list\u it以指向第二个元素 每次迭代它都会向前移动2个advance(列出它,2)) [

我正在向以前构建的代码添加一些功能。我必须循环一个列表,这是2个步骤中的一个,并以不同的方式处理元素

这是我的尝试

for(auto list_it = std::next(list.begin()); list_it != list.end() ; std::advance(list_it,2)){

   // Do something

}
我正在使用
next(list.begin())初始化
list\u it
以指向第二个元素 每次迭代它都会向前移动2个
advance(列出它,2))

[Q]

我不确定如何测试循环退出条件

列出它!=向前推进2时,如果跳过list.end()
,list.end()可能不起作用


有没有标准的方法来处理这个问题?我可能会检查跳过的迭代器是否为
list.end()
,但我不认为这是一种很好的、可扩展的、步长更大的方法。(除非这是唯一的办法)

您可以更改条件以检查并确保当前迭代器和结束迭代器之间的差异大于步长量。那看起来像

for(auto list_it = std::next(list.begin()); 
    std::distance(list_it, list.end()) > step; 
    std::advance(list_it, step))
{

// Do something
}

您可以更改条件以检查并确保当前迭代器和结束迭代器之间的差异大于步长。那看起来像

for(auto list_it = std::next(list.begin()); 
    std::distance(list_it, list.end()) > step; 
    std::advance(list_it, step))
{

// Do something
}
使用,您可以执行以下操作:

for (auto& e : list | ranges::view::drop(1) | ranges::views::stride(2)) {
    // e
}
使用,您可以执行以下操作:

for (auto& e : list | ranges::view::drop(1) | ranges::views::stride(2)) {
    // e
}

更新:修改通用大小

步进大小k,可以根据C++编译器得到O(n)或O(1)中的列表大小。之后,您可以通过以下方式计算步骤:

  size_t steps_allowed = list.size()/k; 
   // list.size() is O(n) for C++98 and O(1) for standard C++ 11.

然后循环另一个变量
i
,并根据
允许的步数检查
i
内部循环终止条件更新:修改通用大小

步进大小k,可以根据C++编译器得到O(n)或O(1)中的列表大小。之后,您可以通过以下方式计算步骤:

  size_t steps_allowed = list.size()/k; 
   // list.size() is O(n) for C++98 and O(1) for standard C++ 11.

然后在另一个变量
i
上循环,并根据
允许的步骤检查
i
,内部循环终止条件,您不能通过
.end()
迭代器。您必须使用计数器或检查所有中间迭代器。例如:

template<class It>
void checked_advance(It& it, It last, std::size_t n) {
    while (n-- > 0 && it != last)
        ++it;
}

assert(!list.empty());
for (auto it = std::next(list.begin()); it != list.end(); 
     checked_advance(it, list.end(), step)) {
    // ...
}
模板
提前检查无效(It&It,It最后一次,标准::大小){
而(n-->0&&it!=最后一个)
++它;
}
断言(!list.empty());
for(auto-it=std::next(list.begin());it!=list.end();
已选中_advance(it,list.end(),step)){
// ...
}

您不能前进通过
.end()
迭代器。您必须使用计数器或检查所有中间迭代器。例如:

template<class It>
void checked_advance(It& it, It last, std::size_t n) {
    while (n-- > 0 && it != last)
        ++it;
}

assert(!list.empty());
for (auto it = std::next(list.begin()); it != list.end(); 
     checked_advance(it, list.end(), step)) {
    // ...
}
模板
提前检查无效(It&It,It最后一次,标准::大小){
而(n-->0&&it!=最后一个)
++它;
}
断言(!list.empty());
for(auto-it=std::next(list.begin());it!=list.end();
已选中_advance(it,list.end(),step)){
// ...
}


您不能跳过
list.end()
,这将是未定义的行为。是的。我正在努力防止这种情况发生。检查一下:iter!=list.end()&(iter+1)!=list.end()?这应该行得通。@E.N.D,
std::next(iter)
而不是
iter+1
。列表迭代器不是随机访问。您不能跳过
List.end()
,它将是未定义的行为。是的。我正在努力防止这种情况发生。检查一下:iter!=list.end()&(iter+1)!=list.end()?这应该行得通。@E.N.D,
std::next(iter)
而不是
iter+1
。列表迭代器不是随机访问。它看起来像是
O(N)
遍历现在是
O(N^2)
@Evg
O(2N)
否?我将当前迭代器向前推进两次,而不是每次都从头开始。但是
std::distance
也必须遍历列表。在每一步中,它都进行
O(N)
迭代。@Evg是的,但它是从
list\u遍历它的
,所以你只做
step
遍历。@Evg哎呀,没关系,我明白了。我还是把它留作一个选项,它看起来像
O(N)
遍历现在是
O(N^2)
@Evg
O(2N)
否?我将当前迭代器向前推进两次,而不是每次都从头开始。但是
std::distance
也必须遍历列表。在每一步中,它都进行
O(N)
迭代。@Evg是的,但它是从
list\u遍历它的
,所以你只做
step
遍历。@Evg哎呀,没关系,我明白了。我仍然将它作为一个选项
std::next(列出它)!=list.end()
不会有任何帮助,因为你增加了
std::advance(list\u it,2)
循环将终止,因为当增加2时,
list\u it
将落在
list.end()
上,不是吗?它可以,或者它可能已经超过了末尾。请记住,OP是在寻找一个通用的解决方案,而不仅仅是步骤是
2
。哎呀,让我将其修改为通用的解决方案。在标准C++11中,
std::list::size()
O(1)
std::next(list_it)!=list.end()
不会有任何帮助,因为你增加了
std::advance(list\u it,2)
循环将终止,因为当增加2时,
list\u it
将落在
list.end()
上,不是吗?它可以,或者它可能已经超过了末尾。请记住,OP是在寻找一个通用的解决方案,而不仅仅是步骤是
2
。哦,让我修改它为通用的解决方案。在标准C++11中,
std::list::size()
O(1)
。很有趣。现在我将坚持使用标准库。不过,我现在还是坚持使用标准库