1. 程式人生 > >C++STL幾種常用容器簡要歸納

C++STL幾種常用容器簡要歸納

本文參考李煜東《演算法競賽進階指南》,筆者作歸納總結。

本文將簡要介紹STL中vector,queue,priority_queue,deque,set,multiset,map,bitset八種容器及其操作方法。

vector

使用此容器需在程式前加上標頭檔案#include< vector >。 vector可理解為變長陣列,基於倍增思想。當以已申請vector長度為m時,若實際長度n=m,則申請長度為2m的陣列,將內容轉移至新地址上,並釋放舊空間;刪除元素時,若n<=m/4,則釋放一半空間。 vector容器能像陣列一樣隨機訪問第i個數a[i],但不支援隨機插入,其將元素插入尾部時的攤還代價為3。

#include<vector>       //標頭檔案
vector<int> a;
vector<int> b[100];
struct rec{···};
vector<rec> c;           //各種宣告

vector<int>::iterator it;           //vector的迭代器,與指標類似

a.size()            //返回實際長度(元素個數),O(1)複雜度
a.empty()           //容器為空返回1,否則返回0,O(1)複雜度
a.clear()           //把vector清空
a.begin()           //返回指向第一個元素的迭代器,*a.begin()與a[0]作用相同
a.end()             //越界訪問,指向vector尾部,指向第n個元素再往後的邊界
a.front()           //返回第一個元素的值,等價於*a.begin和a[0]
a.back()            //返回最後一個元素的值,等價於*--a.begin()和a[size()-1]
a.push_back(x)      //把元素x插入vector尾部
a.pop_back()        //刪除vector中最後一個元素

迭代器使用與指標類似,可如下遍歷整個容器

for ( vector<int>::iterator it=a.begin() ; it!=a.end() ; it++ )

queue

迴圈佇列queue需使用標頭檔案< queue >

queue<int> q;
struct rec{···};queue<rec> q;      //宣告

q.push(x);           //從隊尾使元素x入隊,O(1)
q.pop(x);            //使隊首元素出隊,O(1)
int x=q.front();     //詢問隊首元素的值,O(1)
int y=q.back();      //詢問隊尾元素的值,O(1)

priority_queue

優先佇列priority_queue可理解為一個大根二叉堆必須定義“小於號”,而int,string本身就能比較。同樣需要標頭檔案< queue >。 其宣告與queue相似。

priority_queue<int> q;
priority_queue<pair<int,int>> q;

q.push(x);         //插入   O(log n)
q.pop();           //刪除堆頂元素    O(log n)
q.top();           //查詢堆頂元素   O(1)

可通過插入元素的相反數取出時再取反,或過載“小於號”的方式實現小根堆,通過懶惰刪除法實現隨機刪除操作。

deque

雙端佇列,是一個支援在兩端高效插入或刪除元素的連續線性儲存空間,可像陣列一樣隨機訪問,使用前加標頭檔案< deque >。

q.begin()/q.end()              //頭/尾迭代器,與vector類似
q.front()/q.back()             //頭/尾元素,與queue類似
q.push_back(x)/q.push_front(x) //從隊尾/隊頭入隊
q.pop_back(x)/q.pop_front(x)   //從隊尾/隊頭出隊
q.clear()                      //清空佇列

clear複雜度為O(n),其餘為O(1)。

set/multiset

兩容器相似,但set為有序集合,元素不能重複,multiset為有序多重集合,可包含若干相等的元素,內部通過紅黑樹實現,支援的函式基本相同,同樣必須定義“小於號”運算子,標頭檔案為< set >。 其迭代器不支援隨機訪問,支援星號(*)結束引用,僅支援 ++ 、-- 兩個與算術有關的操作。迭代器it++,則指向從小到大排序的結果中排在it下一名的元素,兩操作時間複雜度均為O(log n)。

q.size()
q.empty()
q.clear()
q.begin()/q.end()          //作用與上文幾種容器類似
q.insert(x)                //將元素x插入集合中,O(log n)
q.find(x)                  //查詢等於x的元素,返回其迭代器,無則返回q.end(),O(log n)
q.lower_bound(x)           //查詢>=x的元素中最小的一個,返回指向該元素的迭代器
q.upper_bound(x)           //查詢>x的元素中最小的一個,返回指向該元素的迭代器
q.erase(it)                //刪除迭代器it指向的元素,O(log n)
q.erase(x)                 //刪除所有等於x的元素,複雜度為O(k+log n),k為被刪除的元素個數
q.count(x)                 //返回等於x的元素個數,O(k+log n),k為元素x的個數

若想從multiset中刪除之多一個等於x的元素,可執行

if((it=q.find(x))!=q.end())
	q.erase(it);

map

map容器是一個鍵值對key-value的對映。內部為一棵以key為關鍵碼的紅黑樹,key和value可以是任意型別,其中key必須定義“小於號”運算子,宣告方法為

map<key_type,value_type> name;

例如

map<long long,bool> vis;
map<string,int> hash;
q.size()
q.empty()
q.clear()
q.begin()/q.end()          //作用與上文幾種容器類似
q.insert(x)                //插入,引數為pair<key_type,value_type>
q.erase(it)                //刪除,引數可以是pair或迭代器
q.find(x)                  //查詢key為x的二元組,返回其迭代器,無則返回q.end(),O(log n)
q[key]                     //可得到key對應的value,也可對key進行賦值,改變對應的value
                           //若查詢的key不存在,則會新建一個二元組(key,zero)。

bitset

bitset可看作一個多位二進位制數,每8位佔用1個位元組,相當於採用了狀態壓縮的二進位制陣列,並支援基本的位運算。一般以32位整數的運算次數為基準估算執行時間,n位bitset執行一次的位運算複雜度可視為n/32,效率較高。標頭檔案。 同樣具有~,&,|,^,<<,>>操作符,==,!=可比較二進位制數是否相等

bitset<10000> q;      //宣告一個10000位的二進位制數
q[k]                  //表示q的第k位,可取值,賦值,最低位為q[0]
q.count()             //返回有多少位1
q.none()              //所有位都為0則返回true,至少1位為1則返回false
q.any()               //所有位都為0則返回false,至少1位為1則返回true,與函式none相反
q.set()               //把所有位變為1
q.set(k,v)            //把第k位變為v,即q[k]=v
q.reset()             //把所有位變為0
q.reset(k)            //把第k位變為0,即q[k]=0
q.flip()              //把所有位取反,即s=~s
q.flip(k)             //把第k位取反,即q[k]^=1

此上所有容器均可視作一個前閉後開的結構。