c++ STL各容器介紹
連結:https://zhuanlan.zhihu.com/p/130905242
來源:知乎
一、什麼是STL?
1、STL(Standard Template Library),即標準模板庫,是一個高效的C++程式庫,包含了諸多常用的基本資料結構和基本演算法。為廣大C++程式設計師們提供了一個可擴充套件的應用框架,高度體現了軟體的可複用性。
2、從邏輯層次來看,在STL中體現了泛型化程式設計的思想(generic programming)。在這種思想裡,大部分基本演算法被抽象,被泛化,獨立於與之對應的資料結構,用於以相同或相近的方式處理各種不同情形。
3、從實現層次看,整個STL是以一種型別引數化(type parameterized)的方式實現的,基於模板(template)。
STL有六大元件,但主要包含容器、迭代器和演算法三個部分。
- 容器(Containers):用來管理某類物件的集合。每一種容器都有其優點和缺點,所以,為了應付程式中的不同需求,STL 準備了七種基本容器型別。
- 迭代器(Iterators):用來在一個物件集合的元素上進行遍歷動作。這個物件集合或許是個容器,或許是容器的一部分。每一種容器都提供了自己的迭代器,而這些迭代器瞭解該種容器的內部結構。
- 演算法(Algorithms):用來處理物件集合中的元素,比如 Sort,Search,Copy,Erase 那些元素。通過迭代器的協助,我們只需撰寫一次演算法,就可以將它應用於任意容器之上,這是因為所有容器的迭代器都提供一致的介面。
STL 的基本觀念就是將資料和操作分離。資料由容器進行管理,操作則由演算法進行,而迭代器在兩者之間充當粘合劑,使任何演算法都可以和任何容器互動運作。這一篇部落格暫時只介紹容器,下一篇介紹迭代器。
二、容器(Containers)
容器用來管理某類物件。為了應付程式中的不同需求,STL 準備了兩類共七種基本容器型別:
- 序列式容器(Sequence containers),此為可序群集,其中每個元素均有固定位置—取決於插入時機和地點,和元素值無關。如果你以追加方式對一個群集插入六個元素,它們的排列次序將和插入次序一致。STL提供了三個序列式容器:向量(vector)、雙端佇列(deque)、列表(list),此外你也可以把 string 和 array 當做一種序列式容器。
- 關聯式容器(Associative containers),此為已序群集,元素位置取決於特定的排序準則以及元素值,和插入次序無關。如果你將六個元素置入這樣的群集中,它們的位置取決於元素值,和插入次序無關。STL提供了四個關聯式容器:集合(set)、多重集合(multiset)、對映(map)和多重對映(multimap)。
示意圖如下圖所示:
2.1 vector
vector(向量): 是一種序列式容器,事實上和陣列差不多,但它比陣列更優越。一般來說陣列不能動態拓展,因此在程式執行的時候不是浪費記憶體,就是造成越界。而 vector 正好彌補了這個缺陷,它的特徵是相當於可拓展的陣列(動態陣列),它的隨機訪問快,在中間插入和刪除慢,但在末端插入和刪除快。
特點
- 擁有一段連續的記憶體空間,並且起始地址不變,因此它能非常好的支援隨機存取
例子
以下例子針對整型定義了一個 vector,插入 6 個元素,然後列印所有元素:
#include <iostream> #include <vector> using namespace std; int main(int argc, char* argv[]) { vector<int> vecTemp; for (int i = 0; i<6; i++) vecTemp.push_back(i); for (int i = 0; i<vecTemp.size(); i++) cout << vecTemp[i] <<" "; // 輸出:0 1 2 3 4 5 return 0; }
作者:luckyum
連結:https://zhuanlan.zhihu.com/p/130905242
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
2.2 deque
deque(double-ended queue)是由一段一段的定量連續空間構成。一旦要在 deque 的前端和尾端增加新空間,便配置一段定量連續空間,串在整個 deque 的頭端或尾端。因此不論在尾部或頭部安插元素都十分迅速。 在中間部分安插元素則比較費時,因為必須移動其它元素。deque 的最大任務就是在這些分段的連續空間上,維護其整體連續的假象,並提供隨機存取的介面。
特點
- 按頁或塊來分配儲存器的,每頁包含固定數目的元素。
- deque 是 list 和 vector 的折中方案。兼有 list 的優點,也有vector 隨機線性訪問效率高的優點。
優缺點和適用場景
優點:支援隨機訪問,即 [] 操作和 .at(),所以查詢效率高;可在雙端進行 pop,push。
缺點:不適合中間插入刪除操作;佔用記憶體多。
適用場景:適用於既要頻繁隨機存取,又要關心兩端資料的插入與刪除的場景。
例子
以下例子聲明瞭一個浮點型別的 deque,並在容器尾部插入 6 個元素,最後打印出所有元素。
#include <iostream>
#include <deque>
using namespace std;
int main(int argc, char* argv[])
{
deque<float> dequeTemp;
for (int i = 0; i<6; i++)
dequeTemp.push_back(i);
for (int i = 0; i<dequeTemp.size(); i++)
cout << dequeTemp[i] << " "; // 輸出:0 1 2 3 4 5
return 0;
}
2.3 list
List 由雙向連結串列(doubly linked list)實現而成,元素也存放在堆中,每個元素都是放在一塊記憶體中,他的記憶體空間可以是不連續的,通過指標來進行資料的訪問,這個特點使得它的隨機存取變得非常沒有效率,因此它沒有提供 [] 操作符的過載。但是由於連結串列的特點,它可以很有效率的支援任意地方的插入和刪除操作。
特點
- 沒有空間預留習慣,所以每分配一個元素都會從記憶體中分配,每刪除一個元素都會釋放它佔用的記憶體。
- 在哪裡新增刪除元素效能都很高,不需要移動記憶體,當然也不需要對每個元素都進行構造與析構了,所以常用來做隨機插入和刪除操作容器。
- 訪問開始和最後兩個元素最快,其他元素的訪問時間一樣。
優缺點和適用場景
優點:記憶體不連續,動態操作,可在任意位置插入或刪除且效率高。
缺點:不支援隨機訪問。
適用場景:適用於經常進行插入和刪除操作並且不經常隨機訪問的場景。
例子
以下例子產生一個空 list,準備放置字元,然後將 'a' 至 'z' 的所有字元插入其中,利用迴圈每次列印並移除集合的第一個元素,從而打印出所有元素:
#include <iostream>
#include <list>
using namespace std;
int main(int argc, char* argv[])
{
list<char> listTemp;
for (char c = 'a'; c <= 'z'; ++c)
listTemp.push_back(c);
while (!listTemp.empty())
{
cout <<listTemp.front() << " ";
listTemp.pop_front();
}
return 0;
}
成員函式empty()
的返回值告訴我們容器中是否還有元素,只要這個函式返回 false,迴圈就繼續進行。迴圈之內,成員函式front()
會返回第一個元素,pop_front()
函式會刪除第一個元素。
注意:list<指標> 完全是效能最低的做法,還不如直接使用 list<物件> 或使用 vector<指標> 好,因為指標沒有構造與析構,也不佔用很大記憶體。
2.4 set
set(集合)由紅黑樹實現,其內部元素依據其值自動排序,每個元素值只能出現一次,不允許重複。
特點
- set 中的元素都是排好序的,集合中沒有重複的元素;
- map 和 set 的插入刪除效率比用其他序列容器高,因為對於關聯容器來說,不需要做記憶體拷貝和記憶體移動。
優缺點和適用場景
優點:使用平衡二叉樹實現,便於元素查詢,且保持了元素的唯一性,以及能自動排序。
缺點:每次插入值的時候,都需要調整紅黑樹,效率有一定影響。
適用場景:適用於經常查詢一個元素是否在某群集中且需要排序的場景。
例子
下面的例子演示 set(集合)的兩個特點:
#include <iostream>
#include <set>
using namespace std;
int main(int argc, char* argv[])
{
set<int> setTemp;
setTemp.insert(3);
setTemp.insert(1);
setTemp.insert(2);
setTemp.insert(1);
set<int>::iterator it;
for (it = setTemp.begin(); it != setTemp.end(); it++)
{
cout << *it << " ";
}
return 0;
}
輸出結果:1 2 3。一共插入了 4 個數,但是集合中只有 3 個數並且是有序的,可見之前說過的 set 集合的兩個特點,有序和不重複。
當 set 集合中的元素為結構體時,該結構體必須實現運算子 ‘<’ 的過載:
#include <iostream>
#include <set>
#include <string>
using namespace std;
struct People
{
string name;
int age;
bool operator <(const People p) const
{
return age < p.age;
}
};
int main(int argc, char* argv[])
{
set<People> setTemp;
setTemp.insert({"張三",14});
setTemp.insert({ "李四", 16 });
setTemp.insert({ "隔壁老王", 10 });
set<People>::iterator it;
for (it = setTemp.begin(); it != setTemp.end(); it++)
{
printf("姓名:%s 年齡:%d\n", (*it).name.c_str(), (*it).age);
}
return 0;
}
/*
輸出結果
姓名:王二麻子
作者:luckyum年齡:10 姓名:張三 年齡:14 姓名:李四 年齡:16 */
連結:https://zhuanlan.zhihu.com/p/130905242
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
可以看到結果是按照年齡由小到大的順序排列。另外 string 要使用c_str()
轉換一下,否則打印出的是亂碼。
另外 Multiset 和 set 相同,只不過它允許重複元素,也就是說 multiset 可包括多個數值相同的元素。這裡不再做過多介紹。
2.5 map
map 由紅黑樹實現,其元素都是 “鍵值/實值” 所形成的一個對組(key/value pairs)。每個元素有一個鍵,是排序準則的基礎。每一個鍵只能出現一次,不允許重複。
map 主要用於資料一對一對映的情況,map 內部自建一顆紅黑樹,這顆樹具有對資料自動排序的功能,所以在 map 內部所有的資料都是有序的。比如一個班級中,每個學生的學號跟他的姓名就存在著一對一對映的關係。
特點
- 自動建立 Key - value 的對應。key 和 value 可以是任意你需要的型別。
- 根據 key 值快速查詢記錄,查詢的複雜度基本是 O(logN),如果有 1000 個記錄,二分查詢最多查詢 10次(1024)。
- 增加和刪除節點對迭代器的影響很小,除了那個操作節點,對其他的節點都沒有什麼影響。
- 對於迭代器來說,可以修改實值,而不能修改 key。
優缺點和適用場景
優點:使用平衡二叉樹實現,便於元素查詢,且能把一個值對映成另一個值,可以建立字典。
缺點:每次插入值的時候,都需要調整紅黑樹,效率有一定影響。
適用場景:適用於需要儲存一個數據字典,並要求方便地根據key找value的場景。
例子
#include "stdafx.h"
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
map<int, string> mapTemp;
mapTemp.insert({ 5,"張三" });
mapTemp.insert({ 3, "李四"});
mapTemp.insert({ 4, "隔壁老王" });
map<int, string>::iterator it;
for (it = mapTemp.begin(); it != mapTemp.end(); it++)
{
printf("學號:%d 姓名:%s\n", (*it).first, (*it).second.c_str());
}
return 0;
}
/*
輸出結果:
學號:3 姓名:李四
學號:4 姓名:隔壁老王
學號:5 姓名:張三
*/
multimap 和 map 相同,但允許重複元素,也就是說 multimap 可包含多個鍵值(key)相同的元素。這裡不再做過多介紹。
2.6 容器配接器
除了以上七個基本容器類別,為滿足特殊需求,STL還提供了一些特別的(並且預先定義好的)容器配接器,根據基本容器類別實現而成。包括:
1、stack
名字說明了一切,stack 容器對元素採取 LIFO(後進先出)的管理策略。
2、queue
queue 容器對元素採取 FIFO(先進先出)的管理策略。也就是說,它是個普通的緩衝區
作者:luckyum
連結:https://zhuanlan.zhihu.com/p/130905242
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。