总的来说,分为两大类:顺序容器,关联容器。
顺序容器,在于,元素的位置排序按其添加次序决定的,而与元素本身的值无关。反之,关联容器中元素的位置排序与元素值相关(想想搜索树就知道了,map,set都是基于红黑树的)。
这里先讲顺序容器:vector, list, deque.
vector元素的存放内存是连续的,跟数组类似。因此,可以按照元素之间的间隔n来访问元素,即,假设迭代器iter指向vector(或deque)的第i个元素,则可以用iter+n来访问位置与i距离n的元素。而list却没有此操作,因为元素的位置不连续,只能从头到尾访问。list的迭代器只能自增,并没有+n或者其他运算<,>,<=,>=
vector,deque,list都有push_back()函数,而deque,list更有push_front()函数.vector却没有。只因为连续存放……但是可以用循环来实现push_front()
如下:
<pre name="code" class="cpp">vector<int> vec;
vector<int>::iterator iter = vec.begin();
while(cin>>word)
iter = iter.insert(iter,word);
但是这个代价很昂贵,每插入一个元素,vec里的所有元素都要向后移动一位。此外,这里还要注意,利用insert(iter,element)函数插入时,是在迭代器iter的前面插入element,且返回指向element的迭代器。要充分理解这,可以看下面的代码。
vector<int> v;
for(int i = 1; i < 10;++i)
v.push_back(i);
vector<int>::iterator first = v.begin(), last = v.end();
int j = 11;
while(first != v.end())
{
first = v.insert(++first,j);
++j;
++first;
}
for(vector<int>::iterator iter = v.begin(); iter != v.end();++iter)
cout<<*iter<<" ";
cout<<endl;
这里的输出是:1 11 2 12 3 13 4 14 5 15 6 16 7 17 8 18 9 19
对于元素连续存放,还有一个注意的是,容器的容量!要了解vector的自增:
capacity():当前容器能够存储的元素总数。
reserve(n):表明应该有n个元素的存储空间。
如:
vector<int> vec;
//此时size = 0, capacity= 0
for(int i = 0; i < 24; ++i)
vec.push_back(i);
//此时size = 24, capacity= 32
</pre><pre name="code" class="cpp">vec.reserve(100);
/此时size = 24, capacity= 100
而当size() == capacity()时,若再向容器插入新元素,则标准库会给vec重新开辟新的内存空间,以保证连续存放,把vec原来的全部元素复制到新内存里去,因此为了提高效率,当不得不重新分配内存时,并不是以capacity+1来开辟空间,而是加倍capacity来开辟新空间(目前编译器不同,开辟多少也不同,也不一定是加倍开辟,但是肯定不是+1开辟,哈哈~)。
删除元素:可以用pop_back(), pop_front()(这个只有deque和list有)这俩函数都是void型,无返回值。
清空:clear()
这里要讲的是erase(p):p是指向被删除元素的迭代器。返回被删除元素后面的元素。如果p指向最后一个元素,则返回end(),若p本身指向end(),则该函数未定义(运行出错!)
erase(p,e)删除迭代器p,e所标记的范围内所有元素,返回被删除元素段后面的元素。
vector<int> vec;
for(int i = 1; i < 11; ++i)
vec.push_back(i);
for(vector<int>::iterator iter = vec.begin(); iter != vec.end();++iter)
cout<<*iter<<" ";
cout<<endl;
vector<int>::iterator del = vec.end();
cout<<"删除前del------>"<<*del<<endl;
del = vec.erase(del);
</pre><pre name="code" class="cpp"> cout<<"删除后del------>"<<*del<<endl;
cout<<*vec.end()<<endl;
结果输出
1 2 3 4 5 6 7 8 9 10
删除前del------>842150451这里运行错误,因为del指向了超出元素未端的位置end(),所以erase(del)出错。
如果改成:
vector<int>::iterator del = vec.end()-1;
cout<<"删除前del------>"<<*del<<endl;
del = vec.erase(del);
cout<<"删除后del------>"<<*del<<endl;
cout<<"此时end()指向---->"<<*vec.end()<<endl;
则输出:
1 2 3 4 5 6 7 8 9 10
删除前del------>10
删除后del------>10
此时end()指向---->10
程序运行并未发错误,但是输出却是有问题的。因为end()本来指向超出未端的下一个元素,虽然已删除,但是vector元素连续存放,所以还是输出了10,但是该内存的元素已失效的,删除后del还是指向end(),所以输出了失效的10.
若是list容器,则
list<int> vec;
for(int i = 1; i < 11; ++i)
vec.push_back(i);
for(list<int>::iterator iter = vec.begin(); iter != vec.end();++iter)
cout<<*iter<<" ";
cout<<endl;
list<int>::iterator del = --vec.end(); //这里不能用vec.end()-1,上面已经说了list的迭代器只能自增或自减
cout<<"删除前del------>"<<*del<<endl;
del = vec.erase(del);
cout<<"删除后del------>"<<*del<<endl;
cout<<*vec.end()<<endl;
程序运行未发生错误,输出:
1 2 3 4 5 6 7 8 9 10
删除前del------>10
删除后del------>-842150451
-842150451
而关联容器map也有erase(p),这里要非常的小心,erase(p)无返回值!迭代器p必须指向容器中确定存在的元素,且不能为end();所在,在循环中用map容器的erase(p)时,要注意,这是错误的写法:
map<string,int> m;
for(map<string,int>::iterator iter = m.begin(); iter != m.end();++iter)
{
m.erase(iter);
}
而正确的是:
map<string,int> m;
for(map<string,int>::iterator iter = m.begin(); iter != m.end();)
{
m.erase(iter++);
}
map的内部数据结构是红黑树,也就是二叉平衡树,使用erase删除一个元素后,树需要进行重新调整,因为不同于vector的顺序存储,所以map中erase方法中当前迭代器没有自动指向下一个节点位置,