C++STL容器和迭代器

一、簡介

  容器(container)用於存放數據的類模板。可變長數組、鏈表、平衡二叉樹等數據結構在 STL 中都被實現爲容器。程序員使用容器時,就是將容器類模板實例化爲容器類,須要指明容器中存放的元素是什麼類型的
  容器中能夠存放基本類型的變量,也能夠存放對象。對象或基本類型的變量被插入容器中時,實際插入的是對象或變量的一個複製品。程序員

1.1 容器分類

  容器分爲2類:順序容器和關聯容器
  順序容器:可變長動態數組 vector、雙端隊列 deque、雙向鏈表 list。之因此被稱爲順序容器,是由於元素在容器中的位置同元素的值無關,即容器不是排序的。將元素插入容器時,指定在什麼位置(尾部、頭部或中間某處)插入,元素就會位於什麼位置。
  關聯容器:set、multiset、map、multimap。
  關聯容器內的元素是排序的。插入元素時,容器會按必定的排序規則將元素放到適當的位置上,所以插入元素時不能指定位置。默認狀況下,關聯容器中的元素是從小到大排序(或按關鍵字從小到大排序)的,並且用<運算符比較元素或關鍵字大小。由於是排好序的,因此關聯容器在查找時具備很是好的性能。
  STL 還在兩類容器的基礎上屏蔽一部分功能,突出或增長另外一部分功能,實現了三種容器適配器:棧 stack、隊列 queue、優先級隊列 priority_queue。
  容器都是類模板。它們實例化後就成爲容器類。用容器類定義的對象稱爲容器對象。算法

二、容器的比較

  任何兩個容器對象,只要它們的類型相同,就能夠用 <、<=、>、>=、==、!= 進行詞典式的比較運算。假設 a、b 是兩個類型相同的容器對象,這些運算符的運算規則以下:
  a == b:若 a 和 b 中的元素個數相同,且對應元素均相等,則a == b的值爲 true,不然值爲 false。元素是否相等是用==運算符進行判斷的。
  a<b:規則相似於詞典中兩個單詞比較大小,從頭至尾依次比較每一個元素,若是發生 a 中的元素小於 b 中的元素的狀況,則a<b的值爲 true;若是沒有發生 b 中的元素小於 a 中的元素的狀況,且 a 中的元素個數比 b 少,a<b的值也爲 true;其餘狀況下值爲 false。元素比較大小是經過<運算符進行的。
  a != b:等價於 !(a == b)。
  a > b:等價於 b < a。
  a <= b:等價於 !(b < a)。
  a >= b:等價於 !(a < b)。數組

三、成員函數

全部容器都有如下兩個成員函數:
  int size():返回容器對象中元素的個數。
  bool empty():判斷容器對象是否爲空。數據結構

順序容器和關聯容器還有如下成員函數:
  begin():返回指向容器中第一個元素的迭代器。
  end():返回指向容器中最後一個元素後面的位置的迭代器。
  rbegin():返回指向容器中最後一個元素的反向迭代器。
  rend():返回指向容器中第一個元素前面的位置的反向迭代器。
  erase(...):從容器中刪除一個或幾個元素。該函數參數較複雜,此處省略。
  clear():從容器中刪除全部元素。函數

若一個容器是空的,則 begin() 和 end() 的返回值相等,rbegin() 和 rend() 的返回值也相等。
順序容器還有如下經常使用成員函數:
  front():返回容器中第一個元素的引用。
  back():返回容器中最後一個元素的引用。
  push_back():在容器末尾增長新元素。
  pop_back():刪除容器末尾的元素。
  insert(...):插入一個或多個元素。該函數參數較複雜,此處省略。性能

 

四、迭代器簡介

  要訪問順序容器和關聯容器中的元素,須要經過「迭代器(iterator)」進行。迭代器是一個變量,至關於容器和操縱容器的算法之間的中介。迭代器能夠指向容器中的某個元素,經過迭代器就能夠讀寫它指向的元素。this

五、分類

迭代器按照定義方式分紅如下四種。spa

5.1 正向迭代器

定義方法以下:指針

  容器類名::iterator 迭代器名;對象

5.2 常量正向迭代器

定義方法以下:

  容器類名::const_iterator 迭代器名;

5.3 反向迭代器

定義方法以下:

  容器類名::reverse_iterator 迭代器名;

5.4 常量反向迭代器

定義方法以下:

  容器類名::const_reverse_iterator 迭代器名;

六、用法示例

  經過迭代器能夠讀取它指向的元素,*迭代器名就表示迭代器指向的元素。經過很是量迭代器還能修改其指向的元素。迭代器均可以進行++操做。反向迭代器和正向迭代器的區別在於:
  對正向迭代器進行++操做時,迭代器會指向容器中的後一個元素;而對反向迭代器進行++操做時,迭代器會指向容器中的前一個元素。
  

  begin 成員函數返回指向容器中第一個元素的迭代器。++i 使得 i 指向容器中的下一個元素。end 成員函數返回的不是指向最後一個元素的迭代器,而是指向最後一個元素後面的位置的迭代器,所以循環的終止條件是i != v.end()。
  對於vector容器而言,也可使用size函數進行遍歷,相比於迭代器會更好。若迭代器指向了容器中最後一個元素的後面或第一個元素的前面,再經過該迭代器訪問元素,就有可能致使程序崩潰,這和訪問 NULL 或未初始化的指針指向的地方相似。
相比於後置運算符,前置運算符的執行速度更快。

CDemo CDemo::operator++ ()
{ //前置++
  ++n;
  return *this;
}
CDemo CDemo::operator ++(int k)
{ //後置++
  CDemo tmp(*this); //記錄修改前的對象
  n++;
  return tmp; //返回修改前的對象
}

  可知,後置++要多生成一個局部對象 tmp,所以執行速度比前置的慢。同理,迭代器是一個對象,STL 在重載迭代器的++運算符時,後置形式也比前置形式慢。所以最好習慣遇到循環控制變量時寫成前置。
  注意:容器適配器 stack、queue 和 priority_queue 沒有迭代器。容器適配器有一些成員函數,能夠用來對元素進行訪問。

七、迭代器功能分類

  不一樣容器的迭代器,其功能強弱有所不一樣。容器的迭代器的功能強弱,決定了該容器是否支持 STL 中的某種算法。經常使用的迭代器按功能強弱分爲輸入、輸出、正向、雙向、隨機訪問五種,這裏只介紹經常使用的三種。

4.1 正向迭代器

  假設 p 是一個正向迭代器,則 p 支持如下操做:++p,p++,*p。此外,兩個正向迭代器能夠互相賦值,還能夠用==和!=運算符進行比較。

4.2 雙向迭代器

  雙向迭代器具備正向迭代器的所有功能。除此以外,若 p 是一個雙向迭代器,則--p和p--都是有定義的。--p使得 p 朝和++p相反的方向移動。

4.3 隨機訪問迭代器

隨機訪問迭代器具備雙向迭代器的所有功能。若 p 是一個隨機訪問迭代器,i 是一個整型變量或常量,則 p 還支持如下操做:
  p+=i:使得 p 日後移動 i 個元素。
  p-=i:使得 p 往前移動 i 個元素。
  p+i:返回 p 後面第 i 個元素的迭代器。
  p-i:返回 p 前面第 i 個元素的迭代器。
  p[i]:返回 p 後面第 i 個元素的引用。
兩個隨機訪問迭代器 p一、p2 還能夠用 <、>、<=、>= 運算符進行比較。
  p1<p2的含義是:p1 通過若干次(至少一次)++操做後,就會等於 p2。其餘比較方式的含義與此相似。
對於兩個隨機訪問迭代器 p一、p2,表達式p2-p1也是有定義的,其返回值是 p2 所指向元素和 p1 所指向元素的序號之差(也能夠說是 p2 和 p1 之間的元素個數減一)。

容器        迭代器功能
vector       隨機訪問
deque        隨機訪問
list         雙向
set / multiset   雙向
map / multimap   雙向
stack       不支持迭代器
queue       不支持迭代器
priority_queue   不支持迭代器

五、迭代器的輔助函數

STL 中有用於操做迭代器的三個函數模板,它們是:
  advance(p, n):使迭代器 p 向前或向後移動 n 個元素。
  distance(p, q):計算兩個迭代器之間的距離,即迭代器 p 通過多少次 + + 操做後和迭代器 q 相等。若是調用時 p 已經指向 q 的後面,則這個函數會陷入死循環。
  iter_swap(p, q):用於交換兩個迭代器 p、q 指向的值。
須要包含頭文件 algorithm。

相關文章
相關標籤/搜索