STL 模板庫思想理解雜談
STL 注重將 DataStructure 與 Algorithm 分開. 通過迭代器作爲 DataStructure 與 Algorithm 之間的橋樑. 如下圖所示
DataStructure <-------iterator-------> Algorithm
具體是怎麼樣做的呢??
其中
算法
- 通過迭代器來確定算法的執行範圍與對象(eg: [begin, end))
比如 sort(iterator first, iterator end, compare cmp);
- 通過迭代器來代(間接地)與DataStrucre中的 element 交換信息
爲什麼要這樣做呢??
有人說了,我一般隨手敲的數據結構也可以啊.爲什麼要這樣做呢??
- 分開可以讓 DataStrucre 與 Algorithm 各司其職.
- 可重用, 減少很多的重複代碼.
- 結構清晰, 易於理解與閱讀.
- 易維護, 各模塊低耦合.
一. Iterator(迭代器)
迭代器是連接 DataStrucre 與 Algorithm 的橋樑. 本質是一個通用的接口.實現了與數據結構中元素的操作,與同期的遍歷等(比如 讀取與訪問,++,–等)
思考一個問題
源於對於不同類型的數據結構,迭代器要有不同的操作.
有些算法並不能用於某些數據結構(這體現爲: 某些算法需要依賴於特定類型的迭代器)
來讓我們比較以下兩個數據結構:
-
鏈表屬於鏈式結構, 不能隨機訪問,只能一次前進一個單位元素.
-
vector屬於順序結構.可以隨機訪問,可以直接 O(1) 訪問到任何一個元素.
binary_search 我們都知道的, 可以對有序的集合查找一個元素. 每次折半查找,複雜度爲 O(log2^n). 而比直接遍歷一遍的 O(n) 複雜度要快的多.
然而折半查找的 精髓在於折半 : 跨元素訪問, 從而省去了訪問不必要的元素.
如果不能跨元素訪問(即不能隨機訪問)只能一個個的去訪問, 二分搜索就失去了價值.
結論: binary_search 不能用於非隨機訪問的迭代器(本數據結構並不支持隨機訪問)因爲特定算法與數據結構只能依賴與特定的 iterator, 便將迭代器分爲了以下 5 種類型(這也是迭代器分類的原因):
1.1 迭代器的分類
- input iterator
- output iterator
- forward iterator
- bidirectional iterator
- random iterator
其中,random 迭代器可以實現隨機訪問,也就可以用於二分搜索.但其餘的則不能. 每種算法或者數據結構都有其特定依賴的迭代器種類. 這樣一來,就能很好連接 DataStrucre 與 Algorithm.
eg: random iterator 可以進行 p+=i 操作, 但雙向迭代器不能.
二. DataStrucre
2.1 DataStrucre分類
- containter
- 序列型容器
- List
- Vector
- Deque
- 聯繫型型容器
- map
- set
- un… 容器
- hashmap
- hashset
- 序列型容器
- adapter
三. Genergic(泛型) programming
cpp 中, 泛型編程通過模板來時間.使得我們可以更專注的編寫數據結構與算法而不用去關心數據元素的類型.
模板技術本質上是靜態多態的體現,數據元素的類型將在編譯期被確定.
再來思考一個問題
我們將泛型籠統的分爲兩類: 1. 內置類型 2. 用戶自定義類型
現在有一個算法,比如 destory 函數. 對於內置類型採用delete即可.對於用戶自定義類型,需要採用其特有的 destructor 函數.
在面向過程編程中,我們可以使用 if 語句來完成選擇.
在面向對象編程中, 我們可以使用多態來完成完成選擇.
那麼在 泛型編程中,如何根據不同類型而進行選擇不同的算法呢???
答案呼之欲出:
模板偏特化
template<typename T>
class
{
int flag = 0;
};
template<>
class<int>
{
int flag = 1;
};
在這個例子中,此模板的作用相當於.
int flag;
if( type == int)
{
flag = 1
}
else//是其他類型
{
flag = 0
}
但是如果我們直接在算法中使用 模板偏特化,代碼會非常多,不利於編程與降低人腦複雜度.
那該怎麼辦呢??? 一種新技術出現了
模板萃取技術
編譯期計算、查詢、判斷、轉換和選擇的幫助類
模板萃取,本質是對類型的各種操作. 解決上面的問題,我們可以用到 判斷萃取技術.
判斷萃取技術(本部分非原創,鏈接給到了文章尾部)
設定這樣一個模板類, 接受一個類型,判斷這個類型是否是內置類型.如果是,返回真.如果不是返回假.
struct True_type
{
bool Get()
{
return true;
}
};
struct False_type
{
bool Get()
{
return true;
}
};
template<typename T>
struct type_traits
{
using _is_pod = False_type;
};
template<>
struct type_traits<int>
{
using _is_pod = True_type;
};
template<>
struct type_traits<double>
{
using _is_pod = True_type;
};
.... 對所有自定義類型類型特化
那麼我們在使用時只需要
if(type_traits<int>::_is_pod().Get() == true){
}
else{
}
就可以實現類型的判斷了.
查詢萃取技術
假設現在有兩種迭代器,
未完待續…