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