标准模板库(STL)是用于C ++编程语言的软件库,影响了C ++标准库的许多部分。它提供了六个组件,称为算法(alorithms),容器(containers),迭代器(iterators),仿函数(functions),配接器(adapters)和配置器(allocators)。STL提供了一组C ++的常用类,例如容器和关联数组,可以与任何内置类型一起使用,并且支持用户自定义类型的一些基本操作(如复制和分配)。 STL算法独立于容器,最后在以"胶合剂“(iterator)将它们粘合在一起,这显着降低了库的复杂性。
由http://www.cplusplus.com/reference/vector/vector/我们可以获得Vector的接口,在模拟实现之前,首先要对各个接口有详细的认识,所以今天就来熟悉各个接口的使用。
下面是各个接口:
在代码中应用这些接口:
void TestVector()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
Print1(v1);
Print2(v1);
Print3(v1);
cout <<"the size of v1 is "<< v1.size() << endl;
vector<int> v2(5, 2); //存入5个2
Print1(v2);
v2.pop_back();
Print1(v2);
cout << "the size of v2 is " << v1.size() << endl;
}
由于系统中没有提供打印接口,这就需要我们手动写一个;
//普通迭代器--可读可写
void Print1(vector<int>& v)
{
vector<int>::iterator it = v.begin();
while (it != v.end())
{
cout << *it << " "; //读
++it;
//cout << ++(*it) << " "; //写,每个值都加1
//++it;
}
cout << endl;
}
在上述代码中我们用到了迭代器,已经知道迭代器是STL的一个接口。
迭代器的模式定义为:提供一种方法,使之能够依序访问某个聚合物(容器)所含的各个元素,而又无需暴露该聚合物的内部表达式。
iterator迭代器称为普通迭代器,意味着我们可以对它进行读写操作(通过operator*和operator++实现),但是有时候我们要求不能对数据进行修改,这时候就就需要const_iterator,只能读不能写,同样的,根据需求不同,还有reverse_iterator(反向迭代器)和const_reverse_iterator,顾名思义,反向迭代器就是逆序遍历,具体是怎样实现的我们在模拟实现iterator再进行学习。
//const迭代器--只能读
void Print2(const vector<int>& v)
{
vector<int>::const_iterator it = v.begin();
while (it != v.end())
{
cout << *it << " ";
++it;
//cout << (*it)++ << " "; //写入会失败
//++it;
}
cout << endl;
}
//反向迭代器/const反向迭代器--逆序遍历
void Print3(const vector<int>& v)
{
vector<int>::const_reverse_iterator it = v.rbegin();
{
while (it != v.rend())
{
cout << *it << " ";
++it;
//cout << ++(*it1) << " "; //不能修改
//++it1;
}
}
cout << endl;
}
运行结果:
接下来看看resize:Change size (public member function)这个接口:这个接口是对当前元素个数进行修改
如果n小于当前的容器大小,则将内容减少到其前n个元素,删除超出(并且销毁它们)的元素。
如果n大于当前的容器大小,则根据需要插入要达到n的元素来扩展内容。 如果指定了val,则新元素将被初始化为val的副本,否则它们被初始化。
如果n也大于当前的容器容量,则会自动重新分配已分配的存储空间。
void TestResize()
{
vector<int> v1;
for (size_t i = 0; i < 10; i++)
{
v1.push_back(i);
}
Print1(v1);
v1.resize(6);
Print1(v1);
v1.resize(9, 10);
Print1(v1);
v1.resize(20);
Print1(v1);
}
reserve:Request a change in capacity(public member function)
如果n大于当前向量容量,则该函数使容器重新分配其存储空间,将其容量增加到n(或更大)。在所有其他情况下,函数调用不会导致重新分配,并且向量容量不受影响。此功能对矢量大小没有影响,不能更改其元素。
void TestReserve()
{
vector<int> v1;
for (size_t i = 0; i < 10; i++)
{
v1.push_back(i);
}
cout << v1.size() << endl;
cout << v1.capacity() << endl;
v1.reserve(20); //将容量扩展到20
cout << v1.capacity() << endl;
v1.reserve(2); //2<20,但是容量不会减小
cout << v1.capacity() << endl;
}
要访问容器中的数据除了我们最开始用到的迭代器,我们还可以使用operator[] 这个接口,通过索引的方式对数据进行访问,它的底层实现就是通过重载“[ ]”来达到下标访问的目的。类似的成员函数vector :: at具有与此运算符函数相同的行为,除了vector :: at被绑定检查,并通过抛出out_of_range异常来指示请求的位置是否超出范围。所以,在使用时一定要注意边界,否则很容产生越界问题。
void TestIndex()
{
vector<int> v1(10); //10个为0的初始化数据
for (size_t i = 0; i < 10; i++)
{
v1[i] = i + 1; //对数据元素进行修改
cout << v1[i] << ' ';
}
cout << endl;
}
insert 有多个接口,这为我们插入数据提供了极大的方便。
void TestInsert()
{
vector<int> v1(5, 1); //11111
vector<int>::iterator it = v1.begin();
it = v1.insert(it, 2); //211111
v1.insert(it, 2, 3); //33211111
it = v1.begin();
vector<int> v2(2, 4); //44
v1.insert(it + 2, v2.begin(), v2.end()); //3344211111
int v3[] = { 5, 6, 7 };
v1.insert(v1.begin(), v3, v3 + 3); //5673344211111
it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
}
vector还有很多的接口,但是其中有很多再以前的学习中都已经接触过,所以没有必要在进行解释。我们也可以以同样的方法模拟学习list,deque等。
接下来是对list中的几个接口的应用
splice:将元素从x转移到容器中,将它们插入位置。具体怎么转移要看传递的参数
1.将x的所有元素传输到容器中。
2.只将i指向的元素从x传送到容器。
3.将范围[起始位置,终止位置)从x传送到容器。
list<int> l1, l2;
list<int>::iterator it;
for (int i = 0; i < 4; ++i) // l1: 0 1 2 3 4
l1.push_back(i);
for (int i = 1; i < 5; ++i) // l2: 100 200 300 400
l2.push_back(i * 100);
it = l1.begin(); // points to 1
++it;
l1.splice(it, l2); // l1: 0 100 200 300 400 1 2 3
Print1(l1);
l2.splice(l2.begin(), l1, it); //l2: 1
Print1(l2);
it = l1.begin();
++it;
l1.splice(l1.begin(), l1, it, l1.end());// l1: 100 200 300 400 1 2 3 0
Print1(l1);
unique:去重。不过要注意的是只有重复的元素是相邻的去重才会有效
void TestUnique()
{
list<int> l1;
l1.push_back(1);
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
l1.push_back(4);
l1.push_back(4);
l1.push_back(5);
Print1(l1);
l1.unique();
Print1(l1);
}