容器:一些特定類型對象的集合
順序容器:爲程序員提供控制元素存儲方式和一定順序訪問元素的能力。
標準容器如下(標準庫):快速順序訪問元素的能力
- vector :可變大小數組 連續空間存儲,所以在兩端添刪元素快速,中間添刪很慢。
- deque:雙端隊列 連續空間存儲,所以在兩端添刪元素快速,中間添刪很慢。
- forward_list :單向鏈表 非連續空間存儲,但只能在尾部添刪元素。
- list :雙向鏈表。 非連續空間存儲,都很快,但是浪費空間
- array:固定大小數組。連續空間存儲,不能增刪、擴張大小。
- string:於vectpr類似,但專門保存字符。 連續空間存儲,所以在兩端添刪元素快速,中間添刪很慢。
增刪元素速度:
- vector:連續空間存儲,所以在兩端添刪元素快速,中間添刪很慢。
- deque:連續空間存儲,所以在兩端添刪元素快速,中間添刪很慢。
- forward_list: 非連續空間存儲,但只能在尾部添刪元素。
- list:非連續空間存儲,都很快,但是浪費空間。
- array:連續空間存儲,不能增刪、擴張大小。
- string :連續空間存儲,所以在尾部添刪元素快速,中間添刪很慢。
遍歷速度:
- vector :可用下標形式或者迭代器遍歷,速度很快
- deque:速度很快
- forward_list :遍歷較慢,不支持元素隨機訪問,因爲只能從頭開始遍歷,查找某元素,較慢
- list :遍歷較慢,不支持元素隨機訪問,因爲只能從頭開始遍歷,查找某元素,較慢
- array:連續空間存儲,可通過下標或迭代器遍歷,速度很快。
- string:可用下標形式或者迭代器遍歷,速度很快。
注意:
1. 使用vector是更好的選擇,除非又理由選擇其他容器
2.儘量使用迭代器,不能使用下標操作,避免隨機訪問,防止越界。
選擇條件:
- 若要求可隨機訪問元素,則應用
vector
、deque
。 - 若要求在容器中間插入或刪除元素,則選擇
list
或forward_list
- 若在兩頭插入或刪除元素,不會在中間位置插入或刪除,則使用
deque
迭代器
迭代器範圍:由一對迭代器表示,分貝指向同一個容器的元素或尾元素的後一個位置(begin、end或first、last)。
左閉合區間:因爲end、last表示最後一個元素的後一個位置,所以[bgein,end)。
使用左閉合範圍的假定:
- 如果begin和end相等,則範圍爲空
- 若begin和end不等,則範圍至少包含一個元素,begin指向第一個元素
- 可對begin遞增,使得begin=end
while(begin!=end)
*begin=v //範圍不空,則begin解引用進行賦值
++begin //移動迭代器,指向下一個元素
C++11 auto
自動判斷類型
list<string> a={"a","ab","abc"};
auto it1=a.begin(); // list<string>:iterator
auto it2=a.rbegin(); // list<string>::reverse_iterator
auto it3=a.cbegin(); // list<string>::const_iterator
auto it4=crbegin(); // list<string>::const_reverse_iterator
容器定義和初始化
每個容器類型都定義了一個默認構造函數,除了array之外,其他容器默認構造函數都會創建一個指定類型的空容器,且都可以接受指定容器大小和元素初始值的參數。
C S //默認構造函數,若C爲array,則元素按默認方式初始化,否則C爲空。
C c1(c2); //c1初始化爲c2的拷貝,c1和c2必須是相同類型的容器,且保存相同類型的元素。
C c{a,b,c...} //c初始化列表中元素的拷貝。
C c={a,b,c...};
C c(b,e); //c初始化爲迭代器b和e指定範圍的元素的拷貝。元素類型必須相同。
只有順序容器(不包括array)的構造函數才能接受大小參數
C s(n); //包含n個元素,這些元素進行了值初始化,構造函數是explicit的
C s(n,t); //s包含值爲t的n個元素
將一個容器初始化爲另一個容器的拷貝
方法1:直接拷貝容器。(容器類型必須相同,元素類型必須相同)
list <string>s1;
slit<string> s2(s1);
方法2:拷貝由迭代器指定的元素範圍(array除外),(容器類型不必相同,元素類型也可以不同)
list <string>s1;
slit<string> s2(s1.begin(),s1.end());
array
的初始化和賦值
定義array
時,不僅需要指定元素類型,還需要指定大小。
array<int,10> c//保存10個int類型的數組
array<int,10>::size_type s=c.size(); //保存c的大小
- 初始化:
array<int,10> c; //默認初始化
array<int,10> c1{1,2,3,3}; //列表初始化
array<int,10> c2={1,2,3,3}; //列表初始化
array<int,10> c3=c; // 拷貝array數組類型
注意:雖然不能對內置數組類型進行拷貝,但是array
可以。
2. 賦值
array
允許賦值,但是=號兩面運算對象必須具有相同類型。
array<.int,10> c1;
array<int,10> c2;
c2=c1; //正確,兩邊都是array,元素都是int
c2={0}; //錯誤,不能用花括號賦值,只能定義
刪除元素
erase
:從容器中指定位置刪除元素。可以刪除由一個迭代器指定的單個元素或一對迭代器指定範圍的所有元素。
返回值
:返回指向刪除的最後一個元素之後位置的迭代器。
list<int> lst={1,2,3,4,5,6,7,8,3};
auto it=lst.begin(); //it類型爲list<int>::iterator,指向第一個元素的迭代器
while(it!=lst.end())
{
if(*it%2)
it=lst.erase(it);//若該元素爲奇數,則刪除
else
++it;
}
刪除多個元素,通過一對迭代器。
ele1=slt.erase(ele1,ele2); //返回指向最後一個被刪除元素之後位置的迭代器,執行後ele1==ele2。
刪除所有元素:clear
或erase
,不適用於array
:
slt.clear();
slt.erase(slt.begin(),slt.end());
改變容器大小: resize
, 不適用於array
:
list<int> lst(10,20); //10個int,每個值都是20.
lst.resize(15); //將5個值爲0的值添加到末尾
lst.resize(10,20); //將10個值爲20的元素添加到尾部
lst.resize(5); //只保存5個元素,最前面五個
標準庫愛採用了可以減少容器空間分配次數的策略,當不得不獲取新的內存空間時,通常分配更大的內存空間。
管理容器的成員函數
//只適用於vector和string
c.capacity(); //不重新分配內存空間,c可以保存多少元素
c.reserve(); //分配至少能容納n個元素的內存空間
shrink_to_fit
只適用於vector
、string
和deque
:
新標準中,我們調用shrink_to_fit
退回不需要的內存空間。