C++迭代器详解:左闭右开原则
C++迭代器详解:左闭右开原则
一、前言
在学习C++编程时,特别是处理LeetCode算法题时,经常会遇到使用STL库中的迭代器来处理各种问题。本文将详细讲解迭代器中的左闭右开原则,帮助读者更好地理解和应用这一重要概念。
二、什么是左闭右开?
如何理解开闭区间
开闭区间是一个数学概念,开区间使用符号小括号表示,闭区间使用符号中括号表示。闭区间包含了两个端点,而开区间则不包含两个端点。
示例:
一共四种情况:
(a,b):区间范围内,不包含a和b
[a,b]:区间范围内,包含a,也包含b
(a,b]:区间范围内,不包含a,包含b
[a,b):区间范围内,包含a,不包含b
如何理解左闭右开
左闭右开是一种区间表示方式,例如在整数上[3,6)表示3,4,5三个数。闭代表取值取到那个数,开代表取值取不到那个数。通常我们在程序中常听到的概念是左闭右开,也就是含左不含右,最常用的就是C++中的迭代器它采取的就是左闭右开策略。
左闭右开的好处
对于一个左闭右开区间[l,r)来说:
能表示单独一个数
若区间内只有一个数我们可以用像[1,2)表示1,注意[x,x]不符合数学上区间的定义(左区间比右区间大)便于统计区间内个数
r 减 l 正好是区间内元素的个数,对于左闭右闭区间来说 r-l+1 才是区间内元素便于表示空集
空集可以用[x,x)表示便于切割区间
例如我们要在区间内找到一个切割点 x,并把 x 左边归为一个区间,x 和 x 右边归为一个区间则切割后的区间就可以用 [l,x) 和 [x,r) 表示和数组下标相匹配
对于一个从0开始的长度为n的数组来说,[0,n)正好表示这个数组的所有下标,如果用闭区间则要用[0,n-1]来表示
三、iterator迭代器中的左闭右开原则
原理理解
在C++中,容器(如string, vector, set, map等)的迭代器都遵循左闭右开的原则。也就是说,对于任何容器c,c.begin()返回的迭代器指向容器的第一个元素,而c.end()返回的迭代器指向容器的“尾后”元素,也就是最后一个元素的下一个位置。
所以,c.end()不指向任何有效元素,不能解引用得到元素,通常只作为范围结束的标志。
例如,下面的代码是遍历一个vector的标准方法:
int main()
{
vector<int> v1 = { 1,2,3,4,5 };
vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
return 0;
}
在这个例子中,v.begin()返回的迭代器指向第一个元素1,v.end()返回的迭代器指向尾后位置。我们一直迭代到it等于v.end()时停止,这时it已经不再指向任何有效元素。这就是左闭右开原则在C++容器中的应用。
应用
根据上面原则的理解,我们可以得出结论:在任何容器中(如string, vector, set, map等),只要调用的函数应用了iterator迭代器,它就会遵循左闭右开原则。
下面我们将会以常见的reverse反转函数在string容器中举例验证左闭右开原则
根据左闭右开原则,进行反转字符串
int main()
{
string s("hello !!");
// 满足左闭右开原则
reverse(s.begin(), s.begin() + 5);
cout << s << endl;
}
根据上面的图例,我们发现在 reverse(s.begin() , s.begin()+5 ) 中 ,满足左闭右开原则,[begin , begin+5) ,实际反转的只有下标为 0 - 4 的 hello
四、常考面试题
题目:反转字符串中的单词
链接:反转字符串中的单词
class Solution {
public:
string reverseWords(string s) {
size_t i = 0;
size_t size = s.size();
while (i < size)
{
size_t bs = s.find(' ', i);
if (bs != string::npos)
{
// 满足左闭右开的原则
reverse(s.begin() + i, s.begin() + bs);
i = bs + 1;
}
else
{
reverse(s.begin()+ i, s.end());
break;
}
}
return s;
}
};
五、总结
本文详细介绍了C++迭代器的左闭右开原则,从数学概念到实际应用,层层递进,帮助读者深入理解这一重要概念。希望本文能帮助读者更好地掌握C++编程技巧。