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