來自:大CC
鏈接:http://www.cnblogs.com/me115/p/4596543.html
僅僅是個選擇的問題,都是STL,可能寫出來的效率相差幾倍;
熟悉以下條款,高效的使用STL;
當對象很大時,建立指針的容器而不是對象的容器
1)STL基於拷貝的方式的來工作,任何需要放入STL中的元素,都會被複制;
這也好理解,STL工作的容器是在堆內開闢的一塊新空間,而我們自己的變量一般存放在函數棧或另一塊堆空間中;爲了能夠完全控制STL自己的元素,爲了能在自己的地盤隨心幹活;這就涉及到複製;
而如果複製的對象很大,由複製帶來的性能代價也不小 ;
對於大對象的操作,使用指針來代替對象能消除這方面的代價;
2)只涉及到指針拷貝操作, 沒有額外類的構造函數和賦值構造函數的調用;
vecttor vt1;
vt1.push_bach(myBigObj);
vecttor vt2;
vt2.push_bach(new BigObj());
注意事項:
1)容器銷燬前需要自行銷燬指針所指向的對象;否則就造成了內存泄漏;
2)使用排序等算法時,需要構造基於對象的比較函數,如果使用默認的比較函數,其結果是基於指針大小的比較,而不是對象的比較;
用empty() 代替size()來檢查是否爲空
因爲對於list,size()會遍歷每一個元素來確定大小,時間複雜度 o(n),線性時間;而empty總是保證常數時間;
儘量用區間成員函數代替單元素操作
使用區間成員函數有以下好處:
1)更少的函數調用
2)更少的元素移動
3)更少的內存分配
例:將v2後半部的元素賦值給v1:
單元式操作:
for (vector::const_iterator ci = v2.begin() + v2.size() / 2;
ci != v2.end();
++ci)
v1.push_back(*ci)
使用區間成員函數assign():
v1.assign(v2.begin() + v2.size() / 2, v2.end());
使用reserver避免不必要的內存分配(for vector)
新增元素空間不夠時,vector會進行如下操作:
1)分配當前空間的兩倍空間;
2)將當前元素拷貝到新的空間中;
3)釋放之前的空間;
4)將新值放入新空間指定位置;
如果預先知道空間的大小,預先分配了空間避免了重新分配空間和複製的代價;
注:reserve()只是修改了容量,並非大小,向vector中增加元素還是需要通過push_back加入;
使用有序的vector代替關聯容器(階段性的操作適用)
對階段性操作的定義:
先做一系列插入、完成之後,後續操作都是查詢;
在階段性的操作下,使用vector有以下優勢:
1)因爲vector有序,關聯容器帶來的有序優勢散失;
2)都是使用二分法查找的前提下,查詢算法對連續的內存空間的訪問要快於離散的空間;
在map的insert()和operator[]中仔細選擇
插入時,insert效率高;因爲operator會先探查是否存在這個元素,如果不存在就構造一個臨時的,然後才涉及到賦值,多了一個臨時對象的構造;
更新時,[]效率更高,insert會創造一個對象,然後覆蓋一個原有對象;而[]是在原有的對象上直接賦值操作;
散列函數的默認比較函數是equal_to,因爲不需要保持有序;
儘量用算法替代手寫的循環
1)效率相比手寫更高;
STL的代碼都是C++專家寫出來的,專家寫出來的代碼在效率上很難超越;
除非我們放棄了某些特性來滿足特定的需求,可能能快過stl;比如,基於特定場合下的編程,放棄通用性,可移植性;
2)不容易出錯;
3)使用高層次思維編程
相比彙編而言,C是高級語言;一條C語言語句,用匯編寫需要好幾條;
同樣的,在STL的世界中,我們也有高層次的術語:
高層次的術語:insert/find/for_each(STL算法)
低層次的詞彙:for /while(C++語法)
用高層次術語來思考編程,會更簡單;
儘量用成員函數代替同名的算法
1)基於效率考慮,成員函數知道自己這個容器和其他容器有哪些特有屬性,能夠利用到這些特性;而通用算法不可以;
2)對於關聯容器,成員函數find基於等價搜索;而通用算法find基於相等來搜索;可能導致結果不一樣;
使用函數對象代替裸函數作爲算法的輸入參數
因爲內聯,在函數對象的方式中,內聯有效,而作爲函數指針時,一般編譯器都不會內聯函數指針指向的函數;即使指定了inline;
比如:
inline bool doubleGreater(double d1, double d2)
{
return dl > d2;
}
vector v;
...
sort(v.begin(), v.end(), doubleGreater);
這個調用不是真的把doubleGreater傳給sort,它傳了一個doubleGreater的指針。
更好的方式是使用函數對象:
sort(v.begin(), v.end(), greater())
注:《effcient c++》中的實驗結論,使用函數對象一般是裸函數的1.5倍,最多能快2倍多
選擇合適的排序算法
需要排序前思考我們的必要需求,可能我們只是需要前多少個元素,這時並不需要使用sort這種線性時間的工具,性能消耗更少的parttition可能是更好的選擇;
以下算法的效率從左到右依次遞減:
partition > stable_partition / nth_element / patical_sort / sort / stable_sort
功能說明:
partition :將集合分隔爲滿足和不滿足某個標準兩個區間;
stable_partition :partition的穩定版本;
nth_element :獲取任意順序的前N個元素;
patical_sort :獲取前N個元素,這個N個元素已排序;
sort:排序整個區間;
stable_sort:sort的穩定版本;
選擇合適的容器
爲什麼vector不提供push_front()成員方法?因爲效率太差,如果有太多從前面插入的需求,就不應該使用vector,而用list;
關心查找速度,首先應該考慮散列容器(非標準STL容器,如:unordered_map,unordered_set);其次是排序的vector,然後是標準的關聯容器;
參考
《effictive STL》
《Efficient C++》