关于STL几点
STL內(nèi)容雖然看起來很多,單獨(dú)成書都不是問題(《STL源碼剖析》),但從實際使用狀況來看,我認(rèn)為只需要知道以下幾點就可以了:
-
怎么用?
各種STL基本的增刪改查怎么使用。每種容器都提供了很多操作,但實際增刪改查我們通常只需要掌握透徹一種方式即可。有些功能只是出于通用性考慮才存在的,但對于相應(yīng)的STL這些操作完全可以忽略。所以我對STL使用的看法是,不需要花太多時間去了解所有功能,只要掌握最基本的即可,要把精力放在對需求的了解并選擇適合的數(shù)據(jù)結(jié)構(gòu)。
-
怎么實現(xiàn)?
本身STL就是封裝了我們常用的數(shù)據(jù)結(jié)構(gòu),所以最先需要了解每種數(shù)據(jù)結(jié)構(gòu)的特性。而且了解實現(xiàn)方式對我們能夠準(zhǔn)確、高效使用STL打下了基礎(chǔ)。
-
如何避免錯誤?
在第二階段了解了STL的實現(xiàn)之后,我們已經(jīng)可以很清楚地知道他們底層使用的是什么數(shù)據(jù)結(jié)構(gòu)以及該數(shù)據(jù)結(jié)構(gòu)做什么操作比較高效。但還有一點需要注意的就是怎么才能用對他們,避免一些未知的錯誤,比如迭代器失效問題。
string
vector
用法:
定義:vector<T> vec;插入元素:vec.push_back(element);vec.insert(iterator, element);刪除元素:vec.pop_back();vec.erase(iterator);修改元素:vec[position] = element;遍歷容器:for(auto it = vec.begin(); it != vec.end(); ++it) {......}其他:vec.empty(); //判斷是否空vec.size(); // 實際元素vec.capacity(); // 容器容量vec.begin(); // 獲得首迭代器vec.end(); // 獲得尾迭代器vec.clear(); // 清空實現(xiàn):
模擬Vector實現(xiàn)
-
線性表,數(shù)組實現(xiàn)。
-
支持隨機(jī)訪問。
-
插入刪除操作需要大量移動數(shù)據(jù)。
-
-
需要連續(xù)的物理存儲空間。
-
每當(dāng)大小不夠時,重新分配內(nèi)存(*2),并復(fù)制原內(nèi)容。
錯誤避免:
迭代器失效
-
插入元素
-
尾后插入:size < capacity時,首迭代器不失效,尾迭代失效(未重新分配空間),size == capacity時,所有迭代器均失效(需要重新分配空間)。
-
中間插入:size < capacity時,首迭代器不失效但插入元素之后所有迭代器失效,size == capacity時,所有迭代器均失效。
-
-
刪除元素
-
尾后刪除:只有尾迭代失效。
-
中間刪除:刪除位置之后所有迭代失效。
-
map
用法:
定義:map<T_key, T_value> mymap;插入元素:mymap.insert(pair<T_key, T_value>(key, value)); // 同key不插入mymap.insert(map<T_key, T_value>::value_type(key, value)); // 同key不插入mymap[key] = value; // 同key覆蓋刪除元素:mymap.erase(key); // 按值刪mymap.erase(iterator); // 按迭代器刪修改元素:mymap[key] = new_value;遍歷容器:for(auto it = mymap.begin(); it != mymap.end(); ++it) {cout << it->first << " => " << it->second << '\n';}實現(xiàn):
RBTree實現(xiàn)
-
樹狀結(jié)構(gòu),RBTree實現(xiàn)。
-
插入刪除不需要數(shù)據(jù)復(fù)制。
-
操作復(fù)雜度僅跟樹高有關(guān)。
-
-
RBTree本身也是二叉排序樹的一種,key值有序,且唯一。
- 必須保證key可排序。
基于紅黑樹實現(xiàn)的map結(jié)構(gòu)(實際上是map, set, multimap,multiset底層均是紅黑樹),不僅增刪數(shù)據(jù)時不需要移動數(shù)據(jù),其所有操作都可以在O(logn)時間范圍內(nèi)完成。另外,基于紅黑樹的map在通過迭代器遍歷時,得到的是key按序排列后的結(jié)果,這點特性在很多操作中非常方便。
面試時候現(xiàn)場寫紅黑樹代碼的概率幾乎為0,但是紅黑樹一些基本概念還是需要掌握的。
它是二叉排序樹(繼承二叉排序樹特顯):
-
若左子樹不空,則左子樹上所有結(jié)點的值均小于或等于它的根結(jié)點的值。
-
若右子樹不空,則右子樹上所有結(jié)點的值均大于或等于它的根結(jié)點的值。
-
左、右子樹也分別為二叉排序樹。
它滿足如下幾點要求:
-
樹中所有節(jié)點非紅即黑。
-
根節(jié)點必為黑節(jié)點。
-
紅節(jié)點的子節(jié)點必為黑(黑節(jié)點子節(jié)點可為黑)。
-
從根到NULL的任何路徑上黑結(jié)點數(shù)相同。
查找時間一定可以控制在O(logn)。
紅黑樹的節(jié)點定義如下:
enum Color {RED = 0,BLACK = 1 }; struct RBTreeNode {struct RBTreeNode*left, *right, *parent;int key;int data;Color color; };所以對紅黑樹的操作需要滿足兩點:1.滿足二叉排序樹的要求;2.滿足紅黑樹自身要求。通常在找到節(jié)點通過和根節(jié)點比較找到插入位置之后,還需要結(jié)合紅黑樹自身限制條件對子樹進(jìn)行左旋和右旋。
相比于AVL樹,紅黑樹平衡性要稍微差一些,不過創(chuàng)建紅黑樹時所需的旋轉(zhuǎn)操作也會少很多。相比于最簡單的BST,BST最差情況下查找的時間復(fù)雜度會上升至O(n),而紅黑樹最壞情況下查找效率依舊是O(logn)。所以說紅黑樹之所以能夠在STL及Linux內(nèi)核中被廣泛應(yīng)用就是因為其折中了兩種方案,既減少了樹高,又減少了建樹時旋轉(zhuǎn)的次數(shù)。
從紅黑樹的定義來看,紅黑樹從根到NULL的每條路徑擁有相同的黑節(jié)點數(shù)(假設(shè)為n),所以最短的路徑長度為n(全為黑節(jié)點情況)。因為紅節(jié)點不能連續(xù)出現(xiàn),所以路徑最長的情況就是插入最多的紅色節(jié)點,在黑節(jié)點數(shù)一致的情況下,最可觀的情況就是黑紅黑紅排列......最長路徑不會大于2n,這里路徑長就是樹高。
set
總結(jié)
- 上一篇: 构造函数不可以声明为虚函数,析构函数可以
- 下一篇: GCC : 什么是编译?什么是静态库?什