關(guān)于STL與泛型編程學(xué)習(xí)感想三(博覽網(wǎng))

體系結(jié)構(gòu)與內(nèi)核分析續(xù)

deque&queue 和 stack 深度探索

deque雙向隊(duì)列是一種雙向開口的連續(xù)線性空間曹抬,可以高效的在頭尾兩端插入和刪除元素忧额,deque在接口上和vector非常相似绿店。(連續(xù)是假象铲敛,分段是事實(shí))

deque的內(nèi)存空間分布是小片的連續(xù)粟关,小片間用鏈表相連言询,實(shí)際上內(nèi)部有一個(gè)map的指針尔觉。其中buffer表示deque的緩沖區(qū)凉袱,每個(gè)buffer可以存放多個(gè)元素結(jié)點(diǎn)。并且每個(gè)buffer指針存放在vector容器中侦铜。每個(gè)iterator存放四個(gè)指針:cur专甩、first、last钉稍、node配深,cur表示當(dāng)前數(shù)據(jù)結(jié)點(diǎn)的指針,first表示buffer首指針嫁盲,last表示buffer的尾指針篓叶,node表示這個(gè)iterator在vector中的指針地址烈掠。所有容器都有兩個(gè)iterator分別指向頭和尾begin& finish。

deque用法:http://blog.csdn.net/hnust_xiehonghao/article/details/8800007



源代碼示例:deque::insert()

//在position處安插一個(gè)元素缸托,其值為x

iterator insert(iterator position,const value_type& x){

if(position.cur == start.cur){? ? ? ? ? ? ? //如果安插點(diǎn)是deque最前端

push_front(x);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //交給push——front()做

return start;

}

else if (position.cur == finish.cur) {? ? //如果安插點(diǎn)是deque最尾端

push_back(x);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //交給push——back()做

iterator tmp =finish;

--tmp;

return tmp;

}

else {

return insert_aux(position,x);

}

}

template

typename deque::iterator

deque::insert_aux(iterator pos,const value_type& x){

difference_type index = pos - start;? ? //安插點(diǎn)之前的元素個(gè)數(shù)

value_type x_copy =x;

if (index

push_front(front());? ? ? ? ? ? //在最前端加入與第一元素同值的元素

...

copy(front2,pos1,front1);? ? //元素搬移

}

else{? ? ? ? ? ? ? ? ? ? ? ? //安插點(diǎn)之后的元素個(gè)數(shù)較少

push_back(back());? //在尾端加入與最末元素同值的元素

...

copy_backward(pos,back2,back1);? ? ? //元素搬移

}

*pos = x_copy;? ? ? ? //在安插點(diǎn)上設(shè)定新值

return pos;

}

deque是如何模擬連續(xù)空間:源代碼做了大量的操作符重載左敌,尤其是遇到buffer邊界時(shí)如何跳到控制中心,使得deque的iterator能夠在buffer之間模擬出連續(xù)空間俐镐。iterator的功勞特別是大量的操作符重載矫限。

實(shí)現(xiàn)源代碼如下:

reference operator[] (size_type n)

{

return start[difference_type(n)];

}

reference front(){return *start;}

reference back()

{

iterator tmp = finish;

--tmp;

return *tmp;

}

size_type size() const {return finish - start;}

bool empty() const {return == start;}

reference operator*() const {return *cur;}

pointer operator->() const {return & (operator*());}

queue(先進(jìn)先出)和stack(先進(jìn)后出):內(nèi)含一個(gè)deque封掉某些功能。

stack和queue都不允許遍歷佩抹,也不提供iterator叼风。

stack和queue都可選擇list和deque作為底層容器。

queue不可選擇vector作為底層結(jié)構(gòu)棍苹,stack可選擇vector作為底層結(jié)構(gòu)无宿。

stack和queue都不可選擇set或map做底層結(jié)構(gòu)。

RB-tree深度探索

Red-Black tree(紅黑樹)是平衡二元搜尋樹(balanced binary search tree)中常被使用的一種枢里。平衡二元搜尋樹的特征:排列規(guī)則有利于search和insert孽鸡,并保持適度平衡,即無任何節(jié)點(diǎn)過深栏豺。

紅黑樹的性質(zhì)如下:

1) 每一個(gè)節(jié)點(diǎn)或者著紅色,或者著成黑色.

2) 根是黑色的

3) 如果一個(gè)節(jié)點(diǎn)是紅色的,那么它的子節(jié)點(diǎn)必須是黑色的.

4) 從一個(gè)節(jié)點(diǎn)到一個(gè)NULL指針的每一條路徑必須包含相同數(shù)目的黑色節(jié)點(diǎn).



re_tree提供“遍歷”操作及iterators彬碱。按正常規(guī)則(++ite)遍歷,便能獲得排序狀態(tài)(sorted)奥洼。我們不應(yīng)使用rb_tree的iterators改變?cè)刂担ㄒ驗(yàn)樵赜衅鋰?yán)謹(jǐn)排列規(guī)則)巷疼。編程并未阻止此事。如此設(shè)計(jì)是正確的灵奖,因?yàn)閞b_tree即將為set和map服務(wù)(作為其底部支持)嚼沿,而map允許元素的data被改變,只有元素的key才是不可被改變的桑寨。key和data一起才為value伏尼。rb_tree提供兩種insertion操作:insert_unique()和insert_equal( )忿檩。前者表示節(jié)點(diǎn)的key一定在整個(gè)tree中獨(dú)一無二尉尾,否則安插失敗燥透;后者表示節(jié)點(diǎn)的key可重復(fù)沙咏。

RB-tree的用法:

begin()函數(shù)獲取最左(最小)的節(jié)點(diǎn)處班套,end()獲取的是根結(jié)點(diǎn)(由于使用了一個(gè)實(shí)現(xiàn)上的技巧肢藐,其實(shí)并不是真的根結(jié)點(diǎn));

empty()判斷是否為空, size(), max_size()最大數(shù)據(jù)的數(shù)量吱韭,count()吆豹;

insert_unique(const value_type& x)將x插入RB-tree中鱼的,保持節(jié)點(diǎn)值獨(dú)一無二;

insert_equal(const value_type& x)將x插入RB-tree中痘煤,允許節(jié)點(diǎn)值重復(fù)凑阶。

關(guān)聯(lián)式容器

set/multiset(set中key不可重復(fù),multiset可以|后面map相同) (key就是vault)二分樹(高度平衡)map/multimap(有key和vault)(所有元素都會(huì)根據(jù)元素的鍵值自動(dòng)被排序)在STL中關(guān)聯(lián)容器使用紅黑樹來實(shí)現(xiàn)衷快,因?yàn)椴皇琼樞蚪Y(jié)構(gòu)宙橱,因而不能使用上面提到的push和pop函數(shù),使用insert和erase函數(shù)來實(shí)現(xiàn)元素的插入刪除操作呕臂。關(guān)聯(lián)容器支持通過鍵來高效地查找和讀取元素强缘,兩個(gè)基本的關(guān)聯(lián)容器類型是map和set消别。map的元素以鍵-值(key-value)對(duì)的形式組織:鍵用于元素在map中的索引,而值則表示所存儲(chǔ)和讀取的數(shù)據(jù)宝冕。set僅包含一個(gè)鍵,并有效地支持關(guān)于某個(gè)鍵是否存在的查詢陨晶。map可理解為字典猬仁,set可理解為一類元素的集合。關(guān)聯(lián)容器和順序容器的本質(zhì)差別在于:關(guān)聯(lián)容器通過鍵(key)存儲(chǔ)和讀取元素先誉,而順序容器則通過元素在容器中的位置順序存儲(chǔ)和訪問元素湿刽。set 和 map 類型的對(duì)象所包含的元素都具有不同的鍵,不允許為同一個(gè)鍵添加第二個(gè)元素褐耳。如果一個(gè)鍵必須對(duì)應(yīng)多個(gè)實(shí)例诈闺,則需使用 multimap 或 multi set,這兩種類型允許多個(gè)元素?fù)碛邢嗤逆I铃芦。

set/multiset深度探索

set/multiset以rb_tree為底層結(jié)構(gòu)(內(nèi)含一個(gè)tree)雅镊,因此有元素自動(dòng)排序特性。排序的依據(jù)是key刃滓,而set/multiset元素的value和key合一:value就是key仁烹。

set/multiset提供“遍歷”操作及iterators。按正常規(guī)則(++ite)遍歷咧虎,便能獲得排序狀態(tài)(sorted)卓缰。

我們無法使用set/multiset的iterators改變?cè)刂担ㄒ驗(yàn)閗ey有其嚴(yán)謹(jǐn)排列規(guī)則)。set/multiset的iterator是其底部的RB tree的const-iterator砰诵,就是為了禁止user對(duì)元素賦值征唬。

set元素的key必須獨(dú)一無二,因此其insert()用的是rb_tree的insert_unique()茁彭。multiset元素的key可以重復(fù)总寒,因此其insert()用的rb_tree的insert_equal()。

map/multimap深度探索

map/multimap以rb_tree為底層結(jié)構(gòu)理肺,因此有元素自動(dòng)排序特性摄闸。排序的依據(jù)是key善镰。

map/multimap提供“遍歷”操作及iterators。按正常規(guī)則(++ite)遍歷年枕,便能獲得排序狀態(tài)(sorted)媳禁。我們無法使用map/multimap的iterators改變?cè)氐膋ey(因?yàn)閗ey有其嚴(yán)謹(jǐn)排列順序),但可以用它來改變?cè)氐膁ata画切。因此map/multimap內(nèi)部自動(dòng)將user指定的key type設(shè)為const竣稽,如此便能禁止user對(duì)元素的key賦值。(內(nèi)含tree限制某些功能)

map元素的key必須獨(dú)一無二霍弹,因此其insert()用的是rb_tree的insert_unique()毫别。multimap元素的key可以重復(fù),因此其insert()用的是rb_tree的insert_equal()典格。

hashtable深度探索

Hashtable是非泛型的集合岛宦,所以在檢索和存儲(chǔ)值類型時(shí)通常會(huì)發(fā)生裝箱與拆箱的操作。

當(dāng)把某個(gè)元素添加到 Hashtable 時(shí)耍缴,將根據(jù)鍵的哈希代碼將該元素放入存儲(chǔ)桶中砾肺,由于是散列算法所以會(huì)出現(xiàn)一個(gè)哈希函數(shù)能夠?yàn)閮蓚€(gè)不同的鍵生成相同的哈希代碼,該鍵的后續(xù)查找將使用鍵的哈希代碼只在一個(gè)特定存儲(chǔ)桶中搜索防嗡,這將大大減少為查找一個(gè)元素所需的鍵比較的次數(shù)变汪。

Hashtable 的加載因子確定元素與Hashtable 可擁有的元素?cái)?shù)的最大比率。加載因子越小蚁趁,平均查找速度越快裙盾,但消耗的內(nèi)存也增加。默認(rèn)的加載因子 0.72通常提供速度和大小之間的最佳平衡他嫡。當(dāng)創(chuàng)建 Hashtable 時(shí)番官,也可以指定其他加載因子。(元素總量/ Hashtable 可擁有的元素?cái)?shù)=加載因子 )當(dāng)向 Hashtable 添加元素時(shí)钢属,Hashtable 的實(shí)際加載因子將增加徘熔。當(dāng)實(shí)際加載因子達(dá)到指定的加載因子時(shí),Hashtable 中存儲(chǔ)桶的數(shù)目自動(dòng)增加到大于當(dāng)前 Hashtable 存儲(chǔ)桶數(shù)兩倍的最小素?cái)?shù)淆党。(Hashtable適用于讀取操作頻繁酷师,寫入操作很少的操作類型)

當(dāng)碰撞的元素超過“籃子”的個(gè)數(shù),經(jīng)驗(yàn)判斷為危險(xiǎn)宁否,則將“籃子”的數(shù)量擴(kuò)大為原來的兩倍窒升,一般籃子數(shù)量是素?cái)?shù)缀遍。GUC初始籃子數(shù)量為53慕匠,兩倍變成106,附近的素?cái)?shù)而且比106大的為193域醇√ㄒ辏可以使用hashtable iterators改變?cè)氐膁ata蓉媳,但不能改變?cè)氐膋ey(因?yàn)閔ashtable根據(jù)key實(shí)現(xiàn)嚴(yán)謹(jǐn)?shù)脑嘏帕校?/p>

hashtable源代碼:



template六個(gè)模板參數(shù):value和key參數(shù)與紅黑樹為底層的set和map類似,第三個(gè)模板參數(shù)hashFcn(hash-function)的目的是希望根據(jù)元素值算出一個(gè)hash code(一個(gè)可進(jìn)行modulus運(yùn)算的值)锅铅,使得元素hash code映射之后能夠夠雜亂夠隨機(jī)地被置于hashtable內(nèi)酪呻,越是亂,越是不容易碰撞盐须,可以傳函數(shù)玩荠、仿函數(shù)、函數(shù)對(duì)象贼邓,它是通過模板偏特化實(shí)現(xiàn)阶冈,c風(fēng)格的字符串char*是一個(gè)指針,stl提供了實(shí)現(xiàn)方式塑径,而C++的字符串string則需要自己寫實(shí)現(xiàn)方式女坑;第四個(gè)ExtractKey告訴我們?nèi)绾稳〕鰇ey;第五個(gè)EqualKey告訴我們?nèi)绾伪容^key大型骋ā匆骗;第六個(gè)alloc為分配器。

hash_map和map的區(qū)別在哪里誉简?

構(gòu)造函數(shù)? hash_map需要hash函數(shù)碉就,等于函數(shù);map只需要比較函數(shù)(小于函數(shù)).

存儲(chǔ)結(jié)構(gòu)? hash_map采用hash表存儲(chǔ)闷串,map一般采用紅黑樹(RB Tree)實(shí)現(xiàn)铝噩。因此其memory數(shù)據(jù)結(jié)構(gòu)是不一樣的。

unordered容器概念

Before C++11

hash_set

hash_multiset

hash_map

hash_multimap

Since C++11

unordered_set

unordered_multiset

unordered_map

unordered_multimap

只是名稱不同窿克,用法不變

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骏庸,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子年叮,更是在濱河造成了極大的恐慌具被,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件只损,死亡現(xiàn)場(chǎng)離奇詭異一姿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)跃惫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門叮叹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人爆存,你說我怎么就攤上這事蛉顽。” “怎么了先较?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵携冤,是天一觀的道長悼粮。 經(jīng)常有香客問我,道長曾棕,這世上最難降的妖魔是什么扣猫? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮翘地,結(jié)果婚禮上申尤,老公的妹妹穿的比我還像新娘。我一直安慰自己衙耕,他們只是感情好瀑凝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著臭杰,像睡著了一般粤咪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上渴杆,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天寥枝,我揣著相機(jī)與錄音,去河邊找鬼磁奖。 笑死囊拜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的比搭。 我是一名探鬼主播冠跷,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼身诺!你這毒婦竟也來了蜜托?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤霉赡,失蹤者是張志新(化名)和其女友劉穎橄务,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體穴亏,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜂挪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嗓化。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棠涮。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖刺覆,靈堂內(nèi)的尸體忽然破棺而出严肪,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布诬垂,位于F島的核電站,受9級(jí)特大地震影響伦仍,放射性物質(zhì)發(fā)生泄漏结窘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一充蓝、第九天 我趴在偏房一處隱蔽的房頂上張望隧枫。 院中可真熱鬧,春花似錦谓苟、人聲如沸官脓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卑笨。三九已至,卻和暖如春仑撞,著一層夾襖步出監(jiān)牢的瞬間赤兴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國打工隧哮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桶良,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓沮翔,卻偏偏與公主長得像陨帆,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子采蚀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容