STL學習筆記(一)

1. 容器(Containers)

容器分爲兩類:前端

  1. 序列式容器(Sequence containers),此乃可序羣集,其中每一個元素均有固定位置————取決於插入時機和地點,和元素值無關。STL提供三個定義好的序列式容器:vector,deque,list
  2. 關聯式容器(Associative containers),此乃已序羣集,元素位置取決於特定的排序準則,即元素位置取決於元素值,和插入次序無關。STL提供四個關聯式容器:set,multiset,map,multimap

1.1 序列式容器

  • Vector Vector將其元素置於一個dynamic array中加以管理,容許隨機存取,便可以利用索引直接存取任何一個元素。 在array尾部附加或移除元素很是快速,但在array中部或頭部安插元素比較費時算法

  • Deque Deque與Vector同樣,也是一個dynamic array,能夠向兩端發展,所以不論在尾部或頭部安插元素都十分迅速,但在中間部分安插元素則比較費時express

  • List 1. List由雙向鏈表實做而成。 2. List不提供隨機存取,即List並無提供以operator[]直接存取元素的能力。 3. List的優點是:在任何位置上執行安插或刪除動做都很是迅速。數組

  • 序列式容器中,向容器首部或末端添加元素分別使用push_front和push_back函數,但vector中並未提供push_front函數數據結構

1.2 關聯式容器

關聯式容器依據特定的排序準則,自動爲其元素排序。排序準則以函數形式呈現,用來比較元素值(value)或元素鍵(key)。缺省狀況下以operator<進行比較,也能夠提供本身的比較函數,定義不一樣的排序準則。dom

  • Set Set的內部元素按其值自動排序,每一個元素只能出現一次。
  • Multiset Multiset和Set相同,只不過它容許元素重複。
  • Map Map的元素都是「實值/鍵值」所造成的一個對組,每一個元素都有一個鍵,是排序準則的基礎。每個鍵只能出現一次,不容許重複。Map可被視爲關聯式數組。
  • Multimap Multimap和Map相同,但容許元素重複,即Multimap可包含多個鍵值相同的元素。Multimap可被當作「字典」
  • **全部關聯式容器都有一個可供選擇的template參數,指明排序準則。缺省採用operator<。

2. 容器適配器(Container Adapter)

除了上述容器類別,爲知足特殊需求,STL提供了一些特別的並預先定義好的容器適配器,包括:數據結構和算法

  • Stack Stack容器對元素採起LIFO管理策略。
  • Queue Queue容器對元素採起FIFO管理策略。
  • Priority Queue Priority Queue容器中的元素能夠擁有不一樣的優先級。

3. 迭代器

迭代器是一個「可遍歷STL容器內所有或部分元素」的對象。一個迭代器用來指出容器中的一個特定位置。其基本操做以下:函數

  • operator* 返回當前位置上的元素值。若是該元素擁有成員,你能夠透過迭代器,直接以operator->取用它們。
  • operator++、operator-- 將迭代器前進或後退一個元素
  • operator==、operator!= 判斷兩個迭代器是否指向同一位置。
  • operator= 爲迭代器賦值。

3.1 全部容器類別都提供一些成員函數,使咱們能夠得到迭代器####

  • begin() 返回指向容器起始點的迭代器。
  • end() 返回一個指向容器結束點的迭代器。結束點在最後一個元素以後,這樣的迭代器稱爲「逾尾」迭代器。
  • rbegin() 返回一個指向最後一個元素的逆向迭代器
  • rend() 返回一個指向第一個元素前一個位置的逆向迭代器。

3.2 任何一種容器都定義有兩種迭代器性別:

  1. container::iterator 這種迭代器以「讀寫」模式遍歷元素。
  2. Container::const_iterator 這種迭代器以「只讀」模式遍歷元素。

3.3 迭代器分類

迭代器被劃分爲5類。STL預先定義好的全部容器中,其迭代器均屬於一下兩種類型:指針

  1. 雙向迭代器(Bidirectional iterator) 雙向迭代器能夠雙向行進:以++或--運算前進或後退。**list、set、multiset、map和multimap這些容器所提供的迭代器都屬於此類。
  2. 隨機存取迭代器(Random access iterator) 隨機存取迭代器不但具有雙向迭代器的全部屬性,還具有隨機訪問能力。更明確的說,他們提供了「迭代器算術運算」必要的操做符(和「通常指針的算術運算符」徹底對應)。你能夠對迭代器增長或減小一個偏移量、處理迭代器之間的距離、或是使用<和>之類的retational(相對關係)操做符來比較兩個迭代器。vector、deque和string所提供的迭代器都屬於此類。

爲了撰寫儘量與容器型別無關的範型程序代碼,最好不要使用隨機存取迭代器的特有操做。以下例,能夠在任何容器上運做:code

for (pos = col.begin();pos != col.end();++pos)
{
	...
}

而下面的程序代碼就不是全部容器都使用了:

for (pos = col.begin();pos < col.end();++pos)
{
	...
}

由於只有random access iterator才支持operator<。

3.4 迭代器適配器

迭代器是一個純粹抽象的概念:任何東西,只要其行爲相似迭代器,它就是一個迭代器。所以,能夠撰寫一些類別,具有迭代器接口,但有着各不相同的行爲。STL提供了數個預先定義的特殊適配器,即迭代器適配器:

  • Insert iterator(安插型迭代器) 安插型迭代器能夠解決算法的「目標空間不足」問題。
  1. Back inserter:內部調用push_back(),在容器尾端插入元素(追加)。
copy (col1.begin(),col1.end(),back_inserter(col2));

固然,只有在提供push_back()成員函數的容器中,back inserter才能派上用場。 2. Front inserter:內部調用push_front(),將元素安插於容器最前端。

copy (col1.begin(),col1.end(),front_inserter(col2));

只有在提供push_front()成員函數的容器中,front inserter才能派上用場,在STL中,這樣的容器是deque和list。 3. General inserter:通常性的inserter,它的做用是將元素插入「初始化時接受之第二參數」所指定位置的前方,其內部調用insert()成員函數。全部STL容器都提供有insert()成員函數 |算是(expression)|Insert種類| |-|-| |back_inserter(container)|使用push_back()在容器尾端安插元素,元素排列次序和安插次序相同| |front_inserter(container)|使用push_front()在容器前段安插元素,元素排列次序和安插次序相反| |Insert(container,pos)|使用insert()在pos位置上安插元素,元素排列次序和安插次序相同|

  • Stream interator(流迭代器)
  1. istream_iterator<string>(cin) 產生一個可從「標準輸入流cin」中讀取數據的stream iterator。元素經過通常的operator>>被讀取進來
  2. istream_iterator<string>() 調用istream iterator的default構造函數,產生一個表明「流結束符號」的迭代器。
  3. ostream_iterator<string>(cout,"\n") 產生一個output stream iterator,經過operator<<向cout寫入數據,第二個參數(可由可無)被用來做爲元素之間的分隔符。
  • Reverse iterator(逆向迭代器) 全部容器均可以經過rbegin()和rend()成員函數產生reverse iterator。

4. 算法(Algorithm)

算法並不是容器類別的成員函數,而是一種搭配迭代器使用的全局函數。

  • 優點:全部算法只需實做一份,就能夠對全部容器運做,數據與操做被明確劃分開來,透過特定的接口彼此互動。
  • 劣勢:用法有失直觀;某些數據結構和算法之間並不兼容,或者即便兼容也會致使糟糕的效能)。

4.1 區間

  • 全部算法都用來處理一個或多個區間內的元素。
  • 全部算法處理的都是半開區間————包含起始元素位置但不包含結尾元素位置。 [begin,end]

4.2 一些簡單的算法

  1. min_element()、max+element() 調用他們時,必須傳入兩個參數,定義出欲處理的元素範圍。
  2. sort() 將由兩個參數設定出來的區間內的全部元素加以排序。還能夠出入一個排序準則,缺省的是operator<。
  3. find() 在給定範圍內搜尋某個值,若成功返回目標元素,若失敗,範圍一個「逾尾迭代器」,亦即find()所接受的第二個參數。
  4. reverse() 將區間內的元素反轉。
  5. distance() 返回兩個迭代器之間的距離

4.3 處理多個區間

一些算法能夠同時處理多個區間,一般必須設定第一個區間的起點和終點,至於其它區間,你只需設定起點便可,終點一般可由第一區間的元素數量推導出來。下面例子中,equal()從頭開始逐一比較col1和col2的全部元素:

if (equal (col1.begin(),col1.end(),col2.begin()))
{
	...
}

所以,col2中參與比較的元素數量,簡潔取決於col1內的元素數量。 因此,若是某個算法用來處理多個區間,那麼當你調用它時,務必確保第二區間所擁有的元素個數,至少和第一區間內的元素個數相同。 固然,若是目標區間空間不足,可使用安插型迭代器

4.4 更易型算法(Manipulating algorithm)

更易型算法是指會「刪除或重排或修改元素」的算法。

  1. 移除元素(remove) 算法remove()刪除指定區間中的某一元素。
remove (col1.begin(),col1.end(),3);

但remove()算法並無真正刪除某一元素所佔的空間,只是將以後的元素向前移動覆蓋了某一數值。事實上,remove返回了一個新的終點,利用這個新的終點,經過容器所提供的成員函數,能夠完全刪除一個元素。

col1.erase(remove(col1.begin(),col1.end(),3),col1.end());

爲什麼算法不本身直接調用erase()?這就是STL爲了獲取靈活性而付出的代價。經過「以迭代器爲接口」,STL將數據結構和算法分離開來。迭代器只是「容器中某一位置」的抽象概念而已,通常來講,迭代器對本身所屬的容器一無所知,任何「以迭代器訪問容器元素」的算法,都不得經過迭代器調用容器類別所提供的任何成員函數。

相關文章
相關標籤/搜索