//STL之容器
//学习目的:各个容器的使用。
/*
容器分为:序列式容器和关联式容器。
序列式容器:array, vector, list, deque
关联式容器:set, map, multiset, multimap
vector的数据安排以及操作方式,与array非常相似两者唯一的差别在于,array是静态空间,一旦配置了就不能改变,想要扩充,一切琐碎得由客户端自己来:首先,配置新空间,然后将元素从旧址一一搬往新址,再释放旧空间;vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。
list不再能够像vector一样以普通指针作为迭代器,因为其节点不保证在存储空间中连续存在。list有一个
重要性质:插入操作和结合操作都不会造成原有的list迭代器失效。这在vector是不成立的。list不仅是一个
双向链表,而且还是一个环状双向链表。
deque是由一段一段的定量连续空间构成。一旦有必要在deque的前端或尾端增加新空间,便配置一段定量
连续空间,串接在整个deque的头端或尾端。deque的最大任务,便是在这些分段的定量连续空间上,维护其
整体连续的假象,并提供随机存取的接口。避免了“重新配置、复制、释放”的轮回,代价则是复杂的迭代器
架构。deque的实现代码分量远比vector或list都多得多。
综述:
vector、list、deque中只有vector存在容量限制,因为它是单向且内存连续数据结构,因此,只有它有容量的限制,超出容量就必须经过“重新配置、复制、释放”的轮回。内存都换地了,当然以前使用的迭代器就都失效了。能非常好的支持随即存取,即[]操作符。
list:本身内存就不连续,因此不会存在容量一说。不支持随即存取。
deque:逻辑或表面上看着是连续内存空间,但实际上是由一段一段的定量连续空间组成,因此,也不存在容量限制。支持随即存取。
关联式容器:
所谓关联式容器,观念上类似关联式数据库(实际上则简单许多):每笔数据(每个元素)都有一个键值(key)和一个实值(value)。当元素被插入到关联式容器中时,容器内部结构(可能是RB-tree,也可能是hash-table)便依照其键值大小,以某种特定规则将这个元素放置于适当位置。关联式容器没有所谓头尾(只有最大元素和最小元素),所以不会有所谓push_back()、push_front()、pop_back()、pop_front()、begin()、end()这样的操作行为。
set的特性是,所有元素都会根据元素的键值自动被排序。set的元素不像map那样可以同时拥有实值(value)和
键值(key),set元素的键值就是实值,实值就是键值,set不允许两个元素有相同的键值。
我们可以通过set的迭代器改变set的元素值吗?不行,因为set元素值就是其键值,关系到set元素的排列规则。
如果任意改变set元素值,会严重破坏set组织。因此set是const_iterator。(map能修改实值,不能修改键值)
set拥有与list相同的某些性质:当客户端对它进行元素新增操作和删除操作时,操作之前的所有迭代器,
在操作完成之后都依然有效。(同样试用于map)
map的特性是,所有元素都会根据元素的键值自动被排序,map的所有元素都是pair,同时拥有实值和键值。
pair的第一元素被视为键值,第二元素被视为实值。map不允许两个元素拥有相同的键值。map被称为映射表,
或称为字典(取“字典之英文单字为键值索引”之象征)。
//本程序代码来源《STL源码剖析》
*/
//使用set应注意的事项
std::set iset;
std::set::iterator it = iset.insert(4).first;
(*it)++; // error. 原因:std::set的迭代器不能修改对应的元素.
//语法上不会报错,程序中也可以修改,但会破坏有序性,set可能表现出非预期的行为
这是因为:
std::set的特点是:
1. 对于插入、删除和查找操作,
set保证其时间复杂度都是O(log n);
2. set是一个有序的、可以前向和后向遍历的容器(双向迭代器);
3. set是一个元素类型和比较函数可以配置的容器,但是一经配置,就不可更改;
4. set的元素可以插入、删除,但是不可更改。
set在任何时刻都是一个有序的结构,而一旦破坏这个有序性,set可能表现出非预期的行为。为了保证set的概念完整性,C++STL厉
行规定了3和4两个限制,在绝大部分情况下,这两个限制是合理的。
但是,当我在set里面存的是shared_ptr元素时, 根本无所谓有没有序. 我就是要通过迭代器获取元素的非const引用. 解决如下:
#include
#include
template
inline T & GetStdSetElement(std::_Rb_tree_const_iterator std_set_iterator)
{
return *(T *)&(*std_set_iterator);
}
int main()
{
using namespace std;
set iset;
pair< set::iterator, bool> res = iset.insert(4);
int & i = GetStdSetElement(res.first);
i++;
cout << *( iset.begin() ) << endl;
return 0;
}
//下面是一个set和map的测试程序
//file:5set-test.cpp
#include
#include
*ite1 = 9; //error, assignment of read-only location
///map
map simap;
simap[string("jjhou")] = 1;
simap[string("jerry")] = 2;
simap[string("jason")] = 3;
simap[string("jimmy")] = 4;
pair value(string("david"), 5);
pair