C++ STL学习之一:STL概况

0. STL综述

STL(Standard Template Library)C++模板库,该书剖析的是SGI版本的STL,是GNU C++的标准库。

STL的价值:1.带给我们一套极具实用价值的零部件,一集一个整合的组织。2.STL带给我们一个高层次的,已泛型思维为基础的,系统化的,条理分明的“软件组件分类学”。

STL六大组件:

1.容器(vector, list, deque, set, map)

2.算法(function template)

3.迭代器:容器与算法之间的交合剂,即所谓的“泛型指针”。

4.仿函数

5.配接器,如queue, stack,priority_queue。

stack、queue、priority_queue 都不支持任一种迭代器,它们都是容器适配器类型,stack是vector/deque/list对象创建了一个先进后出容器;queue是用deque或list对象创建了一个先进先出容器;priority_queue是用vector/deque创建了一个排序队列,内部用二叉堆实现。

6.配置器:负责空间配置与管理。


关系:容器通过空间配置器取得数据存储空间,算法通过迭代器存取容器内容,仿函数可以协助算法完成不同的策略变化,配接器可以修饰或套接仿函数。

1.STL配置器

SGI设计了双层级配置器,第一级配置器直接使用malloc()和free(), 第二级配置器则视情况采用不同的策略: 当配置区块超过128byte时,市值为足够大,便调用第一级配置器,当配置区块小雨128byte时,视之为过小,为了降低额外负担, 便采用更复杂的memory pool整理方式.

2.STL迭代器

迭代器:提供一种方法,使之能够依序寻访某个聚合物(容器)所含的各个元素, 而又无需暴露该聚合物的内部表述方式.
迭代器是一种智能指针. 迭代器最重要的编程工作就是对operator*和operator->进行重载. (可参考智能指针的实现.)
迭代器的相应型别: value type, difference type,reference type, pointer type, iterator_catetory.(迭代器的实现需要好好研究研究.)(个人感觉STL的精髓是迭代器)

3.容器

 

3.1序列式容器
序列式容器: array(C++内建), vector, heap(以算法形式呈现), priority-queue(带权值的队列), list, slist(非标准), deque(双端队列), stack(配接器), queue(配接器);
关联式容器:RB-tree(非公开), set, map, multiset, multimap, 非标准的(hashtable, hash-set, hash-map, hash-multiset, hash-multimap)
vector与array的最大区别,vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素。
注意:对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了,这是程序员容易犯的一个错误。
vector的元素操作:push_back, pop_back(将尾端元素拿掉, 并调整大小), erase(清除[first, last)中的所有元素), clear(全部清除, 直接调用erase), insert(可能引起内存的重新分配) 
list: STL list是一个双向链表,迭代器具有前移,后移的能力。
list重要性质: 插入操作和接合操作不会造成原有list迭代器失效
SGI list不仅是一个双向链表,而且还是一个环状双向链表。
常用的list元素操作:push_front(j前插), push_back(后插), erase(移除迭代器所指节点), pop_front(前弹), pop_back(后弹), clear(清空), remove(移除数值为value的节点), unique(移除连续而且相同的元素), splice(接合), merge(将x合并到*this身上, 两个lists的内容都必须先经过递增排序), reverse(逆向重置), sort(list不能使用STL算法的sort, 必须使用自己的sort函数).
deque是一种双向开口的连续线性空间。所谓双向开口,意思是可以再头尾两端分别做元素的插入和删除操作。
deque和vector的最大差异,一是在于deque允许常数时间内对起头端进行元素的插入或移除操作, 二是在于deque没有所谓的容量观念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。
deque的各种运算效率都比较差,应尽可能选择使用vector,而不用deque。尤其是排序。 
deque的各种操作(pop_back, pop_front, clear, erase, insert等)
stack是一种先进后出的数据结构,它只有一个出口,stack允许新增元素,移除元素,取得最顶端元素,但是,除了最顶端外,没有任何其他方法可以存取stack的其他元素,也就是说,stack不允许有遍历行为
将元素推入stack的操作称为push, 将元素推出 stack的操作称为pop。
stack采用deque或list实现。(因此stack是一种配接器,而非container) 
stack没有迭代器。
queue是传统的队列,先进先出,从最底端加入,最顶端取出。queue也不允许有遍历行为。
 将元素推入queue的操作称为push, 将元素推出 queue的操作称为pop。
queue采用deque或list实现。(因此queue是一种配接器,而非container) 
queue没有迭代器。
heap并非STL容器组件,但是其为priority queue的助手。二叉最大堆是priority queue的底层机制。
二叉堆就是一中完全二叉树。完全二叉树可以用一个序列表示。(因为当一个完全二叉树的某个节点位于array的i处, 其做节点必位于array的2i出,其右子节点必位于array的2i+1处,其父节点必位于i/2处。)采用vector作为heap的底层数据结构。
heap算法: push_heap,  pop_heap,  sort_heap, make_heap(这里需要再看看)
heap没有迭代器, 不能遍历heap。
priority_heap是一个拥有权值观念的queue, 自动依照元素的权值排列;利用一个max_heap实现,也就是采用vector表现的完全二叉树实现。   

(1)vector向量相当于一个数组

    在内存中分配一块连续的内存空间进行存储。支持不指定vector大小的存储。STL内部实现时,首先分配一个非常大的内存空间预备进行存储,即capacity()函数返回的大小,当超过此分配的空间时再整体重新放分配一块内存存储,这给人以vector可以不指定vector即一个连续内存的大小的感觉。通常此默认的内存分配能完成大部分情况下的存储。

   优点:(1) 不指定一块内存大小的数组的连续存储,即可以像数组一样操作,但可以对此数组进行动态操作。通常体现在push_back() pop_back()

         (2) 随机访问方便,即支持[ ]操作符和vector.at()

         (3) 节省空间。

   缺点:(1) 在内部进行插入删除操作效率低。

         (2) 只能在vector的最后进行push和pop,不能在vector的头进行push和pop。

         (3) 当动态添加的数据超过vector默认分配的大小时要进行整体的重新分配、拷贝与释放

(2)list 双向链表

    每一个结点都包括一个信息快Info、一个前驱指针Pre、一个后驱指针Post。可以不分配必须的内存大小方便的进行添加和删除操作。使用的是非连续的内存空间进行存储。

   优点:(1) 不使用连续内存完成动态操作。

        (2) 在内部方便的进行插入和删除操作

        (3) 可在两端进行push、pop

   缺点:(1) 不能进行内部的随机访问,即不支持[ ]操作符和vector.at()

         (2) 相对于verctor占用内存多

(3) deque   双端队列 double-end queue

   deque是在功能上合并了vector和list。

   优点:(1) 随机访问方便,即支持[ ]操作符和vector.at()

         (2) 在内部方便的进行插入和删除操作

         (3) 可在两端进行push、pop

   缺点:(1) 占用内存多

使用区别:

     1)如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector(可以作为priority_queue,stack的底层实现)

     2)如果你需要大量的插入和删除,而不关心随机存取,则应使用list(stack,queue的底层实现)

     3)如果你需要随机存取,而且关心两端数据的插入和删除,则应使用deque


3.2关联式容器
关联式容器:所谓关联式容器就是说每个元素都有一个键值(key)和一个实值(value)。当元素被插入到关联式容器中时,容器内部结构(RB-tree, hash-table)便依照其键值大小,以某种特定规则将这个元素放置于适当位置。关联式容器没有所谓的头尾(只有最大元素和最小元素),因此没有所谓的push-back,push-front, pop-back, pop-front, begin, end这样的行为。

标准的STL关联式容器分为set和map,以及这两类的衍生体,multiset和multimap, 这些容器的底层机制都是RB-Tree。STL提供了非标准的关联式容器 hash table。

这部分关键看AVL-tree和RB-Tree(再看看原理和实现

AVL Tree要求任何节点的左右子树高度相差最多1.

红黑树要求满足的规则:
1. 每个节点不是红色就是黑色。
2.根节点为黑色。
3. 如果节点为红色,其子节点必须为黑色。
4.任一节点到NULL的任何路劲,所含黑节点必须相同。

set元素的key就是value,value就是key。不可以通过set的迭代器改变元素的value。map可以。 

 map的特性是,所有元素都会根据元素的键值自动排序,map的所有元素都是pair,同时拥有value和key, pair的第一个元素被视为key,第二元素被视为value。map不允许两个元素拥有相同的key。

这六大组件的交互关系:container(容器) 通过 allocator(配置器) 取得数据储存空间,algorithm(算法)通过 iterator(迭代器)存取 container(容器) 内容,functor(仿函数) 可以协助 algorithm(算法) 完成不同的策略变化,adapter(配接器) 可以修饰或套接 functor(仿函数)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值