复习笔记(九)——C++中的容器(STL容器)
STL定義
STL(Standard Template Library),即標(biāo)準(zhǔn)模板庫(kù),是一個(gè)高效的C++程序庫(kù)。被容納于C++標(biāo)準(zhǔn)程序庫(kù)(C++ Standard Library)中,是ANSI/ISO C++標(biāo)準(zhǔn)中最新的也是極具革命性的一部分。包含了諸多在計(jì)算機(jī)科學(xué)領(lǐng)域里常用的基本數(shù)據(jù)結(jié)構(gòu)和基本算法。為廣大C++程序員們提供了一個(gè)可擴(kuò)展的應(yīng)用框架,高度體現(xiàn)了軟件的可復(fù)用性
從邏輯層次來(lái)看,在STL中體現(xiàn)了泛型化程序設(shè)計(jì)的思想(generic programming)。在這種思想里,大部分基本算法被抽象,被泛化,獨(dú)立于與之對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu),用于以相同或相近的方式處理各種不同情形。
從實(shí)現(xiàn)層次看,整個(gè)STL是以一種類型參數(shù)化(type parameterized)的方式實(shí)現(xiàn)的基于模板(template)。
容器分為兩大類:順序容器、關(guān)聯(lián)容器。
順序容器
順序容器有以下三種:vector(向量)、 deque(雙隊(duì)列)、list(列表)。
它們之所以被稱為順序容器,是因?yàn)樵卦谌萜髦械奈恢猛氐闹禑o(wú)關(guān),即容器不是排序的。將元素插入容器時(shí),指定在什么位置(尾部、頭部或中間某處)插入,元素就會(huì)位于什么位置。
順序容器的接口:
①插入方法
②刪除方法
pop() ,erase(),clear()③迭代訪問(wèn)方法
使用迭代器④其他順序容器訪問(wèn)方法(不修改訪問(wèn)方法)
front(),back(),下標(biāo)[]運(yùn)算符1、vector
向量屬于順序容器,用于容納不定長(zhǎng)線性序列(即線性群體),提供對(duì)序列的快速隨機(jī)訪問(wèn)(也稱直接訪問(wèn))。
數(shù)據(jù)結(jié)構(gòu)很像一個(gè)數(shù)組,所以與其他容器相比,vector 能非常方便和高效訪問(wèn)單個(gè)元素,支持隨機(jī)訪問(wèn)迭代子。
向量是動(dòng)態(tài)結(jié)構(gòu),它的大小不固定,可以在程序運(yùn)行時(shí)增加或減少與數(shù)組不同,向量的內(nèi)存用盡時(shí),向量自動(dòng)分配更大的連續(xù)內(nèi)存區(qū),將原先的元素復(fù)制到新的內(nèi)存區(qū),并釋放舊的內(nèi)存區(qū)。這是向量類的優(yōu)點(diǎn)。
頭文件:#include <vector>
基本操作:
(1)頭文件 #include<vector>(2)創(chuàng)建vector對(duì)象 vector<int> vec;(3)尾部插入數(shù)字 vec.push_back(a);(4)使用下標(biāo)訪問(wèn)元素 cout<<vec[0]<<endl;記住下標(biāo)是從0開始的。(5)使用迭代器訪問(wèn)元素vector<int>::iterator it;for(it=vec.begin();it!=vec.end();it++)cout<<*it<<endl;(6)插入元素 vec.insert(vec.begin()+i,a);在第i+1個(gè)元素前面插入a;(7)刪除元素 vec.erase(vec.begin()+2);刪除第3個(gè)元素 vec.erase(vec.begin()+i,vec.end()+j);刪除區(qū)間[i,j-1];區(qū)間從0開始(8)向量大小 vec.size(); vec.resize;改變大小(9)清空 vec.clear();示例(輸出質(zhì)數(shù)):
#include <iostream> #include <iomanip> #include <vector> //包含向量容器頭文件 using namespace std ; int main(){vector<int> A(10); //創(chuàng)建vector對(duì)象int n;int primecount = 0, i, j;cout<<"Enter a value>=2 as upper limit: ";cin >> n;A[primecount++] = 2;//下標(biāo)法訪問(wèn)元素for(i = 3; i < n; i++){if (primecount == A.size())A.resize(primecount + 10); //改變?nèi)萜鞔笮?/span>if (i % 2 == 0)continue;j = 3;while (j <= i/2 && i % j != 0)j += 2;if (j > i/2) A[primecount++] = i;}for (i = 0; i<primecount; i++){//輸出質(zhì)數(shù)cout<<setw(5)<<A[i];if ((i+1) % 10 == 0) //每輸出10個(gè)數(shù)換行一次cout << endl;}cout<<endl;return 0; }-------------- 執(zhí)行結(jié)果: Enter a value>=2 as upper limit: 202 3 5 7 11 13 17 192、deque
雙端隊(duì)列是一種放松了訪問(wèn)權(quán)限的隊(duì)列。元素可以從隊(duì)列的兩端入隊(duì)和出隊(duì),也支持通過(guò)下標(biāo)操作符“[]”進(jìn)行直接訪問(wèn)。
與向量的對(duì)比:
功能上:和向量沒(méi)有多少區(qū)別,
性能上:在雙端隊(duì)列起點(diǎn)上的插入和刪除操作快
頭文件:#include <deque>
3、list
列表主要用于存放雙向鏈表,可以從任意一端開始遍歷。列表還提供了拼接(splicing)操作,將一個(gè)序列中的元素從插入到另一個(gè)序列中。
對(duì)比:
①元素的插入和刪除操作對(duì) list 而言尤為高效。
②與 vector 和 deque 相比,對(duì)元素的下標(biāo)訪問(wèn)操作的低效是不能容忍的,因此 list 不提供這類操作。
頭文件:#include <list>
示例:
#include <iostream> #include <list> using namespace std ; int main(){list<int> Link; //構(gòu)造一個(gè)列表用于存放整數(shù)鏈表int i, key, item;for(i=0;i < 10;i++)// 輸入10個(gè)整數(shù)依次向表頭插入{Link.push_front(i);}cout<< "List:"; // 輸出鏈表list<int>::iterator p=Link.begin();while(p!=Link.end()){ //輸出各節(jié)點(diǎn)數(shù)據(jù),直到鏈表尾cout <<*p << " ";p++; //使P指向下一個(gè)節(jié)點(diǎn)}cout << endl;cout << "請(qǐng)輸入一個(gè)需要?jiǎng)h除的整數(shù): ";cin >> key;Link.remove(key);cout << "List: "; // 輸出鏈表p=Link.begin(); // 使P重新指向表頭while(p!=Link.end()){cout <<*p << " ";p++; // 使P指向下一個(gè)節(jié)點(diǎn)}cout << endl; }--------------------- 執(zhí)行結(jié)果示例: List:9 8 7 6 5 4 3 2 1 0 請(qǐng)輸入一個(gè)需要?jiǎng)h除的整數(shù): 3 List: 9 8 7 6 5 4 2 1 0順序容器的選擇
a、若需要隨機(jī)訪問(wèn)操作,則選擇vector;
b、若已經(jīng)知道需要存儲(chǔ)元素的數(shù)目, 則選擇vector;
c、若需要隨機(jī)插入/刪除(不僅僅在兩端),則選擇list
d、只有需要在首端進(jìn)行插入/刪除操作的時(shí)候,才選擇deque,否則都選擇vector。
e、若既需要隨機(jī)插入/刪除,又需要隨機(jī)訪問(wèn),則需要在vector與list間做個(gè)折中。
f、當(dāng)要存儲(chǔ)的是大型負(fù)責(zé)類對(duì)象時(shí),list要優(yōu)于vector;當(dāng)然這時(shí)候也可以用vector來(lái)存儲(chǔ)指向?qū)ο蟮闹羔?#xff0c;同樣會(huì)取得較高的效率,但是指針的維護(hù)非常容易出錯(cuò),因此不推薦使用。
注意:vector與deque的迭代器支持算術(shù)運(yùn)算,list的迭代器只能進(jìn)行++/–操作,不支持普通的算術(shù)運(yùn)算。
關(guān)聯(lián)容器
通過(guò)保存在數(shù)據(jù)項(xiàng)中的索引項(xiàng),盡可能快速檢索數(shù)據(jù)項(xiàng)。
STL標(biāo)準(zhǔn)庫(kù)中只包含有序關(guān)聯(lián)容器:set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)。
set, multiset:數(shù)據(jù)項(xiàng)就是索引項(xiàng)。 multiset允許出現(xiàn)重復(fù)的索引項(xiàng)。
map, multimap:數(shù)據(jù)項(xiàng)是由索引項(xiàng)和其他某種類型的數(shù)據(jù)組成的一對(duì)數(shù)據(jù)。 multimap允許出現(xiàn)重復(fù)的索引項(xiàng)。
1、map
增加和刪除節(jié)點(diǎn)對(duì)迭代器的影響很小。對(duì)于迭代器來(lái)說(shuō),可以修改實(shí)值,而不能修改key。
自動(dòng)建立Key-value的對(duì)應(yīng)。key 和 value可以是任意你需要的類型。
根據(jù)key值快速查找記錄,查找的復(fù)雜度基本是Log(N),如果有1000個(gè)記錄,最多查找10次,1,000,000個(gè)記錄,最多查找20次。
map的構(gòu)造函數(shù):
使用map得包含map類所在的頭文件
#include <map>map對(duì)象是模板類,需要關(guān)鍵字和存儲(chǔ)對(duì)象兩個(gè)模板參數(shù):
map<int, string> personnel;//用int作為索引,存儲(chǔ)string對(duì)象示例:
#include <map> #include <iostream> #include <string> using namespace std; int main(){map< string, string > trans_map;typedef map< string, string >::value_type valType;trans_map.insert( valType( "001", "wang" ));trans_map.insert( valType( "002", "li" ));trans_map.insert( valType( "003", "luo" ));trans_map.insert( valType( "004", "wu" ));trans_map.insert( valType( "005", "zhao" ));trans_map.insert( valType( "006", "sun" ));trans_map.insert( valType( "007", "qian" ));trans_map.insert( valType( "008", "long" ));map< string,string >::iterator it;cout << "Here is our transformation map: \n";for(it=trans_map.begin();it!=trans_map.end();++it)cout<<"key: "<<(*it).first<<"\t"<<"value: " <<(*it).second<<"\n";cout<<"Find Key:005"<<endl;it=trans_map.find("005");if (it==trans_map.end()){cout<<"not found"<<endl;}else{cout<<"key: "<<(*it).first <<"\t"<<"value: " <<(*it).second<<"\n";}return 0; }---------------------- 執(zhí)行結(jié)果: Here is our transformation map: key: 001 value: wang key: 002 value: li key: 003 value: luo key: 004 value: wu key: 005 value: zhao key: 006 value: sun key: 007 value: qian key: 008 value: long Find Key:005 key: 005 value: zhao2、multimap
multimap 除了元素對(duì)的關(guān)鍵字不是唯一外,與 map 相似
頭文件:#include <map>
3、set
set 可以被視為只有關(guān)鍵字而沒(méi)有相關(guān)的元素值的 map,因此 set 的用戶接口也發(fā)生了微小的變化:成員類型中沒(méi)有:
①typedef Key value_type;
②typedef Cmp value_compare
③操作中沒(méi)有元素的下標(biāo)訪問(wèn)操作。
頭文件:#include <set>
4、multiset
multiset 除了關(guān)鍵字不是唯一外,與 set 相似。
頭文件:#include <set>
容器的函數(shù)
所有容器都有以下兩個(gè)成員函數(shù):
int size():返回容器對(duì)象中元素的個(gè)數(shù)。
bool empty():判斷容器對(duì)象是否為空。
順序容器和關(guān)聯(lián)容器還有以下成員函數(shù):
begin():返回指向容器中第一個(gè)元素的迭代器。
end():返回指向容器中最后一個(gè)元素后面的位置的迭代器。
rbegin():返回指向容器中最后一個(gè)元素的反向迭代器。
rend():返回指向容器中第一個(gè)元素前面的位置的反向迭代器。
erase(...):從容器中刪除一個(gè)或幾個(gè)元素。
clear():從容器中刪除所有元素。
如果一個(gè)容器是空的,則 begin() 和 end() 的返回值相等,rbegin() 和 rend() 的返回值也相等。
順序容器還有以下常用成員函數(shù):
front():返回容器中第一個(gè)元素的引用。
back():返回容器中最后一個(gè)元素的引用。
push_back():在容器末尾增加新元素。
pop_back():刪除容器末尾的元素。
insert(...):插入一個(gè)或多個(gè)元素。該函數(shù)參數(shù)較復(fù)雜,此處省略。
示例
(這里只列舉一些容器以及一些函數(shù)用法)
順序容器:
vector 容器
deque 容器
void printd(deque<int> &d) {for(deque<int>::iterator it = d.begin(); it != d.end();it++){cout<<"元素"<<*it<<endl;} } void main() {deque<int> d;d.push_back(1); //在容器末尾增加新元素d.push_back(2); d.push_front(3); //在容器頭尾增加新元素d.push_front(4);printd(d);deque<int>::iterator it = find(d.begin(),d.end(),3); //查找指定元素3 找到時(shí),返回該元素的迭代器;找不到時(shí),返回end()。 if(it != d.end()){cout<<"3與第一個(gè)元素的距離為:"<<distance(d.begin (),it)<<endl;}}關(guān)聯(lián)容器:
set容器
map容器
//元素的添加、遍歷、刪除等基本操作 void main() {//1、創(chuàng)建map對(duì)象map<int, string> map1;//方法1 添加元素 pair是一個(gè)有兩個(gè)元素的結(jié)構(gòu)體,方便使用,類似map :鍵值可以隨意使用 //pair可以用來(lái)當(dāng)做map的鍵值來(lái)插入 pair<T1,T2> p1 創(chuàng)建一個(gè)空的pair對(duì)象,有兩個(gè)元素T1和T2,采用值初始化map1.insert(pair<int, string>(1,"hehe"));map1.insert(pair<int, string>(2,"xixi"));//方法2 添加元素 make_pair//make_pairmap1.insert(make_pair(3,"haha"));map1.insert(make_pair(4,"huhu"));//方法3 添加元素map1.insert(map<int, string>::value_type(5,"kaka"));map1.insert(map<int, string>::value_type(6,"yiyi"));//方法4 數(shù)組方式插入數(shù)據(jù)map1[7] = "yaya";//容器遍歷(迭代器)for(map<int, string>::iterator it = map1.begin();it != map1.end(); it++){cout<<it->first<<"\t"<<it->second <<endl;}cout<<"遍歷結(jié)束"<<endl;//容器的刪除while(!map1.empty()){map<int, string>::iterator it = map1.begin();map1.erase(it);}//map查找map<int, string>::iterator it1 = map1.find(2);if(it1 != map1.end()){cout<<"不存在"<<endl;}else{cout<<it1->first<<"\t"<<it1->second<<endl;}} 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的复习笔记(九)——C++中的容器(STL容器)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 复习笔记(八)——C++模板
- 下一篇: SQLite3单例模式(C++)