概述
STL容器类
- 【1】 序列式容器
- 1.vector
- 2.deque
- 3.list
- 【2】适配器容器
- stack
- queue
- priority_queue
- 【3】关联式容器
- 1.set,unordered_set,multiset
- 2. map,unordered_map,multimap
- 3.pair make_pair
- 4.四种智能指针
- unique_ptr
- shared_ptr
- weak_ptr
【1】 序列式容器
vector与deque的迭代器支持算术运算,list的迭代器只能进行++/–操作,不支持普通的算术运算。
1.vector
引用头文件<vector>用于存储连续的元素,数组,定义一维数组,如下,
vector<int> pos(32, -1);//定义32个字符
vector<char> a(32);
a.pop_back();
a.push_back(0);
首先这是动态的,非常灵活。储存的时候是连续的线性空间,支持高效的随机访问和在尾端插入/删除操作,但其他位置的插入/删除操作效率低下。
class Vector
{
public:
iterator start;
iterator begin(){return start};
//目前使用了的空间头
iterator finish;
iterator end(){return finish};
//目前使用了的空间的尾
size_type size(){ return size_type(end-start);}
reference front() {return *begin();}
reference back(){return *(end()-1);}
iterator end_of_storage; //目前可用空间的尾
bool empty(){return begin()==end();}
}
当我们用push_back插入的时候,会检查 还有没有备用的空间 ,如果没有的话
要经历allocator先按规则分配空间 然后把之前的拷贝过去, 再插入,最后释放原来的空间 这是一个庞大的工程
分配空间的规则
{
如果原本大小为0
分配空间为1;
else
分配空间为=原来的*2;
}
2.deque
引用头文件<deque>,双端队列
我们知道连续内存的容器不能随意扩充,因为这样容易扩充别人那去。deque却可以,它创造了内存连续的假象。其实deque由一段一段构成 ,他是分段连续,而不是内存连续 当走向段的尾端时候自动跳到下一段 所以支持迭代器++ 操作,自动跳到下一段的方法由operator++实现。deque每次扩充 则申请一个段,双端队列底层是一段假象的连续空间,实际是分段连续的,“整体连续”的假象。可以头插和尾插,也可以弹出队首和队尾。
b.push_front(0);
b.push_front(0);
b.pop_back();
b.pop_front();
如果只是简单的存储元素使用vector就可以了,如果对元素任意位置进行插入或者删除操作比较多,则使用list即可,所以一般很少使用deque;deque的最大应用,就是用其作为标准库中stack和queue的底层结构。
3.list
引用头文件<list>,list底层是一个带头节点的双向循环链表,任意位置插入和删除时间复杂度0(1)。
【2】适配器容器
stack
引用<stack>,栈,先进后出,stack(栈)是一种后进先出的数据结构 ,最后加入栈的元素将最先被取出来,在栈的同一端进行数据的插入与取出,这一段叫做“栈顶”。由于栈只是进一步封装别的数据结构,并提供自己的接口,所以代码非常简洁,如果不指定容器,默认是用deque来作为其底层数据结构,stack(栈)的常用操作:top(),push(elem),pop(),empty(),size();
queue
引用<queue>,队列,先进先出,queue(队列)也是一种逻辑数据结构,其具有先进先出的特性,只能在队的前端进行删除, 在队的后端进行插入。queue也可以看成是容器的容器,内部是使用其它容器来存放具体数据,然后加限制,使得我们的数据操作只能是在头或尾。从尾部添加数据,从头部取数据,从而实现FIFO的特性。同stack一样,内部默认数据存放容器为deque,若要用非默认容器初始化,必须要在模板中指定容器类型。
priority_queue
引用<ueue>,具有优先级的队列,在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。底层数据结构通常采用堆数据结构来实现。
模版原型:priority_queue<T,Sequence,Compare>
priority_queue<int, vector<int>, greater<int>> c;
实现优先级队列的底层容器,默认是vector;
第三个参数是c++比较函数。默认情况下是less;
【3】关联式容器
1.set,unordered_set,multiset
集合(set)是一种包含已排序对象的关联容器,不允许有重复元素。无序集合(unordered_set)则元素不重复且无序。set(<set>)和unordered_set(<unordered_set>)底层分别是用红黑树和哈希表实现的。multiset(<set>)它可以保存重复的元素,这些数据有序。这意味我们总可以插入元素,当然必须是可接受的元素类型。默认用 less 来比较元素,但也可以指定不同的比较函数。
红黑树:
优点:很多操作在lg(n)的时间复杂度下就可以实现,因此效率非常的高
缺点: 空间占用率高,因为每一个节点都需要额外保存父节点、孩子节点和红/黑性质,使得每一个节点都占用大量的空间
红黑树,Red-Black Tree 「RBT」是一个自平衡(不是绝对的平衡)的二叉查找树(BST),树上的每个节点都遵循下面的规则:
性质1:每个节点要么是黑色,要么是红色。
性质2:根节点是黑色。
性质3:每个叶子节点(NIL)是黑色。
性质4:每个红色结点的两个子结点一定都是黑色,没有两个相邻的红色节点(并没有说不能出现连续的黑色节点)
性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
平衡二叉树
平衡二叉树,又称AVL树,指的是左子树上的所有节点的值都比根节点的值小,而右子树上的所有节点的值都比根节点的值大,且左子树与右子树的高度差最大为1。因此,平衡二叉树满足所有二叉排序(搜索)树的性质。插入和删除节点需要重新平衡,主要有四种调整方式:LL(左旋)、RR(右旋)、LR(先左旋再右旋)、RL(先右旋再左旋)。
哈希表:
优点:查找速度非常的快
缺点: 哈希表的建立比较耗费时间
哈希表
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
不管hash函数设计的如何巧妙,总会有特殊的key导致hash冲突,特别是对动态查找表来说。
hash函数解决冲突的方法有以下几个常用的方法
1.开放定制法
2.链地址法
3.公共溢出区法
建立一个特殊存储空间,专门存放冲突的数据。此种方法适用于数据和冲突较少的情况。
4.再散列法
准备若干个hash函数,如果使用第一个hash函数发生了冲突,就使用第二个hash函数…
typedef struct
{
char* Key;
char* Value;
hash_node* next;
}hash_node;//节点
typedef struct {
int size;
int count;
hash_node* node;
}hash_table;//表
2. map,unordered_map,multimap
map(<map>)是STL的一个关联容器,一对多映射,基于关键字快速查找,不允许重复值,对象是模板类,需要关键字和存储对象两个模板参数,其中第一个参数称为关键字,每个关键字只能在map中出现一次;第二个参数称为该关键字的值,可理解为“{键,值}对” 。map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。
unordered_map(<unordered_map>)则是无序的,unordered_map内部实现了一个哈希表(也叫散列表,通过把关键码值映射到Hash表中一个位置来访问记录,查找的时间复杂度可达到O(1),其在海量数据处理中有着广泛应用)。
multimap(<map>) 容器保存的是有序的键/值对,但它可以保存重复的元素。multimap 中会出现具有相同键的元素序列,它们会被添加到容器中。
map、set、multiset、multimap这四种关联容器是有序的。有序的含义是它们按照顺序进行存储。
3.pair make_pair
std::pair主要的作用是将两个数据组合成一个数据,两个数据可以是同一类型或者不同类型。pair是将2个数据组合成一个数据,例如stl中的map就是将key,value放在一起来保存。当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first,second 因为是使用struct不是class,所以可以直接使用pair的成员变量。
template pair make_pair(T1 a, T2 b)
{
return pair(a, b);
}
我们可以使用pair的构造函数也可以使用make_pair来生成我们需要的pair。 一般make_pair都使用在需要pair做参数的位置,可以直接调用make_pair生成pair对象。
vector<pair<int, int>> p(10,make_pair<int, int>(45, 99));
cout << p[0].first << endl;//first得到pair的第一个值
cout << p[9].second << endl;//second得到第二个值
4.四种智能指针
C++ 标准模板库 STL(Standard Template Library) 一共给我们提供了四种智能指针:(<memery>)auto_ptr、unique_ptr、shared_ptr 和 weak_ptr,其中 auto_ptr 是 C++98 提出的,C++11 已将其摒弃,并提出了 unique_ptr 替代 auto_ptr。auto_ptr的缺点是:存在潜在的内存崩溃问题。
unique_ptr
实现独占式拥有或严格拥有概念,保证同一时间内只有一个智能指针可以指向该对象。它对于避免资源泄露。
shared_ptr
实现共享式拥有概念。多个智能指针可以指向相同对象,该对象和其相关资源会在“最后一个引用被销毁”时候释放。从名字share就可以看出了资源可以被多个指针共享,它使用计数机制来表明资源被几个指针共享。可以通过成员函数use_count()来查看资源的所有者个数。除了可以通过new来构造,还可以通过传入auto_ptr, unique_ptr,weak_ptr来构造。当我们调用release()时,当前指针会释放资源所有权,计数减一。当计数等于0时,资源会被释放。shared_ptr 是为了解决 auto_ptr 在对象所有权上的局限性(auto_ptr 是独占的), 在使用引用计数的机制上提供了可以共享所有权的智能指针。
weak_ptr
一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内存管理的是那个强引用的 shared_ptr. weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr 设计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。weak_ptr是用来解决shared_ptr相互引用时的死锁问题,如果说两个shared_ptr相互引用,那么这两个指针的引用计数永远不可能下降为0,资源永远不会释放。它是对对象的一种弱引用,不会增加对象的引用计数,和shared_ptr之间可以相互转化,shared_ptr可以直接赋值给它,它可以通过调用lock函数来获得shared_ptr。
最后
以上就是怕孤独流沙为你收集整理的C++学习笔记-STL标准模板库(二)STL容器类【1】 序列式容器【2】适配器容器【3】关联式容器的全部内容,希望文章能够帮你解决C++学习笔记-STL标准模板库(二)STL容器类【1】 序列式容器【2】适配器容器【3】关联式容器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复