相信熟悉C++的同学们都知道STL这个东西,我们平时在用的时候十分的方便,因为人家给我们封装好了,那我们作为正在学习C++的同学,是可以去手动实现一些STL中的容器和算法,这样可以达到锻炼自己编码能力的效果,并且这个过程中还可以熟悉数据结构,千万不要小看这个,虽然是在重复造轮子,但是只有通过造轮子,我们才能深入底层知识,这样大家的编程路才可以走得远。
简单复习以下STL的核心技术,泛型编程,这个十分重要,泛型编程的出现让程序员可以通过只写一次代码实现多种类型的通用模板,这样可以大大的提高代码的重复使用率,因为代码量较大,所以代码部分我放在我个人的github的代码仓库,因为时间较短,所以我只是先实现了list容器还有两个简单的算法。
代码链接
这个list容器内部我实现了迭代器,这样的话我们也可以通过C++11的新特性增强for来遍历容器更加方便。
接下来我来说一下实现迭代器的思路:
大家首先要先明白迭代器是什么意思,我们知道各种STL中的容器的实现方式都是不同的,就拿list来说,这是一个双向链表容器,那我们该如何拿到这个容器中内部的元素呢?我们只能用这个容器的开发者给我们提供的接口来访问,但是这个容器的开发者只给我们提供了front()和back()这两个函数来访问list的头部和尾部,显而易见,这并不能满足我们的需求,我们的想要可以访问该容器中的所有元素,这时候如果我们不熟悉该容器的内部结构,显然这个需求是难以实现的,并且开发者并不是只写了这一个容器,还有其他容器,如果这样的话,那我们的学习成本会非常高,并且容易出错,这时候迭代器的作用就出现了,首先迭代器是一个类对象,也就是说迭代器我们将他抽象成了一个类,这个类的对象指向该容器的元素,我们可以直接通过迭代器去访问这个容器内部的元素,并且就算是不同的容器我们对外提供相同名称的接口,这样使用者就只需要知道这些接口就可以访问到内部元素,并且迭代器对象可以像指针一样进行++或者--的操作,这样我们就不需要知道这个容器内部如何实现,只需要知道这些接口就可以去访问到内部元素了,这样就更加方便用户去操作这个容器了。
关于迭代器类型
迭代器类型非常简单,就只有四种
iterator 正向非常迭代器,支持读写操作
const_iterator 正向常迭代器,只支持读操作
reverse_iterator 反向非常迭代器,也是支持读写操作,就是遍历时候顺序和正向的相反
reverse_const_iterator 反向常迭代器,支持读操作
所有容器的对象都会对外提供以下接口
begin() 返回正向非常迭代器,指向容器的第一个元素
begin() const 返回正向常迭代器
end() 返回正向非常迭代器,指向该容器的最后一个元素的下一位
end() const 返回返回正向常迭代器
rbegin() 返回反向非常迭代器 指向最后一个元素
rend() 返回反向非常迭代器 指向第一个元素的前一位
以下的代码演示以下怎么使用迭代器访问元素
#include <vector>
#include <iostream>
using namespace std:
int main() {
vector<int> v;
for (int i = 0; i < 10; ++i) {
v.push_back(i); // 插入元素
}
// 遍历元素
// iterator 迭代类是容器的内置类 使用::访问
vector<int>::iterator it = v.begin();
// 迭代器可以直接使用== 或者!= 判断是否相等
// 并且在使用迭代器的时候可以像指针一样的操作
for (; it != v.end(); ++it){
cout << *it << endl;
}
// 优化上面的写法
for (auto& val : v) {
cout << val << endl;
}
return 0;
}
我上面用了两种遍历的方式,其中第二种了解C++11的同学应该不陌生,事实上,第二种写法的底层原理就是第一种写法,我们在自己实现的容器中只要有实现了begin()和end()函数,那么我们写的容器可就可以支持这样的写法了,更加清爽!