C++中STL容器總結


整理博客不易,如果本文對你有所幫助,請給博主 點贊 + 收藏 + 關注!謝謝!

1、容器分類

STL中通常將容器分爲三類:順序容器關聯容器容器適配器
1、順序容器

是一種各元素之間有順序關係的線性表,是一種線性結構的可序羣集。順序性容器中的每個元素均有固定的位置,除非用刪除或插入的操作改變這個位置。順序容器的元素排列次序與元素值無關,而是由元素添加到容器裏的次序決定。

順序容器包括:

vector(向量)、list(列表)、deque(隊列)。

2、關聯容器

關聯式容器是非線性的樹結構,更準確的說是二叉樹結構。排序的容器底層是通過紅黑樹實現的,散列的是通過哈希表實現的。

關聯容器可分爲兩類:

(1)有序的:map(集合)、set(映射)、multimap(多重集合)、multiset(多重映射)。
(2)無序的:unordered_mapunordered_setunordered_multimapunordered_multiset

3、容器適配器
C++提供了三種容器適配器(container adapter):stack,queue和priority_queue。stack和queue基於deque實現,priority_queue基於vector實現。

適配器包括:

stack(棧) 、queue(隊列) 、priority_queue(優先級隊列) 。

容器類自動申請和釋放內存,因此無需new和delete操作。

2、順序型容器

2.1 vector容器

1、簡介

頭文件 #include <vector>

vector是STL提供的動態數組,數組的大小可以動態的變化,類似與一個線性數組,索引效率高,插入,刪除的效率很低,需要遍歷數據列表。

2、優缺點:

優點:支持隨機訪問,即 [] 操作和 .at(),查詢效率高。
缺點:當向頭部或中部,插入或刪除元素,插入效率低。

3、插入、刪除的時間複雜度:
在這裏插入圖片描述
4、定義與初始化

	vector<int> vec1;    //默認初始化,vec1爲空
	vector<int> vec2(vec1);  //使用vec1初始化vec2
	vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2
	vector<int> vec4(10);    //10個值爲0的元素
	vector<int> vec5(10,4);  //10個值爲4的元素
	vector<string> vec6(10,"null");    //10個值爲null的元素
	vector<string> vec7(10,"hello");  //10個值爲hello的元素

5、常用的操作方法

 	vec1.push_back(100);            //添加元素
    int size = vec1.size();         //元素個數
    bool isEmpty = vec1.empty();    //判斷是否爲空
    cout<<vec1[0]<<endl;        //取得第一個元素
    vec1.insert(vec1.end(),5,3);    //從vec1.back位置插入5個值爲3的元素
    vec1.pop_back();              //刪除末尾元素
    vec1.erase(vec1.begin(),vec1.end());//刪除之間的元素,其他元素前移
    cout<<(vec1==vec2)?true:false;  //判斷是否相等==、!=、>=、<=...
    vector<int>::iterator iter = vec1.begin();    //獲取迭代器首地址
    vector<int>::const_iterator c_iter = vec1.begin();   //獲取const類型迭代器
    vec1.clear();                 //清空元素

6、遍歷方法

    //下標法(vector的特有訪問方法,一般容器只能通過迭代器訪問)
    int length = vec1.size();
    for(int i=0;i<length;i++) {
       cout<<vec1[i]<<endl;
    }
    //迭代器法
    vector<int>::const_iterator iterator = vec1.begin();
    for(;iterator != vec1.end();iterator++) {
       cout<<*iterator<<endl;
    }

2.2 list容器

1、簡介

頭文件 #include <list>

由 deque 實現而成,元素也存放在堆中。設計目的是令容器任何位置的添加和刪除操作都很快速,作爲代價不支持元素的隨機訪問——爲了訪問一個元素,只能遍歷整個容器。

2、優缺點:

優點:內存不連續,動態操作,可在任意位置插入或刪除且效率高。
缺點:不支持隨機訪問。

3、插入、刪除的時間複雜度:
在這裏插入圖片描述
4、定義與初始化

	list<int> lst1;          //創建空list
    list<int> lst2(3);       //創建含有三個元素的list
    list<int> lst3(3,2); //創建含有三個元素的值爲2的list
    list<int> lst4(lst2);    //使用lst2初始化lst4
    list<int> lst5(lst2.begin(),lst2.end());  //同lst4

5、常用的操作方法

 	lst1.assign(lst2.begin(),lst2.end());  //分配值
    lst1.push_back(10);                    //添加值
    lst1.pop_back();                   //刪除末尾值
    lst1.begin();                      //返回首值的迭代器
    lst1.end();                            //返回尾值的迭代器
    lst1.clear();                      //清空值
    bool isEmpty1 = lst1.empty();          //判斷爲空
    lst1.erase(lst1.begin(),lst1.end());                        //刪除元素
    lst1.front();                      //返回第一個元素的引用
    lst1.back();                       //返回最後一個元素的引用
    lst1.insert(lst1.begin(),3,2);         //從指定位置插入3個值爲2的元素
    lst1.rbegin();                         //返回第一個元素的前向指針
    lst1.remove(2);                        //相同的元素全部刪除
    lst1.reverse();                        //反轉
    lst1.size();                       //含有元素個數
    lst1.sort();                       //排序
    lst1.unique();                         //刪除相鄰重複元素

6、遍歷方法

//迭代器法
    for(list<int>::const_iterator iter = lst1.begin();iter != lst1.end();iter++) {
       cout<<*iter<<endl;
    }

2.3 deque容器

1、簡介

頭文件 #include <deque>

deque容器類與vector類似,支持隨機訪問和快速插入刪除,它在容器中某一位置上的操作所花費的是線性時間。與vector不同的是,deque還支持從開始端插入數據:push_front()。其餘類似vector操作方法的使用。

2、優缺點:

優點:支持隨機訪問,即 [] 操作和 .at(),查詢效率高;當向兩端,插入或刪除元素,插入效率高。
缺點:當向中部,插入或刪除元素,插入效率低。

3、插入、刪除的時間複雜度:
在這裏插入圖片描述
4、定義與初始化

deque<int> c   ;  //產生一個空的deque,其中沒有任何元素
deque<int> c1(c2); //產生另一個同型deque的副本(所有元素都被拷貝)
deque<int> c(n) ;  //產生一個大小爲n的deque
deque<int> c(n , elem) ;  //產生一個大小爲n的deque,每個元素值都是elem。
dequer<int> c(begin,end); //產生一個deque,以區間[begin ; end]做爲元素初值

5、常用的操作方法

c.size();         //返回當前的元素數量
c.empty();       //判斷大小是否爲零。等同於c.size() == 0,但可能更快
c.max_size();    //可容納元素的最大數量
c.at(idx) ;       //返回索引爲idx所標示的元素。如果idx越界,拋出out_of_range
c[idx] ;         //返回索引idx所標示的元素。不進行範圍檢查
c.front() ;       //返回第一個元素,不檢查元素是否存在
c.back();        //返回最後一個元素
c.begin();       //返回一個隨機迭代器,指向第一個元素
c.end();         //返回一個隨機迭代器,指向最後元素的下一位置
c1 = c2  ;        //將c2的所有元素賦值給c1;
c.assign(n , elem);    //將n個elem副本賦值給c
c.assing(beg , end);   //將區間[beg;end]中的元素賦值給c;
c.push_back(elem);   //在尾部添加元素elem
c.pop_back()    ;    //移除最後一個元素(但不回傳)
c.push_front()   ;   //在頭部添加元素elem
c.pop_front()    ;   //移除頭部一個元素(但不回傳)
c.erase(pos)    ;   //移除pos位置上的元素,返回一元素位置,如 c.erase( c.begin() + 5)移除第五個元素
c.insert(pos , elem); //在pos位置插入一個元素elem,並返回新元素的位置
c.insert(pos , n , elem); //在pos位置插入n個元素elem,無返回值
c.insert(pos , beg , end);
c.resize(num);       //將容器大小改爲num。可更大或更小。
c.resize(num , elem);  //將容器大小改爲num,新增元素都爲 elem
c.clear();            //移除所有元素,將容器清空

3、有序關聯容器

3.1 set(集合)和 multiset(多重集合)

multisetset用法幾乎一致,只是multiset可以允許值重複而已,在此就不重複介紹了。

1、簡介

頭文件 #include <set>

set(集合):由紅黑樹實現,其中每個元素只包含一個關鍵字並依據其值自動排序,支持高效的關鍵字查詢操作,每個元素值只能出現一次,不允許重複。插入和刪除效率比用其他序列容器高,因爲對於關聯容器來說,不需要做內存拷貝和內存移動。
multiset(多重集合):唯一的區別是插入的元素可以相同。

2、優缺點:

優點:關鍵字查詢高效,且元素唯一,以及能自動排序。
缺點:每次插入值的時候,都需要調整紅黑樹,效率有一定影響。

3、插入、刪除的時間複雜度:
在這裏插入圖片描述

4、定義與初始化

	set<int> iset(ivec.begin(), ivec.end());	// 根據迭代器範圍內的元素初始化
	set<int> set1; 	// 創建一個空的set集合

5、常用的操作方法

	set1.insert("the"); //第一種方法:直接添加
	iset2.insert(ivec.begin(), ivec.end());//第二種方法:通過指針迭代器
    set1.size();    //元素個數
    set1.empty();   //判斷空
    set1.find();	// 返回一個迭代器,此迭代器指向集合中其值與指定值相等的元素的位置。
    set1.begin();	// 返回一個迭代器,此迭代器指向集合中的第一個元素。
    set1.end();		// 返回超過末尾迭代器。
	set1.cbegin();	// 返回一個常量迭代器,此迭代器指向集合中的第一個元素。
	set1.cend();	// 返回一個超過末尾常量迭代器。

6、遍歷方法

	//正向迭代器
    for(set<int>::iterator iter = set1.begin();iter!=set1.end();iter++) {
       cout << *iter << endl;
    }
    //反向迭代
	for(set<int>::iterator iter = set1.rbegin();iter!=set1.rend();iter++) {
       cout << *iter << endl;
    }

7、刪除方法

	set1.erase(iterator it);	//刪除迭代器指向的對象
	set1.erase(iterator first,iterator last);	//刪除first到last迭代器範圍中的內容
	set1.erase(value);	//通過值刪除
	set1.clear();	// 清空所有元素,相對於set1.erase(set1.begin(),set1.end());

3.2 map(映射)和multimap(多重映射)

multimapmap用法幾乎一致,只是multimap可以允許值重複而已,在此就不重複介紹了。

1、簡介

頭文件 #include <map>

map(映射):由紅黑樹實現,其中每個元素都是一些 鍵值對(key-value):關鍵字起索引作用,值表示與索引相關聯的數據。每個元素有一個鍵,是排序準則的基礎。每一個鍵只能出現一次,不允許重複。插入和刪除效率比用其他序列容器高,因爲對於關聯容器來說,不需要做內存拷貝和內存移動。

multimap(多重映射):唯一的區別是插入的元素(值)可以相同,即同一個鍵可以對應多個值。
在這裏插入圖片描述

2、優缺點:

優點:關鍵字查詢高效,且元素唯一,以及能自動排序。把一個值映射成另一個值,可以創建字典。
缺點:每次插入值的時候,都需要調整紅黑樹,效率有一定影響。

3、插入、刪除的時間複雜度:
在這裏插入圖片描述

4、定義與初始化

	map<k, v>m 		// 創建一個名爲m的空map對象,其鍵和值的類型分別爲k和v
	map<k, v> m(m2) // 創建m2的副本m,m與m2必須有相同的鍵類型和值類型
	map<k, v> m(b, e) 	// 創建map類型的對象m,存儲迭代器b和e標記的範圍內所有元素的副本。元素的類型必須能轉換爲pair<const k, v>

5、常用的操作方法

	// 插入元素
	map1[3] = "Saniya";                    //添加一個鍵爲 3,值爲"Saniya"的鍵-值對
    map1.insert(map<int,string>::value_type(2,"Diyabi"));//插入元素
    map1.insert(pair<int,string>(1,"Siqinsini")); //插入一個pair類型的鍵-值對
    map1.insert(make_pair<int,string>(4,"V5")); //通過make_pair插入一個pair類型的鍵-值對
    map1.insert(iterator first,iterator last);	// 插入另一個map在迭代器範圍內的數據
    //其他
	map<int,string>::iterator iter_map = map1.begin();//取得迭代器首地址
    int key = iter_map->first;             //取得key
    string value = iter_map->second;       //取得value
    map1.size();                       //元素個數
    map1.empty();                       //判斷空
    map1.find();	// 返回一個迭代器,此迭代器指向映射中其鍵與指定鍵相等的元素的位置。
    map1.begin();	// 返回一個迭代器,此迭代器指向映射中的第一個元素。
    map1.end();		// 返回超過末尾迭代器。
	map1.cbegin();	// 返回一個常量迭代器,此迭代器指向映射中的第一個元素。
	map1.cend();	// 返回一個超過末尾常量迭代器。
	map1.count();	// 返回映射中其鍵與參數中指定的鍵匹配的元素數量。

6、遍歷方法

	//正向迭代器
    for(map<int,string>::iterator iter = map1.begin();iter!=map1.end();iter++) {
       int keyk = iter->first;
       string valuev = iter->second;
    }
    //反向迭代
	for(map<int,string>::iterator iter = map1.rbegin();iter!=map1.rend();iter++) {
       int keyk = iter->first;
       string valuev = iter->second;
    }

7、刪除方法

	map1.erase(iterator it);	//刪除迭代器指向的對象
	map1.erase(iterator first,iterator last);	//刪除first到last迭代器範圍中的內容
	map1.erase(const Key&key);	//通過關鍵字刪除
	map1.clear();	// 清空所有元素,相對於map1.erase(map1.begin(),map1.end());

4、無序關聯容器

4.1 unordered_map/unordered_multimap

unordered_multimap unordered_map用法幾乎一致,只是unordered_multimap 可以允許值重複而已,在此就不重複介紹了。

1、簡介

頭文件 #include <unordered_map>

unordered_map和map類似,都是存儲的key-value的值,可以通過key快速索引到value。不同的是unordered_map不會根據key的大小進行排序,存儲時是根據key的hash值判斷元素是否相同,即unordered_map內部元素是無序的。unordered_map的底層是一個防冗餘的哈希表(開鏈法避免地址衝突)。

哈希表最大的優點,就是把數據的存儲和查找消耗的時間大大降低,時間複雜度爲O(1);而代價僅僅是消耗比較多的內存。哈希表的查詢時間雖然是O(1),但是並不是unordered_map查詢時間一定比map短,因爲實際情況中還要考慮到數據量。
2、優缺點:

優點: 因爲內部實現了哈希表,因此其查找速度非常的快
缺點: 哈希表的建立比較耗費時間

3、初始化

unordered_map<string, int> map1; map1[string("abc")] = 1; map1["def"] = 2;//創建空map,再賦值
unordered_map<string, int> map2(map1);    //拷貝構造
unordered_map<string, int> map3(map1.find("abc"), map1.end());    //迭代器構造
unordered_map<string, int> map4(move(map2));    //移動構造
unordered_map<string, int> map5 {{"this", 100},{"can", 100},};//使用initializer_list初始化

4、常見用法

map1.at("abc");	//查找具有指定key的元素,返回value
map1.find("abc");    //查找鍵爲key的元素,找到返回迭代器,失敗返回end()
map1.count("abc");    //返回指定key出現的次數,0或1
map1.emplace(make_pair("str1", 1));    //使用pair的轉換移動構造函數,返回pair<unordered_map<string, int>::iterator, bool>
map1.emplace("str2", 2);    //使用pair的模板構造函數,如果key已經存在則什麼都不做
map1.insert(pair<string ,int>("sex", 1));//插入元素,返回pair<unordered_map<string, int>::iterator, bool>
map1.insert(unordered_map<string, int>::value_type("sex", 1));//插入元素,如果key已經存在則什麼都不做
map1.insert(make_pair("sex", 1));//插入元素,返回pair<map<string, int>::iterator, bool>,插入成功second爲true,失敗爲flase
map1.insert({"sex", 1});    //使用initializer_list插入元素
map1.insert(map1.end(), {"sex", 1});//指定插入位置,如果位置正確會減少插入時間
map1.insert(map2.begin(), map2.end());//使用範圍迭代器插入
map1.erase("abc");	    //刪除操作,成功返回1,失敗返回0
map1.erase(map1.find("abc"));	    //刪除操作,成功返回下一個pair的迭代器
map1.erase(map1.begin(), map1.end());    //刪除map1的所有元素,返回指向end的迭代器
map1.empty();        //是否爲空
map1.size();        //大小
map1.bucket_count();    //返回容器中的桶數
map1.bucket_size(1);    //返回1號桶中的元素數
map1.bucket("abc");    //abc這個key在哪一個桶
map1.load_factor();    //負載因子,返回每個桶元素的平均數,即size/float(bucket_count);
map1.max_load_factor();//返回最大負載因子
map1.max_load_factor(2);//設置最大負載因子爲2,rehash(0)表示強制rehash
map1.rehash(20);//設置桶的數量爲20,並且重新rehash
map1.reserve(20);//將容器中的桶數設置爲最適合元素個數,如果20大於當前的bucket_count乘max_load_factor,則增加容器的bucket_count並強制重新哈希。如果20小於該值,則該功能可能無效。
unordered_map<string, int>::iterator it = map1.begin();	    //返回指向map1首元素的迭代器
unordered_map<string, int>::const_iterator c_it = map1.cbegin();	    //返回指向map1首元素的常量迭代器
unordered_map<string, int>::local_iterator it = map1.begin(1);//返回1號桶中的首元素迭代器
unordered_map<string, int>::const_local_iterator c_it = map1.cbegin(1);//返回1號桶中的首元素的常量迭代器
pair<unordered_map<string, int>::iterator, unordered_map<string, int>::iterator> it = map1.equal_range("abc");//返回一個pair,pair裏面第一個變量是lower_bound返回的迭代器,第二個迭代器是upper_bound返回的迭代器
map1.clear();        //清空

5、示例
在這裏插入圖片描述

4.2 unordered_set/unordered_multiset

unordered_multiset unordered_set 用法幾乎一致,只是unordered_multiset 可以允許值重複而已,在此就不重複介紹了。

1、簡介

頭文件 #include <unordered_set>

unordered_set基於哈希表,數據插入和查找的時間複雜度很低,幾乎是常數時間,而代價是消耗比較多的內存,無自動排序功能。底層實現上,使用一個下標範圍比較大的數組來存儲元素,形成很多的桶,利用hash函數對key進行映射到不同區域進行保存。

2、優缺點:

優點: 因爲內部實現了哈希表,因此其查找速度非常的快
缺點: 哈希表的建立比較耗費時間

3、初始化

unordered_set<int> set1; //創建空set
unordered_set<int> set2(set1);    //拷貝構造
unordered_set<int> set3(set1.begin(), set1.end());    //迭代器構造
unordered_set<int> set4(arr,arr+5);    //數組構造
unordered_set<int> set5(move(set2));    //移動構造
unordered_set<int> set6 {1,2,10,10};//使用initializer_list初始化

4、常見用法

set1.find(2);    //查找2,找到返回迭代器,失敗返回end()
set1.count(2);    //返回指2出現的次數,0或1
set1.emplace(3);    //使用轉換移動構造函數,返回pair<unordered_set<int>::iterator, bool>
set1.insert(3);    //插入元素,返回pair<unordered_set<int>::iterator, bool>
set1.insert({1,2,3});    //使用initializer_list插入元素
set1.insert(set1.end(), 4);//指定插入位置,如果位置正確會減少插入時間,返回指向插入元素的迭代器
set1.insert(set2.begin(), set2.end());//使用範圍迭代器插入
set1.erase(1);	    //刪除操作,成功返回1,失敗返回0
set1.erase(set1.find(1));	    //刪除操作,成功返回下一個pair的迭代器
set1.erase(set1.begin(), set1.end());    //刪除set1的所有元素,返回指向end的迭代器
set1.empty();        //是否爲空
set1.size();        //大小
set1.bucket_count();    //返回容器中的桶數
set1.bucket_size(1);    //返回1號桶中的元素數
set1.bucket(1);    //1在哪一個桶
set1.load_factor();    //負載因子,返回每個桶元素的平均數,即size/float(bucket_count);
set1.max_load_factor();//返回最大負載因子
set1.max_load_factor(2);//設置最大負載因子爲2,rehash(0)表示強制rehash
set1.rehash(20);//設置桶的數量爲20,並且重新rehash
set1.reserve(20);//將容器中的桶數設置爲最適合元素個數,如果20大於當前的bucket_count乘max_load_factor,則增加容器的bucket_count並強制重新哈希。如果20小於該值,則該功能可能無效。
unordered_set<int>::iterator it = set1.begin();	    //返回指向set1首元素的迭代器
unordered_set<int>::const_iterator c_it = set1.cbegin();	    //返回指向set1首元素的常量迭代器
unordered_set<int>::local_iterator it = set1.begin(1);//返回1號桶中的首元素迭代器
unordered_set<int>::const_local_iterator c_it = set1.cbegin(1);//返回1號桶中的首元素的常量迭代器
pair<unordered_set<int>::iterator, unordered_set<int>::iterator> it = set1.equal_range(1);//返回一個pair,pair裏面第一個變量是lower_bound返回的迭代器,第二個迭代器是upper_bound返回的迭代器
set1.clear();        //清空

5、容器適配器

5.1 stack容器

1、簡介

頭文件 #include <stack>

C++ Stack(堆棧) 是一個容器類的改編,爲程序員提供了堆棧的全部功能,——也就是說實現了一個先進後出(FILO)的數據結構。

2、插入、刪除的時間複雜度:
在這裏插入圖片描述

3、常用的操作方法

	s1.empty() //堆棧爲空則返回真
	s1.pop() //移除棧頂元素
	s1.push() //在棧頂增加元素
	s1.size() //返回棧中元素數目
	s1.top() //返回棧頂元素

5.2 queue容器

1、簡介

頭文件 #include <queue>

queue具有先進先出的數據結構。持新增元素、移除元素、從最底端加入元素、取最頂端元素。
在這裏插入圖片描述

2、插入、刪除的時間複雜度:
在這裏插入圖片描述

3、常用的操作方法

	q.push(x); 	//入隊,將x元素接到隊列的末端;
	q.pop(); 	//出隊,彈出隊列的第一個元素,並不會返回元素的值;
	q.front();  //訪問隊首元素
	q.back(); 	//訪問隊尾元素
	q.size(); 	// 訪問隊中的元素個數
	q.empty(); 	//判斷隊列是否爲空

5.3 priority_queue容器

1、簡介

頭文件 #include <queue>

priority_queue實現了優先隊列這一ADT,也就是我們常說的堆。但要明晰的是,優先隊列是一種ADT,而堆是它的一種具體實現。在默認狀態下,priority_queue實現的是大根堆,但你可以通過模板特化從而實現小根堆。

定義:priority_queue<Type, Container, Functional>

Type 就是數據類型,Container 就是容器類型(Container必須是用數組實現的容器,比如vector,deque等等,但不能用 list。STL裏面默認用的是vector),Functional 就是比較的方式。

當需要用自定義的數據類型時才需要傳入這三個參數,使用基本數據類型時,只需要傳入數據類型,默認是大頂堆,如下所示:

 //升序隊列,小頂堆
 priority_queue <int,vector<int>,greater<int> > q;
 //降序隊列,大頂堆
 priority_queue <int,vector<int>,less<int> >q;
 //greater和less是std實現的兩個仿函數(就是使一個類的使用看上去像一個函數。
 //其實現就是類中實現一個operator(),這個類就有了類似函數的行爲,就是一個仿函數類了)

2、插入、刪除的時間複雜度:
在這裏插入圖片描述

3、常用的操作方法

	q.push(x); 	//入隊,將x元素接到隊列的末端,(並排序)
	q.pop(); 	//出隊,彈出隊列的第一個元素,並不會返回元素的值;
	q.front();  //訪問隊首元素
	q.back(); 	//訪問隊尾元素
	q.size(); 	// 訪問隊中的元素個數
	q.empty(); 	//判斷隊列是否爲空

整理博客不易,如果本文對你有所幫助,請給博主 點贊 + 收藏 + 關注!謝謝!

參考:https://blog.csdn.net/u014465639/article/details/70241850
https://blog.csdn.net/like_that/article/details/98446479
https://blog.csdn.net/weixin_43844677/article/details/104902417
https://blog.csdn.net/zhuikefeng/article/details/104738544

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章