1.vector底层实现
其底层数据结构是动态数组,由于数组的特点,vector也具有以下特性:
1、O(1)时间的快速访问;
2、顺序存储,所以插入到非尾结点位置所需时间复杂度为O(n),删除也一样;
通过这 3 个迭代器,就可以表示出一个已容纳 2 个元素,容量为 5 的 vector 容器。
- _Myfirst 和 _Mylast 可以用来表示 vector 容器中目前已被使用的内存空间;
- _Mylast 和 _Myend 可以用来表示 vector 容器目前空闲的内存空间;
- _Myfirst 和 _Myend 可以用表示 vector 容器的容量。
扩容规则
当我们新建一个vector的时候,如std::vector vec,会首先分配给他一片连续的内存空间,再通过vec.push_back()向其中增加元素. 当初始分配空间已满,就会引起vector扩容, 默认容量是0, 之后插入按照1 2 4 8 16 倍扩容。GCC是二倍扩容,VS13是1.5倍扩容。扩容后是一片新的内存,需要把旧内存空间中的所有元素都拷贝进新内存空间中去,之后再在新内存空间中的原数据的后面继续进行插入构造新元素,并且同时释放旧内存空间,并且,由于vector 空间的重新配置,导致旧vector的所有迭代器都失效了。
注意:
这种格式不被允许,当vector被初始化时,未访问的空间不能进行复制操作,以免超出系统内部分配的空间而出现问题。
void vector_test() {
vector<int> vec;
vec.push_back(2);
vec.push_back(6);
vector<int>::iterator it;
for (int i = 0;i < 5;i++) vec[i] = i;
cout << vec[5] << endl;
}
2.deque底层实现
vector容器是单向开口的连续内存空间,deque 则是一种双向开口的连续线性空间。所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,vector 容器也可以在头尾两端插入元素,但是在其头部操作效率奇差。
deque与vector一样,底层实现是数组。和 vector 容器采用连续的线性空间不同,deque 容器存储数据的空间是由一段一段等长的连续空间构成,各段空间之间并不一定是连续的,可以位于在内存的不同区域。
void deque_test() {
deque<int> deq;
deq.push_back(56);
deq.push_front(8);
deq.pop_back();
deq.pop_front();
deque<int> deq2(5, 8); // 赋初值5个8
for (deque<int>::iterator it = deq2.begin(); it != deq2.end();it++) {
cout << *it << endl;
}
deque<int>::iterator it = deq.begin();
deq.insert(it, 5, 45);
cout << deq.at(1) << endl; // deq.at()与deq[]的区别在于可以检查是否越界
deq.clear();
}
3.map底层实现
map的底层实现采用的就是一种非常高效的平衡检索二叉树:红黑树完成的。
ps:multimap允许同一个键,不同的值存在。
关于红黑树的详细解说:
void map_test() {
map<int, string> person;
person.insert(pair<int, string>(1, "555"));
person.insert(map<int, string>::value_type(6, "96"));
person[21] = "sdja";
pair <map< int, string > ::iterator, bool > insert_pair;
insert_pair = person.insert(map<int, string>::value_type(5, "415"));
if (!insert_pair.second)
cout << "insert eror" << endl;
map<int, string>::iterator iter;
iter = person.find('1');
if (iter != person.end()) {
cout << "find the dic" << endl;
person.erase(iter);
}
else {
cout << "find error" << endl;
}
person.erase(person.begin(), person.end());
}
4. list底层实现
由于 list 容器的元素并不是连续存储的,所以该容器迭代器中,必须包含一个可以指向 list 容器的指针,可以双向的操作容器内的数据。
void list_test() {
list<int> li;
li.push_back(5);
li.push_front(6);
list<int>::iterator it;
for (it = li.begin();it != li.end();it++) {
cout << int(*it) << endl;
}
li.reverse();
li.clear();
}
5.set底层实现
set作为一个容器是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。
ps:multiset允许容器里面存储的值重复。
set的底层实现是通过红黑树完成的。
void set_test() {
set<int> s;
s.insert(5);
s.insert(8);
s.insert(96);
int max_value = s.max_size();
int begin = *s.begin();
int end = *s.end();
s.clear();
set<int>::iterator it;
}