Boolan_STL与泛型编程_第三周笔记

本周课程重点讲解了容器deque、容器queue、容器rb_tree、容器set/multiset、容器map/multimap以及容器hashtable的源代码和使用方法,简单介绍了hash_set/hash_multiset、hash_map/hash_multimap以及容器unordered的概念。

1、容器deque

1.1 容器deque结构

容器deque内含有多个buffer(缓冲区),每个buffer中的iterator有4个指针,分别是cur、first、last和node。本小节主要讲解容器deque的结构以及如何插入一个元素。

总结本小节内容如下:

(1)每个buffer中iterator的4个指针:node指向buffer,first和last指向buffer的头和尾,cur指向buffer中某一个元素;

(2)进行插入元素之前,需判断是否走到buffer的边界,如果没有达到buffer边界,则直接插入元素,如果达到buffer边界,则通过node指向下一个buffer;

(3)deque中有4个数据成员:两个iterator分别指向deque的begin和finish,一个指向vector的指针(map,控制中心)和vector的大小(map_size),所以共16+16+4+4=40个字节(32位cpu);

(4)deque的模板参数有3个,包括元素类型、分配器、BufSiz(默认是0,G4.9没有该参数),__deque_buf_size用于计算buffer size,如果没有指定BufSiz,那么会根据元素的大小(sz)设置buffer size,如果一个元素的大小小于512,那么要用512除以元素的大小来计算buffer size. 如果大于等于512,buffer size会设置为1;

(5)deque<T>::insert(),指定一个位置放置新的元素,有2种情况:a、安插点在头或尾(position.cur是start.cur或finish.cur),调用push_front(x)(安插点在最前端)或push_back(x)(安插点在最尾端)实现;b、如果不在头和尾,那么就要调用辅助函数insert_aux(position, x),insert_aux插入数据时会先判断插入点前后哪一边的元素少,取少的那一边全部元素向前移动一个位置,之后空出来的位置放入x,这样做是为了使得程序尽可能高效。

1.2 deque模拟连续空间

deque表示双向开口容器,它模拟了一个连续的存储空间,但实质上它是一个分段连续的容器。本小节主要讲解了deque如何模拟连续空间。

总结本小节内容如下:

(1)总的来说是依靠deque iterators实现分段连续的,实现源代码见上图;

(2)两个迭代器之间的距离(difference_type operartor-(const self& x) const {})=中间完整缓冲区个数(node-x.node-1)*bufsiz+起始buffer的元素数量(x.last-x.cur)+结尾buffer的元素数量(cur-first);

(3)移动一个位置:调用++时,先判断cur==last,如果是,则set_node(node+1),移动到后一个buffer的第一个元素的位置;调用--时,先判断cur==first,如果是,那么set_node(node-1)切换到前一个buffer的最后一个元素的位置;

(4)移动多个位置:先判断是否会跨越缓冲区,如果是,那么再计算要跨越几个缓冲区,再移动node指针来跨越缓冲区,到达最后一个缓冲区,再计算要偏移几个元素,最后到达指定的位置,通过重载+=,-=,+,-运算符实现,其中operator-=相当于+= -n,所以-=是利用operator+=来实现,其他类似;

(5)容器deque中vector每次按照2倍大小进行扩充,扩充后,会将之前的元素拷贝到中段,前后都能留有空闲空间,便于前后扩展。

1.3 queue和stack

queue(先进先出)和stack(先进后出)均是通过调用deque来实现的,它们内部拥有一个deque,因此他们的各个函数都是调用的deque的函数。

queue和stack也可以选择list作为底部结构,但是默认是选择deque,选择deque作为底部支撑效率更高;stack可以选择vector作为底层结构,但queue不可以;queue和stack都不可以选择set或map作为底层结构。

queue和stack都不允许遍历,也不提供iterator,因为不允许中间插入/删除元素。

2、容器rb_tree

rb_tree(红黑树)是平衡二分搜索树中常被使用的一种,是关联式容器,查找和插入元素快。

总结本节内容如下:

(1)遍历时,++iter得到的元素是按照key排序的;

(2)rb_tree为set和map提供底部支撑,其中map允许改变data,不允许改变key;

(3)rb_tree提供两种insert操作:insert_unique()和insert_equal(),insert_unique()表示节点的key在整个树中是唯一的,insert_equal()表示节点的key可以重复;

(4)rb_tree的元素顺序:从左到右,从下到上;

(5)rb_tree的模板参数:key、value(key和data合成value)、KeyofValue(从value中取key的方法)、Compare(两个节点key比较大小的方法)、Alloc=alloc;

(6)rb_tree的大小: G2.9 中大小是12(两个指针和一个泛函数,4+4+1=9,对齐成4的倍数后是12),G2.9 中大小是24(3ptr+1color)。

3、容器set/multiset和容器map/multimap

(1)对于set/multiset来讲key就是value,不能改变元素值。

(2)set插入数据是调用的rb_tree的insert_unique(), multiset插入数据是调用的rb_tree的insert_equal()。

(3)set/multiset的iterator是rb_tree中的const_interator,防止修改iterator指向的元素。

(4)set的所有操作都是调用底层rb_tree的操作,所以set也未尝不是一个container adapter。

(1)对于map/multimap来说key是const类型,防止用户更改key。

(2)map/multimap的iterator就是rb_tree的iterator。

(3)容器map独特的operator[ ],其内部实现iterator _i = lower_bound(_k),如果map中没有_k, 那么会返回适合放置_k的位置,之后会调用insert插入到map中。

4、容器hashtable

hashtable底层实现是通过开链法来实现的,hashtable内的元素称为桶(bucket),而由桶所链接的元素称为节点(node),其中存入桶元素的容器为stl本身很重要的一种序列式容器——vector容器。之所以选择vector为存放桶元素的基础容器,主要是因为vector容器本身具有动态扩容能力,无需人工干预。hash_set、hash_map、hash_multiset、hash_multimap四个关联容器都是以hashtable为底层实现方法。

总结本节内容如下:

(1)当空间足够时,编号为多少就放在相应位置,当空间不够时,H/M余数是多少就放置在相应位置,这样会发生碰撞,解决办法是使用链表;

(2)当元素个数比篮子的个数多的时候,会将hashtable打散,将篮子增加到大约是原有的2倍;

(3)hashtable有6个模板参数:value,key, class HashFcn(计算元素对应的编号), class ExtractKey(从元素中取出key), class EqualKey(计算key相等的方法), class Alloc=alloc;

(4)hashtable中iterator的设计,考虑到遍历完一个链表后,要能够回到hashtable, 再遍历下一个链表,所以iterator中除了有一个指向当前节点的指针外node* cur, 还有一个指向hashtable本身的指针hashtable* ht;

(5)hashtable的大小:1(HashFcn)+1(EqualKey)+1(ExtractKey)+12(vector buckects占12字节(内部有3个指针))+4(size_type num_elements占4个字节)=19,对齐后是20个字节。

5、容器unordered

c++11将hash_set,hash_multiset,hash_map,hash_multimap这4个名字改为unordered_set, unordered_multiset, unordered_map,unordered_multimap。

(1)容器unoerdered_set中元素不能重复;

(2)c.bucket_size(i)打印第i个篮子中元素的数量;

(3)总的bucket的个数一定大于总元素的个数。

6、课后补充学习

(一)红黑树与平衡二叉树

红黑树介绍:http://blog.csdn.net/eric491179912/article/details/6179908

平衡二叉树介绍:http://www.cnblogs.com/abatei/archive/2008/11/17/1335031.html

红黑树十分复杂,只学习了一点,后续继续学习。

红黑树与平衡二叉树的区别:

1、平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知;

2、红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单;

3、红黑树就是平衡二叉树,只不过它的每个节点多加了一个标志属性,这个标志是在增加和删除节点时用的。对一个平衡二叉树做几次增加删除节点的操作,它就变成非平衡的了,这不利于查找。所以每次增加删除节点后都要进行调整,调整的算法就是按红黑树的规则“红节点的孩子不能是红节点”。对一个n个节点的红黑树做一次这样的调整最多需要log(n)步。

(二)stack的用法

详见:http://blog.csdn.net/wallwind/article/details/6858634

(三)#include <cstring>、#include<string>与#include<string.h>的区别

#include<string>是C++特化的字符容器,内含string类。

#include<string.h>是标准C提供的字符处理函数集,面向char *。

#include <cstring>是C++为兼容C提供的的C++版本,里面的主要改进有:将一些隐藏变量编入命名空间;修正一些C++编译器认为Bug的代码,其余没发现很多改变。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容