STL源码剖析学习之容器

来源:互联网 发布:c语言课程设计贪吃蛇 编辑:程序博客网 时间:2024/05/29 17:28

//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<int> iset;
std::set<int>::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 <iostream>
#include <set>

template<class T>
inline T & GetStdSetElement(std::_Rb_tree_const_iterator<T>  std_set_iterator)
{
    return *(T *)&(*std_set_iterator);
}


int main()
{    
    using namespace std;

    set<int> iset;
    pair< set<int>::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 <set>
#include <map>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

void main()
{
///////////////////////////////set/////////////////////////////////
int i;
int ia[5] = {0, 1, 2, 3, 4};
set<int> iset(ia, ia + 5);

cout << "size = " << iset.size() << endl; //size = 5
cout << "3 count = " << iset.count(3) << endl; //3 count = 1
iset.insert(3);//此语句执行结果无效,因为已有3
cout << "3 count = " << iset.count(3) << endl; //3 count = 1

set<int>::iterator ite1 = iset.begin();
set<int>::iterator ite2 = iset.end();
for (; ite1 != ite2; ++ite1)
{
cout << *ite1;
}
cout << endl; //01234

//使用STL算法find()来搜寻元素,可以有效运作,但不是好办法
ite1 = find(iset.begin(), iset.end(), 1);
if (ite1 != iset.end())
{
cout << "3 found" << endl;
}

//面对关联式容器,应该使用其所提供的find函数来搜寻元素,会比
//使用STL算法find,更有效率,因为STL算法find只是循序搜寻。
ite1 = iset.find(3);
if (ite1 != iset.end())
{
cout << "3 found" << endl;
}

//企图通过迭代器来改变set元素,是不被允许的。

*ite1 = 9; //error, assignment of read-only location


///////////////////////////////////map////////////////////////////////
map<string,int> simap;
simap[string("jjhou")] = 1;
simap[string("jerry")] = 2;
simap[string("jason")] = 3;
simap[string("jimmy")] = 4;

pair<string,int> value(string("david"), 5);
pair<map<string,int>::iterator,bool> IstRt;
IstRt = simap.insert(value);
cout << IstRt.first->first << endl;
cout << IstRt.first->second << endl;

map<string,int>::iterator simap_iter = simap.begin();
for (; simap_iter != simap.end(); ++simap_iter)
{
cout << simap_iter->first << ' ' << simap_iter->second << endl;
}

int number = simap[string("jjhou")];
cout << number << endl;
//面对关联式容器,应该使用其所提供的find函数来搜寻元素,会比
//使用STL算法find,更有效率,因为STL算法find只是循序搜寻。
simap_iter = simap.find(string("jerry"));
if (simap_iter != simap.end())
{
cout << "jerry found" << endl;
}

//simap_iter->first = string("hhhh");  //error
simap_iter->second = 9; //right

getchar();
}
原创粉丝点击