在经过各种STL算法(例如std :: nth_element和std :: sort)的模板定义之后,您必须找到它们的模板定义,该模板定义由类型为Random-access Iterator的对象组成。那么,它们是什么?为什么要使用它们?
随机访问迭代器是C++标准库中存在的五种主要迭代器之一,其他类型是Input迭代器, Output迭代器, Forward迭代器和Bidirectional迭代器。
随机访问迭代器是一种迭代器,可用于在相对于它们所指向的元素的任意偏移位置访问元素,并提供与指针相同的功能。就功能而言,随机访问迭代器是最完整的迭代器。所有指针类型也是有效的随机访问迭代器。
要注意的是,像vector,deque这样的容器都支持随机访问迭代器。这意味着,如果我们为它们声明普通迭代器,则这些迭代器将是随机访问迭代器,就像在list,map,multimap,set和multiset的情况下,它们是双向迭代器。
因此,从上述层次结构可以说,随机访问迭代器是所有迭代器类型中最强的。
显着特征
- 可用性:随机访问迭代器可用于多遍算法中,即涉及在不同遍中多次处理容器的算法。
- 相等/不相等比较:可以将随机访问迭代器与另一个迭代器进行相等性比较。由于迭代器指向某个位置,因此这两个迭代器仅在指向相同位置时才相等,否则就不相等。
因此,如果A和B是随机访问迭代器,则以下两个表达式有效:
A == B // Checking for equality A != B // Checking for inequality
- 取消引用:可以将随机访问迭代器同时作为rvalue和lvalue进行解引用。
// C++ program to demonstrate Random-access iterator #include
#include using namespace std; int main() { vector v1 = {10, 20, 30, 40, 50}; // Declaring an iterator vector ::iterator i1; for (i1=v1.begin();i1!=v1.end();++i1) { // Assigning values to locations pointed by iterator *i1 = 7; } for (i1=v1.begin();i1!=v1.end();++i1) { // Accessing values at locations pointed by iterator cout << (*i1) << " "; } return 0; } 输出:
7 7 7 7 7
因此,正如我们在此处看到的那样,我们既可以访问迭代器,也可以为其分配值,因此,迭代器是一个随机访问迭代器。
- 可递增的:可以对随机访问迭代器进行递增,以便使用运算符++()引用序列中的下一个元素,如前一代码所示,其中i1在for循环中递增。
因此,如果A是随机访问迭代器,则以下两个表达式有效:
A++ // Using post increment operator ++A // Using pre increment operator
- 可减少的:就像我们可以将运算符++()与随机访问迭代器一起使用来增加它们一样,我们也可以减少它们。
// C++ program to demonstrate Random-access iterator #include
#include using namespace std; int main() { vector v1 = {1, 2, 3, 4, 5}; // Declaring an iterator vector ::iterator i1; // Accessing the elements from end using decrement // operator for (i1=v1.end()-1;i1!=v1.begin()-1;--i1) { cout << (*i1) << " "; } return 0; } 输出:
5 4 3 2 1
因为,我们从向量的结尾开始,然后通过递减指针而朝起点移动,这表明递减运算符可与此类迭代器一起使用。
- 关系运算符:虽然,双向迭代器无法与=等关系运算符一起使用,但是层次结构中较高的随机访问迭代器支持所有这些关系运算符。
If A and B are Random-access iterators, then A == B // Allowed A <= B // Allowed
- 算术运算符: -等方面的关系运算符一样,他们也可以用算术运算运算符如+,使用。这意味着随机访问迭代器可以在两个方向上移动,也可以太随机地移动。
If A and B are Random-access iterators, then A + 1 // Allowed B - 2 // Allowed
// C++ program to demonstrate Random-access iterator #include
#include using namespace std; int main() { vector v1 = {1, 2, 3, 4, 5}; // Declaring first iterator vector ::iterator i1; // Declaring second iterator vector ::iterator i2; // i1 points to the beginning of the list i1 = v1.begin(); // i2 points to the end of the list i2 = v1.end(); // Applying relational operator to them if ( i1 < i2) { cout << "Yes"; } // Applying arithmetic operator to them int count = i2 - i1; cout << "\ncount = " << count; return 0; } 输出:
Yes count = 5
在这里,由于i1指向起点,而i2指向终点,因此i2会大于i1,并且它们之间的差就是它们之间的总距离。
- 使用偏移量解除引用运算符([]):随机访问迭代器支持偏移量解除引用运算符([]),该运算符用于随机访问。
If A is a Random-access iterator, then A[3] // Allowed
// C++ program to demonstrate Random-access iterator #include
#include using namespace std; int main() { vector v1 = {1, 2, 3, 4, 5}; int i; // Accessing elements using offset dereference // operator [ ] for(i=0;i<5;++i) { cout << v1[i] << " "; } return 0; } 输出:
1 2 3 4 5
- 可交换的:这些迭代器指向的值可以交换或交换。
实际实施
了解了它的功能之后,了解它的实际实现也非常重要。如前所述,随机访问迭代器可用于所有目的和每种情况。以下STL算法显示了其实际实现之一:
- std :: random_shuffle:众所周知,该算法用于随机地重排容器中存在的所有元素。因此,让我们看一下它的内部工作原理(不要只关注可以在其中使用随机访问迭代器的地方):
// Definition of std::random_shuffle() template void random_shuffle(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& gen) { iterator_traits::difference_type i, n; n = (last - first); for (i=n-1; i>0; --i) { swap (first[i],first[gen(i+1)]); } }
在这里,我们可以看到我们使用了随机访问迭代器,因为没有其他类型的迭代器支持算术运算运算符,这就是我们使用它的原因。
实际上,如果您正在考虑使用随机访问迭代器,则可以使用随机访问迭代器来代替任何其他类型的迭代器,因为它是C++标准库中最强大和最佳的迭代器类型。