1、STL簡介node
(一)、泛型程序設計程序員
泛型編程(generic programming)
將程序寫得儘量通用
將算法從數據結構中抽象出來,成爲通用的
C++的模板爲泛型程序設計奠基了關鍵的基礎
算法
(二)、什麼是STL編程
一、STL(Standard Template Library),即標準模板庫,是一個高效的C++程序庫。
二、包含了諸多在計算機科學領域裏經常使用的基本數據結構和基本算法。爲廣大C++程序員們提供了一個可擴展的應用框架,高度體現了軟件的可複用性安全
三、從邏輯層次來看,在STL中體現了泛型化程序設計的思想(generic programming)
數據結構
在這種思想裏,大部分基本算法被抽象,被泛化,獨立於與之對應的數據結構,用於以相同或相近的方式處理各類不一樣情形。框架
四、從實現層次看,整個STL是以一種類型參數化(type parameterized)的方式實現的
函數
基於模板(template)spa
2、STL組件操作系統
Container(容器) 各類基本數據結構
Adapter(適配器) 可改變containers、Iterators或Function object接口的一種組件
Algorithm(算法) 各類基本算法如sort、search…等
Iterator(迭代器) 鏈接containers和algorithms
Function object(函數對象)
Allocator(分配器)
(一)、容器
容器類是容納、包含一組元素或元素集合的對象
七種基本容器:
向量(vector)、雙端隊列(deque)、列表(list)、集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)
標準容器的成員絕大部分都具備共同的名稱
序列式容器
序列式容器Sequence containers,其中每一個元素均有固定位置——取決於插入時機和地點,和元素值無關。(vector、deque、list)
關聯式容器
關聯式容器Associative containers,元素位置取決於特定的排序準則以及元素值,和插入次序無關。(set、multiset、map、multimap)
一、須要頻繁在序列中間位置上進行插入和/或刪除操做且不須要過多地在序列內部進行長距離跳轉,應該選擇list
二、vector頭部與中間插入刪除效率較低,在尾部插入與刪除效率高。
三、deque是在頭部與尾部插入與刪除效率較高
set/map/multiset/multimap
set,同map同樣,全部元素都會根據元素的鍵值自動被排序,由於set/map二者的全部各類操做,都只是轉而調用RB-tree的操做行爲,不過,值得注意的是,二者都不容許兩個元素有相同的鍵值。
不一樣的是:set的元素不像map那樣能夠同時擁有實值(value)和鍵值(key),set元素同時擁有實值和鍵值,且實值就是鍵值,鍵值就是實值,而map的全部元素都是pair,同時擁有實值(value)和鍵值(key),pair的第一個元素被視爲鍵值,第二個元素被視爲實值。
至於multiset/multimap,他們的特性及用法和set/map徹底相同,惟一的差異就在於它們容許鍵值重複,即全部的插入操做基於RB-tree的insert_equal()而非insert_unique()。In computer science, a multimap (sometimes also multihash) is a generalization of a map or associative array
abstract data type in which more than one value may be associated with and returned for a given key.
摘自 sgi stl 紅黑樹數據結構定義:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
typedef bool _Rb_tree_Color_type; const _Rb_tree_Color_type _S_rb_tree_red = false; const _Rb_tree_Color_type _S_rb_tree_black = true; struct _Rb_tree_node_base { typedef _Rb_tree_Color_type _Color_type; typedef _Rb_tree_node_base* _Base_ptr; _Color_type _M_color; _Base_ptr _M_parent; _Base_ptr _M_left; _Base_ptr _M_right; static _Base_ptr _S_minimum(_Base_ptr __x) { while (__x->_M_left != 0) __x = __x->_M_left; return __x; } static _Base_ptr _S_maximum(_Base_ptr __x) { while (__x->_M_right != 0) __x = __x->_M_right; return __x; } }; template <class _Value> struct _Rb_tree_node : public _Rb_tree_node_base { typedef _Rb_tree_node<_Value>* _Link_type; _Value _M_value_field; }; |
hash_set/hash_map/hash_multiset/hash_multimap
hash_set/hash_map,二者的一切操做都是基於hashtable之上。不一樣的是,hash_set同set同樣,同時擁有實值和鍵值,且實值就是鍵值,鍵值就是實值,而hash_map同map同樣,每個元素同時擁有一個實值(value)和一個鍵值(key),因此其使用方式,和上面的map基本相同。但因爲hash_set/hash_map都是基於hashtable之上,因此不具有自動排序功能。爲何? 由於hashtable沒有自動排序功能。
至於hash_multiset/hash_multimap的特性與上面的multiset/multimap徹底相同,惟一的差異就是它們hash_multiset/hash_multimap的底層實現機制是hashtable(而multiset/multimap,上面說了,底層實現機制是RB-tree),因此它們的元素都不會被自動排序,不過也都容許鍵值重複。
因此說白了,什麼樣的結構決定其什麼樣的性質,由於set/map/multiset/multimap都是基於RB-tree之上,因此有自動排序功能,而hash_set/hash_map/hash_multiset/hash_multimap都是基於hashtable之上,因此不含有自動排序功能,至於加個前綴multi_無非就是容許鍵值重複而已。
std::tr1::unordered_map 是無序哈希表,但操做效率要比 std::map、std::hash_map、 __gnu_cxx::hash_map 都要高,能夠研究一下。
(二)、迭代器
一、迭代器Iterators,用來在一個對象羣集(collection of objects)的元素上進行遍歷。這個對象羣集或許是個容器,或許是容器的一部分。迭代器的主要好處是,爲全部容器提供了一組很小的公共接口。迭代器以++進行累進,以*進行提領,於是它相似於指針,咱們能夠把它視爲一種smart pointer
二、好比++操做能夠遍歷至羣集內的下一個元素。至於如何作到,取決於容器內部的數據組織形式。
三、每種容器都提供了本身的迭代器,而這些迭代器可以瞭解容器內部的數據結構。
(三)、算法
算法Algorithms,用來處理羣集內的元素。它們能夠出於不一樣的目的而搜尋、排序、修改、使用那些元素。經過迭代器的協助,咱們能夠只需編寫一次算法,就能夠將它應用於任意容器,這是由於全部的容器迭代器都提供一致的接口。
(四)、適配器
一、適配器是一種接口類
爲已有的類提供新的接口
目的是簡化、約束、使之安全、隱藏或者改變被修改類提供的服務集合
二、三種類型的適配器:
容器適配器:用來擴展7種基本容器,它們和順序容器相結合構成棧、隊列和優先隊列容器
迭代器適配器(反向迭代器、插入迭代器、IO流迭代器)
函數適配器(函數對象適配器、成員函數適配器、普通函數適配器)
(五)、函數對象
一、函數對象(function object)也稱爲仿函數(functor)
二、一個行爲相似函數的對象,它能夠沒有參數,也能夠帶有若干參數。
三、任何重載了調用運算符operator()的類的對象都知足函數對象的特徵
四、函數對象能夠把它稱之爲smart function。
五、STL中也定義了一些標準的函數對象,若是以功能劃分,能夠分爲算術運算、關係運算、邏輯運算三大類。爲了調用這些標準函數對象,須要包含頭文件<functional>。
(六)、分配器
負責空間配置與管理。從實現的角度來看,配置器是一個實現了動態空間配置、空間管理、空間釋放的class template。
隱藏在這些容器後的內存管理工做是經過STL提供的一個默認的allocator實現的。固然,用戶也能夠定製本身的allocator,只要實現allocator模板所定義的接口方法便可,而後經過將自定義的allocator做爲模板參數傳遞給STL容器,建立一個使用自定義allocator的STL容器對象,如:
stl::vector<int, UserDefinedAllocator> array;
大多數狀況下,STL默認的allocator就已經足夠了。這個allocator是一個由兩級分配器構成的內存管理器,當申請的內存大小大於128byte時,就啓動第一級分配器經過malloc直接向系統的堆空間分配,若是申請的內存大小小於128byte時,就啓動第二級分配器,從一個預先分配好的內存池中取一塊內存交付給用戶,這個內存池由16個不一樣大小(8的倍數,8~128byte)的空閒列表組成,allocator會根據申請內存的大小(將這個大小round up成8的倍數)從對應的空閒塊列表取表頭塊給用戶。
這種作法有兩個優勢:
(1)小對象的快速分配。小對象是從內存池分配的,這個內存池是系統調用一次malloc分配一塊足夠大的區域給程序備用,當內存池耗盡時再向系統申請一塊新的區域,整個過程相似於批發和零售,起先是由allocator向總經商批發必定量的貨物,而後零售給用戶,與每次都向總經商要一個貨物再零售給用戶的過程相比,顯然是快捷了。固然,這裏的一個問題時,內存池會帶來一些內存的浪費,好比當只需分配一個小對象時,爲了這個小對象可能要申請一大塊的內存池,但這個浪費仍是值得的,何況這種狀況在實際應用中也並很少見。
(2)避免了內存碎片的生成。程序中的小對象的分配極易形成內存碎片,給操做系統的內存管理帶來了很大壓力,系統中碎片的增多不但會影響內存分配的速度,並且會極大地下降內存的利用率。之內存池組織小對象的內存,從系統的角度看,只是一大塊內存池,看不到小對象內存的分配和釋放。
參考:
C++ primer 第四版 Effective C++ 3rd C++編程規範