C++ Primer 第9章 顺序容器 第一次学习笔记
1. 順序容器概述
#include <vector> //可變大小數(shù)組。支持快速隨機(jī)訪問(wèn)。在尾部之外的位置插入或刪除元素可能很慢 #include <deque> //雙端隊(duì)列。支持快速隨機(jī)訪問(wèn)。在頭尾位置插入、刪除速度都很快 #include <list> //雙向鏈表。只支持雙向順序訪問(wèn)。在list中任何位置進(jìn)行插入、刪除操作速度都很快 #include <array> //固定大小數(shù)組。 支持快速隨機(jī)訪問(wèn)。不能添加或刪除元素 #include <string> //與vector相似的容器,但專(zhuān)門(mén)用于保存字符。隨機(jī)訪問(wèn)快。在尾部插入、刪除速度快/*通常,使用vector是最好的選擇,除非有很好的理由選擇其他容器 可以定義一個(gè)容器,其元素的類(lèi)型是另一個(gè)容器:vector<vector<string>> lines; 此處lines是一個(gè)vector,其元素類(lèi)型是string的vector2. 左閉合范圍
一個(gè)迭代器范圍由一對(duì)迭代器表示,兩個(gè)迭代器分別指向同一個(gè)容器中的元素或尾元素之后的位置。
左閉合區(qū)間:[begin,end)表示范圍自begin開(kāi)始,于end之前結(jié)束(end不能指向begin之前的位置)
使用左閉合范圍有三種方便的性質(zhì):
a) 如果begin==end,范圍為空 ? ?
b) 如果begin!=end,則范圍至少包含一個(gè)元素
c) 可以對(duì)begin遞增若干次,使begin==end
因此,我們可以用循環(huán)處理一個(gè)元素范圍,給定合法范圍的begin和end,若范圍為空,則退出循環(huán)
3. vector和string迭代器支持>、>=、<、<=關(guān)系運(yùn)算符,但list不支持
list<int> lst1; list<int>::iterator iter1=lst1.begin(),iter2=lst1.end(); /*while(iter1<iter2) 這是不可以的誒*/ while(iter1!=iter2) /*這才是對(duì)的*/4. begin(返回指向第一個(gè)元素或第一個(gè)字符的迭代器)和end(返回指向容器或string對(duì)象尾元素的下一位置的迭代器)有多個(gè)坂(版)本:
a) rbegin和rend返回反向迭代器
b) 以c開(kāi)頭的坂本則返回const迭代器
list<string> a={"Milton","Shakespear","Austen"}; 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=a.crbegin(); //list<string>::const_reverse_iterator5.?迭代器類(lèi)型
a) 當(dāng)不需要寫(xiě)訪問(wèn)時(shí),應(yīng)使用cbegin和cend
b) 如果對(duì)象是個(gè)常量,只能使用const_iterator
vector<int> v1;const vector<int> v2;auto it1=v1.begin(),it2=v2.begin(); //error,it1和it2類(lèi)型不一致auto it3=v1.cbegin(),it4=v2.cbegin();6.?容器定義和初始化
#include <iostream> #include <vector> using namespace std; int main(){vector<int> v1; //默認(rèn)初始化。如果不是array, 容器為空vector<int> v2(v1); //v2初始化為v1的拷貝。這兩個(gè)容器必須是相同的容器類(lèi)型,vector<int> v3=v1; //且保存的是相同的元素類(lèi)型 vector<int> v4{1,2,3}; //列表初始化,初始化為初始化列表中元素的拷貝, vector<int> v5={1,2,3}; //列表中元素的類(lèi)型必須與容器的元素類(lèi)型相同 vector<int> v6(v1.begin(),v1.end()); //初始化為兩個(gè)迭代器指定范圍中的元素的拷貝vector<int> v7(10,-1); //10個(gè)int元素,每個(gè)都初始化為-1vector<int> v8(10); //10個(gè)int元素,每個(gè)都初始化為0 return 0; } 注意:當(dāng)傳遞迭代器參數(shù)來(lái)拷貝一個(gè)范圍時(shí),不要求容器類(lèi)型是相同的,只要能將要拷貝的元素轉(zhuǎn)換為要初始化的容器的元素類(lèi)型即可: vector<float> ivec1={0.1,0.5,5.6};vector<int> ivec2(ivec1.begin(),ivec1.end());7. swap:交換兩個(gè)相同類(lèi)型容器的內(nèi)容。
元素本身并未交換,swap只是交換了兩個(gè)容器的內(nèi)部數(shù)據(jù)結(jié)構(gòu),which means除string外,指向容器的迭代器、引用和指針在swap操作之后都不會(huì)失效,它們?nèi)灾赶?/span>
swap操作之前所指向的那些元素。
8. 容器大小操作
每個(gè)容器都有三個(gè)與大小相關(guān)的操作:
a) size返回容器中元素的數(shù)目
b) empty當(dāng)size為0時(shí)返回布爾值true
c) max_size返回一個(gè)大于或等于該類(lèi)型容器所能容納的最大元素?cái)?shù)的值
d) 每個(gè)容器類(lèi)型都支持相等運(yùn)算符(==和!=);除了無(wú)序關(guān)聯(lián)容器外的所有容器都支持關(guān)系運(yùn)算符(>、>=、<、<=)
e) 關(guān)系運(yùn)算符左右兩邊的運(yùn)算對(duì)象必須是相同類(lèi)型的容器,且必須保存相同類(lèi)型的元素
9. 向順序容器添加元素(vector和string不支持push_front和emplace_front)
c.push_back(t) //在c的尾部創(chuàng)建一個(gè)值為t或由args創(chuàng)建的元素 c.emplace_back(args) //返回voidc.insert(p,t) //在迭代器p指向的元素之前創(chuàng)建一個(gè)值為r或由args創(chuàng)建的元素 c.emplace(p,args) //返回voidc.insert(p,n,t) //在迭代器p指向的元素之前插入n個(gè)值為t的元素。//返回指向新添加的第一個(gè)元素的迭代器;若n為0,則返回p c.insert(p,b,e) //將迭代器p和e指定的范圍內(nèi)的元素插入到迭代器p指向的元素之前。b和e不能指向c中的元素。//返回指向新添加的第一個(gè)元素的迭代器;若范圍為空,則返回p c.insert(p,il) //il是一個(gè)花括號(hào)包圍的元素值列表。將這些給定值插入到迭代器p指向的元素之前。//返回指向新添加的第一個(gè)元素的迭代器;若列表為空,則返回pa) 向一個(gè)vector、string或deque插入元素會(huì)使所有指向容器的迭代器、引用和指針失效b) 當(dāng)用一個(gè)對(duì)象初始化容器時(shí)(或?qū)⒁粋€(gè)對(duì)象插入到容器中時(shí)),實(shí)際上放到容器中的是對(duì)象值的一個(gè)拷貝而不是其本身;隨后對(duì)容器中元素的任何改變都不會(huì)影響到原始對(duì)象
c) 每個(gè)insert函數(shù)都接受一個(gè)迭代器作為其第一個(gè)參數(shù),將元素插入到迭代器所指定的位置之前
vector<int> vec{1,10,24,3};vec.insert(vec.begin(),4);for(auto c:vec)cout<<c<<" "; 輸出結(jié)果為4 1 10 24 3d)?insert還有一個(gè)版本接受的參數(shù)為一個(gè)元素?cái)?shù)目和一個(gè)值,它將指定數(shù)量的元素添加到指定位置之前,這些值都按給定值初始化
vector<string> svec{"hhh"};svec.insert(svec.end(),10,"A233"); 輸出結(jié)果為hhh A233 A233 A233e) 接受一對(duì)迭代器或一個(gè)初始化列表的insert坂本將給定范圍中的元素插入到指定位置之前
vector<string> svec1={"i","love","study","and"};vector<string> svec2={"study","makes","me","happy"};svec2.insert(svec2.begin(),svec1.begin(),svec1.end()-2); //將svec1最后的兩個(gè)元素添加到svec2的開(kāi)始位置for(auto c:svec2)cout<<c<<" ";svec1.insert(svec1.end(),{"i","want","to","be","a dalao"});for(auto n:svec1)cout<<n<<" ";注意:拷貝的范圍是左閉合區(qū)間,即第三行的svec1.end()-2,the string "study",沒(méi)有被拷貝過(guò)去
f) 使用insert的返回值可以在容器中一個(gè)特定位置反復(fù)插入元素,因?yàn)閕nsert函數(shù)返回的是新添加的(第一個(gè)元素的)迭代器
vector<string> svec={"anita","Anita","ANITA","gcn","GCN"};auto iter=svec.begin();string word;while(cin>>word)iter=svec.insert(iter,word); //等價(jià)于調(diào)用push_frontfor(auto c:svec)cout<<c<<" ";10. 訪問(wèn)元素
a) 每個(gè)順序容器都有一個(gè)front成員函數(shù),除forward_list之外的所有順序容器都有一個(gè)back成員函數(shù)。這兩個(gè)操作分別返回首元素和尾元素的引用
c.back() //返回c中尾元素的引用,若c為空,函數(shù)行為未定義c.front() //返回c中首元素的引用,若c為空,函數(shù)行為未定義c[n] //返回c中下標(biāo)為n的元素的引用,n是一個(gè)無(wú)符號(hào)整數(shù),若n>=c.size(),函數(shù)行為未定義 c.at[n] //返回下標(biāo)為n的元素的引用。如果下標(biāo)越界,則拋出一out_of_range異常b) 不可以對(duì)空容器調(diào)用front和back
c) 在容器中訪問(wèn)元素的成員函數(shù)(front、back、下標(biāo)和at)返回的是引用。如果容器是一個(gè)const對(duì)象,返回值是const引用。如果容器不是const,可以用返回的普通引用改變?cè)氐闹?/span>
vector<int> ivec={7,2,4,6,2,0,9};if(!ivec.empty()){ ivec.front()=42; //將42賦予c中的第一個(gè)元素 auto &v1=ivec.back(); //獲得指向最后一個(gè)元素的引用cv1=1024;auto v2=ivec.back(); //v2不是一個(gè)引用,只是ivec.back()的拷貝v2=0; //v2不是引用,未改變c中的元素 }for(auto a:ivec)cout<<a<<" "; //輸出結(jié)果是42 2 4 6 2 0 102411. 刪除元素(與vector和string不支持push_front一樣,vector和string也不支持pop_front)
c.pop_back() //刪除c中尾元素,返回void c.pop_front() //刪除c中首元素,返回void c.erase(p) //刪除迭代器p所指定的元素,返回一個(gè)指向被刪元素之后元素的迭代器。若p指向尾元素,返回尾后迭代器。 c.erase(b,e) //刪除迭代器b和e所指定范圍內(nèi)的元素。返回一個(gè)指向最后一個(gè)被刪的元素之后元素的迭代器 c.clear() //刪除c中所有元素,返回void a) pop_front和pop_back都返回void。如果需要彈出的元素的值,應(yīng)在執(zhí)行彈出操作之前保存它b) 成員函數(shù)erase從容器中指定位置刪除元素,兩種形式的erase都返回指向刪除的(最后一個(gè))元素之后位置的迭代器。下面的栗子刪除ivec中的所有奇數(shù),調(diào)用了接受一個(gè)迭代器的erase坂本的函數(shù)
vector<int> ivec;int n;while(cin>>n)ivec.push_back(n);auto it=ivec.begin();while(it!=ivec.end()){ //不為空if(*it%2)it=ivec.erase(it); //erase返回被刪元素之后元素的迭代器else++it;}for(auto c:ivec)cout<<c<<" ";c) 接受一對(duì)迭代器的erase坂本允許我們刪除一個(gè)范圍內(nèi)的元素。依舊是左閉合區(qū)間,栗子在下面
vector<int>ivec{0,1,2,3,4,5,6,7,8,9};auto iter1=ivec.begin()+1,iter2=ivec.end()-2; //*(ivec.end()-2)是8,前面的那個(gè)是1ivec.erase(iter1,iter2);for(auto c:ivec)cout<<c<<"";
d) 為了刪除一個(gè)容器中的所有元素,既可以調(diào)用clear函數(shù),也可以用begin和end獲得的迭代器作為參數(shù)調(diào)用erase
ivec1.clear();ivec2.erase(ivec2.begin(),ivec2.end());//等價(jià)調(diào)用,都是刪除容器中所有元素12. 改變?nèi)萜鞔笮?/span>
a) 用resize函數(shù)增大或縮小容器
c.resize(n) //調(diào)整c的大小為n個(gè)元素。//若n<c.size(),則多出的元素被丟棄。若必須添加新元素,對(duì)新元素進(jìn)行值初始化c.resize(n,t) //調(diào)整c的大小為n個(gè)元素。任何新添加的元素都初始化為值tb) 如果當(dāng)前大小大于所要求的大小,容器后部的元素會(huì)被刪除;如果當(dāng)前大小小于新大小,會(huì)將新元素添加到容器后部
vector<int> ivec(10,42); //10個(gè)int,每個(gè)int的值都是42ivec.resize(15); //將5個(gè)值為0的元素添加到ivec的末尾ivec.resize(25,-1); //將10個(gè)值為-1的元素添加到ivec的末尾ivec.resize(5); //從ivec的末尾刪除20個(gè)元素13. 容器操作可能使迭代器失效
a) 在向容器vector或string添加元素后,且存儲(chǔ)空間被重新分配,指向容器的迭代器、指針或引用都會(huì)失效;如果存儲(chǔ)空間未重新分配,指向插入位置之前的元素的迭代器、指針和引用仍有效,但指向插入位置之后元素的迭代器、指針和引用都會(huì)失效
b) 刪除vector或string的一個(gè)元素后,指向被刪元素之前元素的迭代器、指針和引用仍有效
c) 刪除元素時(shí),尾后迭代器總會(huì)失效
14. 構(gòu)造string的其他方法
string s1string s2(s1)string s2=s1 //等價(jià)于s2(s1)string s3("value")string s3="value"string s4(n,'c')string有與其他順序容器相同的構(gòu)造函數(shù),在前面。下面是新內(nèi)容
string s(cp,n) //s是cp指向的數(shù)組中前n個(gè)字符的拷貝。此數(shù)組至少應(yīng)該包含n個(gè)字符string s(s2,pos2) //s是strings2從下標(biāo)pos2開(kāi)始的字符的拷貝string s(s2,pos2,len2) //s是string s2從下標(biāo)pos2開(kāi)始len2個(gè)字符的拷貝。不管len2的值是多少,構(gòu)造函數(shù)至多拷貝s2.size()-pose2個(gè)字符16. string搜索操作
a) string類(lèi)提供了6個(gè)不同的搜索函數(shù)。每個(gè)搜索操作都返回一個(gè)string::size_type的值,表示匹配發(fā)生位置的下標(biāo);如果搜索失敗,返回npos(初始化為值-1)
s.find(args) //查找s中args第一次出現(xiàn)的位置s.rfind(args) //查找s中args最后一次出現(xiàn)的位置s.find_first_of(args) //在s中查找args中任何一個(gè)字符第一次出現(xiàn)的位置s.find_last_of(args) //在s中查找args中任何一個(gè)字符最后一次出現(xiàn)的位置s.find_first_not_of(args) //在s中查找第一個(gè)不在args中的字符s.find_last_not_of(args) //在s中查找最后一個(gè)不在args中的字符args必須是以下形式之一:
c,pos 從s中位置pos開(kāi)始查找字符c。pos默認(rèn)為0s2,pos 從s中位置pos開(kāi)始查找字符串s2。pos默認(rèn)為0 cp,pos 從s中位置pos開(kāi)始查找指針cp指向的以空字符結(jié)尾的C風(fēng)格字符串。pos默認(rèn)為0 cp,pos,n 從s中位置pos開(kāi)始查找指針cp指向的數(shù)組的前n個(gè)字符。pos和n無(wú)默認(rèn)值17.compare函數(shù)
a) 類(lèi)似于strcmp,根據(jù)string是等于、大于還是小于參數(shù)指定的字符串,s.compare()返回0、正數(shù)或負(fù)數(shù)
b) 根據(jù)是要比較兩個(gè)string還是一個(gè)string與一個(gè)字符數(shù)組,參數(shù)各有不同。以下是s.compare()的6種參數(shù)形式
s2 比較s和s2pos1,n1,s2 將s中從pos1開(kāi)始的n1個(gè)字符與s2進(jìn)行比較pos1,n1,s2,pos2,n2 將s中從pos1開(kāi)始的n1個(gè)字符與s2中從pos2開(kāi)始的n2個(gè)字符進(jìn)行比較cp 比較s與cp指向的以空字符結(jié)尾的字符數(shù)組pos1,n1,cp 將s中從pos1開(kāi)始的n1個(gè)字符與cp指向的以空字符結(jié)尾的字符數(shù)組進(jìn)行比較pos1,n1,cp,n2 將s中從pos1開(kāi)始的n1個(gè)字符與指針cp指向的地址開(kāi)始的n2個(gè)字符進(jìn)行比較18.容器適配器
a) 標(biāo)準(zhǔn)庫(kù)定義了三個(gè)順序容器適配器:stack、queue和priority_queue
b) 一種適配器本質(zhì)上是一種機(jī)制,能使某種事物的行為看起來(lái)像另外一種事物一樣。一個(gè)容器適配器接受一種已有的容器類(lèi)型,使其行為看起來(lái)像一種不同的類(lèi)型。例如,stack適配器接受一個(gè)順序容器,并使其操作起來(lái)像一個(gè)stack一樣
c) 所有容器適配器都支持的操作和類(lèi)型:
size_type 一種類(lèi)型,足以保存當(dāng)前類(lèi)型的最大對(duì)象的大小value_type 元素類(lèi)型container_type 實(shí)現(xiàn)適配器的底層容器類(lèi)型A a; 創(chuàng)建一個(gè)名為a的空適配器A a(c); 創(chuàng)建一個(gè)名為a的適配器,帶有容器c的一個(gè)拷貝關(guān)系運(yùn)算符 每個(gè)適配器都支持所有關(guān)系運(yùn)算符:==、!=、<、<=、>和>=,這些運(yùn)算符返回底層容器的比較結(jié)果a.empty() 若a包含任何元素,返回false,否則返回truea.size() 返回a中的元素?cái)?shù)目swap(a,b) 交換a和b的內(nèi)容,a和b必須有相同類(lèi)型,a.swap(b) 包括底層容器類(lèi)型也必須相同? ??
19.定義一個(gè)適配器
a) 每個(gè)適配器都定義了兩個(gè)構(gòu)造函數(shù):默認(rèn)構(gòu)造函數(shù)創(chuàng)建一個(gè)空對(duì)象,接受一個(gè)容器的構(gòu)造函數(shù)拷貝該容器來(lái)初始化適配器
b) 可以使用除array和forward_list之外的任何容器類(lèi)型來(lái)構(gòu)造stack
c) queue可以構(gòu)造于list或deque之上,但不能基于vector構(gòu)造
d) priority_queue可以構(gòu)造于vector或string之上
20.棧適配器(可以在vector、deque或list之上時(shí)間)
a) stack類(lèi)型定義在stack頭文件中。以下是stack所支持的操作:
s.pop() 刪除棧頂元素,但不返回該元素值 s.push(item) 創(chuàng)建一個(gè)新元素壓入棧頂,該元素通過(guò)拷貝或移動(dòng)item而來(lái), s.emplace(args) 或者由args構(gòu)造 s.top() 返回棧頂元素,但不將元素彈出棧下面是一個(gè)小栗子:
stack<int>intStack; //空棧 for(size_t ix=0;ix!=10;ix++) intStack.push(ix); //intStack保存0到9十個(gè)數(shù) while(!intStack.empty()){ //intStack中有值就繼續(xù)循環(huán) int value=intStack.top(); intStack.pop(); //彈出棧頂值的元素,繼續(xù)循環(huán) }b) 每個(gè)容器適配器都基于底層容器類(lèi)型的操作定義了自己的特殊操作。我們只可以使用適配器操作,不能使用底層容器類(lèi)型的操作。例如,不能在一個(gè)stack上調(diào)用push_back,而必須使用stack自己的操作——push
21. 隊(duì)列適配器(queue默認(rèn)基于deque實(shí)現(xiàn),priority_queue默認(rèn)基于vector實(shí)現(xiàn))
a) queue和priority_queue適配器定義在queue頭文件中。以下是queue和priority_queue支持的操作
q.pop() 返回queue的首元素或priority_queue的最高優(yōu)先級(jí)的元素,但不返回此元素q.front() 返回首元素或尾元素,但不刪除瓷元素q.back() 只適用于queueq.top() 返回最高優(yōu)先級(jí)元素,但不刪除該元素,只適用于priority_queueq.push(item) 在queue末尾或priority_queue中恰當(dāng)?shù)奈恢脛?chuàng)建一個(gè)元素,q.emplace(args) 其值為item,或者由args構(gòu)造b) 標(biāo)準(zhǔn)庫(kù)queue使用一種先進(jìn)先出的存儲(chǔ)和訪問(wèn)策略:進(jìn)入隊(duì)列的對(duì)象被放置到隊(duì)尾,而離開(kāi)隊(duì)列的對(duì)象則從隊(duì)首刪除
c) priority_queue允許為隊(duì)列中的元素建立優(yōu)先級(jí),新加入的元素會(huì)排在所有優(yōu)先級(jí)比它低的已有元素之前
轉(zhuǎn)載于:https://www.cnblogs.com/chuninggao/p/7275433.html
總結(jié)
以上是生活随笔為你收集整理的C++ Primer 第9章 顺序容器 第一次学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。