STL数据结构总结

文章目录

        • 【1】vector
        • 【2】list
        • 【3】deque
        • 【4】stack
        • 【5】queue
        • 【6】heap
        • 【7】priority_queue
        • 【8】slist
        • 【9】关联式容器
        • 【10】rb_tree 红黑树
        • 【11】set
        • 【12】map
        • 【13】multiset
        • 【14】mutimap
        • 【15】hashtable
        • 【16】hashset
        • 【17】hash_map
        • 【18】hash_multiset
        • 【19】hash_multiset

大体记录一下STL数据结构基本原理。

【1】vector

连续性空间。

【2】list

非连续性空间,双向环形链表,在最后加上一个空白节点;

【3】deque

队列,双端开口都可操作的连续性空间。如需要配置新的空间那么会在头端或者尾端配置一段定量连续空间,维护其整体连续的假象;由一段一段的定量连续空间构成;
一旦有必要在deque的前端或尾端增加新空间,便配置一段定量连续空间,串接在整个deque的头端或尾端。deque的最大任务,便是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的接口。避开了“重新配置、复制、释放”的轮回,代价是复杂的迭代器架构。
在deque里面维护了一个连续的空间存放指针map中控器(二级指针),然后这些指针指到不同的也不连续的空间。
STL数据结构总结_第1张图片
STL数据结构总结_第2张图片
STL数据结构总结_第3张图片
在删除的时候 erase:
如果删除段的前面元素较少则将前面较少的段向后移动,如果后面段较少就将后面段向前移动,这样就保证了每次移动的距离是最少的。
STL数据结构总结_第4张图片
STL数据结构总结_第5张图片
在插入的时候 insert:
1.如果在最前,则调用push_front();
2.如果在最后,则调用push_back();
3.否则,和删除一样判断前后哪个部分较小则将小的部分向大的部分移动,但是之前需要插入一个值用来存储新元素,一般是push_front(front()),或者push_back(back())。

【4】stack

是一种先进后出的数据结构,不允许有遍历。
STL数据结构总结_第6张图片
stack 严格意义上来说不算容器,因为它的实现是基于其他容器的基础之上的,就是修改了接口。
看其定义:
STL数据结构总结_第7张图片
在构造的时候可以指定底层容器,默认的情况下是deque作为底层容器,如下例子底层容器是list。
STL数据结构总结_第8张图片

【5】queue

队列,先进先出,底端加入,顶端取出,不允许遍历。
STL数据结构总结_第9张图片
与stack类似,底层容器都是用其他实现的,缺省情况下用的是deque。如构造代码如下,可以指定容器的类型:

STL数据结构总结_第10张图片STL数据结构总结_第11张图片

【6】heap

堆,用最大推(完全平衡二叉树)实现。任然是一个连续的数组,只不过内部元素顺序的构成是完全二叉树的形式插入的。heap是跟节点的大小永远大于子节点。
排序:sort_heap 排序完是从小到大。将最大的数(跟节点)提取出来放到最后,然后–last,继续堆化求最大值。
STL数据结构总结_第12张图片
节点的插入,如插入50:
STL数据结构总结_第13张图片
如果用vector去初始化的话,就可以扩充heap。如果是array初始化,之后扩充的话就是不合法挨打heap。
STL数据结构总结_第14张图片
STL数据结构总结_第15张图片

【7】priority_queue

底层实现是max_heap,默认底层容器是queue,push_back()之后,然后利用max_heap重排vector。

【8】slist

是一个单向链表。对比于list的双向循环链表会失去很多功能但是所耗用的空间更小。
基于同样的效率考虑,slist不提供push_back(),只提供push_front()。因此slist的元素次序会和元素插入进来点次序相反,也就是头插法。

begin(): return head.next()
end(): iterator(0),最后应该是空的
STL数据结构总结_第16张图片
size(): __slist_size(head.next()),这个说明了head节点不存储数据
交换链表的话就是将两个链表的head相互交换即可。
front(): return head.next()->data;
push_front(): 从头部插入,使其成为slist的第一个元素。注意没有push_back()。
pop_front(): 从头部删除元素。

【9】关联式容器

类似与关联式数据库,每个元素都有一个键值key 和一个实值value。当元素被插入到关联式容器中时,容器内部结构(可能是RB-tree,也可能是hash-table)便依照其键值大小,以某种特定规则将这个元素放置于适当位置。关联式容器没有所谓的头和尾,也就意味着不会有push_back(),和push_front()之类的。
STL数据结构总结_第17张图片

【10】rb_tree 红黑树

有一个header节点指向root节点,mostleft是最左边的节点也是最小的值,mostright是最右边的节点也就是最大值。

【11】set

stl的set底层原理是用rb_tree来实现的,所以set的操作行为基本都是rb_tree来实现的。当然SGI也有用hash table来实现过的那种叫hash set。由于set是去重复的,所以在insert的时候是用的insert_unique()。当然也有允许用重复值的set叫mutiset这个就是用rb_tree的insert_equal()。

注意:set 的迭代器是不可用来改变数值的,因为在代码实现的时候 iterator被定义为了 const iterator。
在这里插入图片描述

【12】map

map的特性是,所有元素都会根据元素的键值自动排序。map的所有元素都是pair,同时拥有实值value和键值key。pair的第一元素都被视为键值,第二元素都被视为实值。map不允许两个元素拥有相同的键值。注意,map一定使用底层RB-tree的insert_unique()而非是insert_equal(),multimap才使用insert_equal()。因为map不允许相同的键值存在,multimap才允许相同键值存在。
如果要修改map的键值是不可以的,因为在map内部pair的顺序是根据键值来排序的,如果修改了键值那么将会严重的影响pair的顺序。而map的实值是可以的修改的,不影响排序。因此,map iterators,既不是一种constant iterators,也不是一种mutable iterators。也就是map可以用迭代器来改变实值。
map 的底层机制也是RB-tree来实现的。每个节点的内容是一个pair,pair第一个值是键,第二是值。
面对关联式容器,应该使用其所提供的find()函数来搜寻元素,会比使用STL算法find()更有效率,因为STL算法find()只是循环搜寻。

iter = simap.find(string("mchen"));
if(iter == simap.end())
    cout << "not found" << endl;

取key值用: iter->first
取value值用: iter->second

【13】multiset

就是插入的时候用的RB-tree的 insert_equal()

【14】mutimap

就是插入的时候用的RB-tree的 insert_equal()

【15】hashtable

键值和实值是一样的。索引值是用实值通过映射函数是得到的一个整数。

hashtable由两部分组成,一部分是vector(也就是一个bucket,这个桶的值是将key值取hash然后和数组大小取模的结果),这个值就是将键值通过映射函数处理后得到一个整数,关键在于散列函数和碰撞处理,这个vector的大小是28个质数中的一个,vecotr的缺省大小是50,即对应的质数是53;另一部分是一个链表用来存具体的实值。在对应的桶中插入节点的时候是采用头插的方式。
STL数据结构总结_第18张图片
在前置++ 的操作中,如果下个节点不为空那么就是 cur = cur->next;如果是为空的话那么就是移动到下个buckets中指向第一个节点。
注意,没有–的迭代器,也就是没有后退的操作。
STL数据结构总结_第19张图片
可以插入重复的值。
STL数据结构总结_第20张图片
当vector的大小改变的时候,那么这个键需要重排了(就是resize()函数),因为值通过映射函数转化为整数的之后 要和 当前的vector的长度取余之后的值,就是这个节点要去哪个buckets下面的链表里。同时在插入的时候可以插重复的数据,如果是重复的则插入的久节点的后面,否则则插到头结点。

【16】hashset

  1. hashset的底层机制是由hashtable实现的,和set一样有实值,但是没有排序。
  2. hashset不允许插入重复的值。
  3. buckets的vector缺省的大小是100,对应的质数数组的大小是193;

【17】hash_map

  1. hashmap 的底层原理是由hashtable实现。
  2. 运用map,为的是能够根据键值快熟搜寻元素,这一点,不论其底层是RB-tree还是hashtable,都可以达成任务。但是注意,RB-tree有自动排序功能而hashtable没有,反应出来的结果就是,map的元素有自动排序功能而hash_map没有。
  3. buckets的vector缺省的大小是100,对应的质数数组的大小是193;
  4. 不循序要有重复的键值;

【18】hash_multiset

  1. hash_multiset 的特性与 mutiset 完全相同,唯一的差别在于它的底层机制是hashtable。也因此,hash_multiset的元素并不会被自动排序。
  2. hash_multiset和hash_set 实现上的唯一差别在于,前者的元素插入操作才用底层机制hashtable的insert_equal(),后者则是才用insert_unique()。

【19】hash_multiset

  1. hash_multimap 的特性与 mutimap 完全相同,唯一的差别在于它的底层机制是hashtable。也因此,hash_multimap的元素并不会被自动排序。
  2. hash_multimap和hash_map 实现上的唯一差别在于,前者的元素插入操作才用底层机制hashtable的insert_equal(),后者则是才用insert_unique()。

你可能感兴趣的:(C/C++)