STL与泛型编程 第三周 博览网

deque

  • deque其实是分段连续,即在其内部并不是连续分布的。但抽象为连续的分布。如下图:
    image.png

    image.png

    deque可以前后扩充。其中map可以认为是一个控制中心,它其实是一个vector,当map容量不够时进行扩充,扩充后会进行数据copy,但是它会将数据copy到中间位置。
  • deque模拟连续空间由deque iterator完成,
  • array、vector、deque均抽象为连续空间可以使用+=、-=、[]运算符。其他容器则不可以。
  • stack、queue使用的是deque,只不过取消掉一部分功能。stack、queue其实就是一个adapter,它们都不允许遍历,也不提供iterator。stack、queue都可以选择list或者deque作为底层结构,但是deque为默认底层结构,速度更快一点。stack可以选择vector作为底部支撑,但是queue不可以选择vector作为底层结构。


    image.png

    image.png
  • stack、queue默认基于deque实现,priority_queue是在vector上实现的。priority_queue还要求随机访问能力,故它只能构造在vector和deque之上,不能基于list构造。
  • stack包含在stack头文件中,queue和priority_queue均在queue头文件中。

各容器特殊操作

  • array不支持C c(b,e)操作,即构造C,将迭代器b和e指定的范围内的元素拷贝到C
  • vector deque array支持迭代器+=操作。其他均不支持。包括list。
  • list不支持迭代器的比较运算符(除了== !=)
  • forward_list因为无法保证size运算的常数复杂度,所以不支持size()运算.
  • 所有容器都支持== !=操作,但只有顺序容器支持< <= > >=操作。比较两个容器其实就是将元素逐对进行比较。
  • 只有顺序容器可以(不包括array)的构造函数才能接收容器大小的参数。例如:
    list<string> a(4,"haha");
    array<int,4> c;//array在创建时必须指定大小
  • 只有vector,array,deque,string提供快速随机访问容器。使用at()成员函数可以检查是否越界,如果下表越界会抛出out_of_range异常。
  • 访问容器前必须检查是否未空,否则出现知名错误。
  • 除了array外,swap()成员函数不对任何元素进行拷贝、删除和插入操作,它不会移动元素本省,它只是改变容器内部的数据结构,因此可以保证在常数时间内完成,因此swap后指向元素的迭代器、引用和指针仍指向这个元素。
  • swap 两个array会真正交换它们的元素。因此指向元素的迭代器、引用和指针指向array的相同位置,但是元素值已经不同了。
  • swap有成员函数版本和非成员函数版本,统一使用非成员函数版本是一个好习惯。
  • 赋值相关预算会导致指向左边容器内部的迭代器,引用和指针失效。
  • 对vector、string、deque插入元素(array不支持此操作)会使指向容器的迭代器、引用和指针失效。导致无法再使用,使用时可以使用insert()返回的值对其重新进行赋值。
  • 删除deque中除首尾元素之外的任何元素都会使所有迭代器、引用和指针失效。指向vector或string中删除点后位置的迭代器、引用和指针都会失效。
  • 对于vector、deuqe、list的insert(p)会返回指向新添加元素的第一个元素,插入位置为迭代器p指向元素的前面;erase(p)会删除p指向的元素,返回一个被删除元素之后元素的迭代器。
  • 对于forward_list由于其特殊性,insert_after(p)为在p之后插入元素,返回一个指向最后一个元素的迭代器;erase_after(p)为删除p指向的位置之后的元素,返回一个被删除元素之后元素的迭代器。
  • 由于向迭代器添加元素和删除元素的代码可能会使失效,因此必须保证每次改变容器的操作之后都正确地定位迭代器。这个建议对于vector、string、和deque尤为重要。
  • 当我们添加/删除vector或string的元素后,或者在deque中首元素外任何位置添加/删除元素后,原来end返回的尾后迭代器均失效,因此不要轻易保存尾后迭代器进行循环判断,而是在每次循环后都进行更新,end()的运行速度一般很快。

string

  • 对于string还有特殊版本的insert和earse汉本,它接收的第一个参数是下表,而不是迭代器。

associative container - rb_tree

  • associative container包括map、set、multiset、multimap其底层支持就是一个RB_Tree.
  • 红黑树是一种平衡二叉搜索树。这种结构有利于search和insert。我们不应使用RB_Tree的iterator改变元素的值,因为元素在rb_Tree中的序列是严格排列规则的。rb_tree提供两种insertion操作:inser_unique()和insert_equal(),地址一种表示节点key在树中独一无二,重复的key无法放入树中,后者表示节点可以重复,重复的key可以被放入树中。
    image.png
  • set/multiset提供遍历操作及iterator。无法使用iterator改变key值。
  • map/multimap提供遍历操作及iterator。通过iterator无法改变map和multimap的key值,但是可以改变它的data值。
  • map的operator[]有特殊的功能,可以通过它来方元素进去。multimap则无此功能。

unorder container - hashtable

  • unorder_map/multimap unorder_set/multitset底层结构均为容器hashtable。
  • hashtable的工作原理


    image.png

    如果元素个数超过buckets内的个数时,则buckets进行扩充,变为原来的2倍数字附近的质数的个数。在gun2.9中内置的hashtable中buckets的大小,初始为53,第一次扩大为97,第三次扩大为193,以此类推。每一次buckets的扩充都消耗大量时间,包括vector的增长以及元素的重新分配。

  • hashtable类没有为std:: string提供默认的hashfunction,所以要自己写一个hashfunction来处理字符串产生hashcode。但是为C风格的字符串提供了默认的产生的hashcode的hashfunction。
  • 我们通常不对关联容器使用泛型算法。关联容器可以使用只读取元素的算法,一般不使用泛型find算法,而使用关联容器专门的find算法。
  • 关联容器的关键字类型要嘛自己有定义的<操作符,要嘛在实例化泛型时传入一个函数指针来提供比较运算。
bool compareIsbn(const Book &lhs,const Book &rhs) {...}//Book是一个类
set<Book,decltype(compareIsbn)*> bookstore(compareIsbn);//创建实例时传入一个比较函数
//或者如下
typedef bool (*pf) (const Book &,const Book &);
set<Book,pf> bookstore(compareIsbn)
  • 对于set或者map,insert(或emplace)返回一个pair类型,first是一个迭代器,指向给定关键字元素,second为一个bool值,指示是否插入成功。
  • 对于允许重复关键字的容器,insert或者emplace只返回一个指向插入元素的迭代器。
  • 对于map进行下表运算符操作时,如果元素不在map中,则会添加元素到map中,因此如果只是向知道一个元素是否已在map中,但不存在时不想添加元素时不可以使用下表运算符
  • 对于无序关联容器,不需要提供<运算符,只需要提供==运算符即可。
  • 默认情况下,无序容器使用关键字类型的==运算符来比较元素,它们还使用一个hash<key_type>类型的对象来生成每个元素的哈希值;标准库为内置类型(包括指针)、string和只能指针类型定义了hash,因此我们可以直接定义关键字是内置以上类型的无序容器;但是我们不能直接定义关键字类型为自定义类类型的无序容器,必须提供自己的hash模板版本。自定义类型版本
unorderde_multiset<Book,decltype(hasher)*,decltype(eqOp)* > bookstore(42,hasher,eqOp);
/*hasher,eqOp为函数名,初始化对象传入的参数分别为同大小、哈希函数指针、相等行判断运算符指针*/
unordered_set <Foo,decltype(FooHash)* >fooSet(10,FooHash);
/*如果在FOO类中定义了==运算符,则可以只重载哈希函数*/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容