C++ primer 第9章 順序容器

文章目錄

  • 順序容器類型
    • 確定使用哪種順序容器
  • 容器庫概覽
    • 容器操作
    • 迭代器
      • 迭代器支持的所有操作
      • 迭代器支持的所有運算
      • 迭代器范圍
        • 對構成范圍的迭代器的要求
        • 標準庫迭代器范圍左閉右開的三種性質
    • 容器定義和初始化
      • 將一個新容器創建為另一個容器的拷貝
        • 將array拷貝到vector中的代碼
      • 與順序容器大小相關的構造函數
      • 標準庫array具有固定大小
    • 賦值和swap
      • 測試swap的代碼
    • 關系運算符
  • 順序容器的特有操作
    • 向順序容器添加元素
      • 容器元素是拷貝
      • 在容器中特定位置添加元素:insert
      • emplace操作
    • 訪問元素
      • 訪問成員函數返回的是引用
    • 刪除元素
    • 特殊的forward_list操作
    • 改變容器大小
    • 容器操作可能使迭代器失效
  • vector對象是如何增長的
    • capacity和size
  • 額外的string操作
    • 構造string的其他方法
    • substr操作
    • 從一個vector \

順序容器類型

在這里插入圖片描述
string和vector將元素保存在連續的內存空間中,因此支持快速隨機訪問,但是在這兩種容器的中間位置添加或刪除元素會非常耗時,因為需要移動插入/ 刪除位置之后的所有元素,來保持連續存儲。而且添加一個元素有時可能還需要分配額外的存儲空間,這種情況下,每個元素都必須移動到新的存儲空間中。
list和forward_list兩個容器添加和刪除操作快速,但不支持元素的隨機訪問,為了訪問一個元素只能遍歷整個容器,其存儲的內存空間不連續。
deque支持快速隨機訪問,中間位置添加或刪除元素非常耗時,但是在deque的兩端添加或刪除元素很快。

確定使用哪種順序容器

通常,使用vector是最好的選擇,除非你有很好的理由選擇其他容器。
在這里插入圖片描述

容器庫概覽

一般來說,每個容器都定義在一個頭文件中,文件名與類型名相同,即deque定義在頭文件deque中,list定義在頭文件list中,以此類推。容器均定義為模板類,例如對vector,我們必須提供額外信息來生成特定的容器類型。對大多數,但不是所有容器,我們還需要額外提供元素類型信息:

list<Sales_data> 保存Sales_data對象的list
deque<double> 保存double的deque

順序容器幾乎可以保存任意類型的元素。特別是,我們可以定義一個容器,其元素的類型是另一個容器。這種容器的定義與任何其他容器類型完全一樣:

vector<vector<string>> lines; 此處lines是一個vector,其元素類型是string的vector

容器操作

在這里插入圖片描述
在這里插入圖片描述

迭代器

迭代器支持的所有操作

forward_list迭代器不支持遞減運算符
在這里插入圖片描述

迭代器支持的所有運算

這些運算只適用于string、vector、deque和array的迭代器,我們不能將它們用于其他任何容器類型的迭代器。

例如,list的迭代器不支持<運算,只支持遞增、遞減、==以及!=運算,原因在于list是將元素以鏈表方式存儲,在內存中不連續,兩個指針的大小關系與它們指向的元素的前后關系并不一定是吻合的,實現<運算將會非常困難和低效。
在這里插入圖片描述

迭代器范圍

一個迭代器范圍由一對迭代器表示,兩個迭代器分別指向同一個容器中的元素或者是尾元素之后的位置。這兩個迭代器通常被稱為begin和end

對構成范圍的迭代器的要求

如果滿足如下條件,兩個迭代器begin和end構成一個迭代器范圍:
它們指向同一個容器中的元素,或者是容器最后一個元素之后的位置,且我們可以通過反復遞增begin來到達end。換句話說,end不在begin之前。

標準庫迭代器范圍左閉右開的三種性質

假定begin和end構成一個合法的迭代器范圍,則

  • 如果begin與end相等,則范圍為空
  • 如果begin與end不相等,則范圍至少包含一個元素,且begin指向該范圍中的第一個元素
  • 我們可以對begin遞增若干次,使得begin==end

容器定義和初始化

每個容器類型都定義了一個默認構造函數。除array之外,其他容器的默認構造函數都會創建一個指定類型的空容器,且都可以接受指定容器大小和元素初始值的參數。
在這里插入圖片描述

將一個新容器創建為另一個容器的拷貝

為了創建一個容器為另一個容器的拷貝,兩個容器的類型及其元素類型必須匹配。不過,當傳遞迭代器參數來拷貝一個范圍時,就不要求容器類型是相同的了,而且新容器和原容器中的元素類型也可以不同,只要能將要拷貝的元素轉換為要初始化的容器的元素類型即可。
在這里插入圖片描述

將array拷貝到vector中的代碼

int ia[] = { 0,1,1,2,3,5,8,13,21,55,89 };
vector<int>vect;
vect.assign(ia,ia+11);

與順序容器大小相關的構造函數

如果元素類型是內置類型或者是具有默認構造函數的類類型,可以只為構造函數提供一個容器大小參數。如果元素類型沒有默認構造函數,除了大小參數外,還必須指定一個顯式的元素初始值。
只有順序容器的構造函數才接受大小參數,關聯容器并不支持。

標準庫array具有固定大小

與內置數組一樣,標準庫array的大小也是類型的一部分。當定義一個array時,除了指定元素類型,還要指定容器大小,例如array<int,42>
與其他容器不同,一個默認構造的array是非空的:它包含了與其大小一樣多的元素。這些元素都被默認初始化。如果我們對array進行列表初始化,則初始值的數目必須等于或小于array的大小。如果初始值數目小于array的大小,則它們被用來初始化array中靠前的元素,所有剩余元素都會進行值初始化。在這兩種情況下,如果元素類型是一個類類型,那么該類必須有一個默認構造函數,以使值初始化能夠進行。

我們不能對內置數組類型進行拷貝或對象賦值操作,但array并無此限制:
在這里插入圖片描述

賦值和swap

與內置數組不同,標準庫array類型允許賦值,賦值后左右兩邊的運算對象需具有相同的類型:

array<int, 10>a1 = {0,1,2,3,4,5,6,7,8,9};
array<int, 10>a2 = { 0 };
a1 = a2;//此時a1中的元素為10個0

在這里插入圖片描述
除array外,swap不對任何元素進行拷貝、刪除或插入操作,因此可以保證在常數時間內完成。
除string外, 指向容器的迭代器、引用和指針在swap操作之后都不會失效,它們仍指向swap操作之前所指向的那些元素,但是在swap之后,這些元素已經屬于不同的容器了,詳情可見對vector進行測試的代碼。與其他容器不同,swap兩個array會真正交換它們的元素,因此,對于array,在swap操作之后,指針、引用和迭代器所綁定的元素保持不變,但元素值已經與另一個array中對應元素的值進行了交換,詳情可見對array進行測試的代碼。

測試swap的代碼

對array進行測試的代碼

int main() {array<int, 10>a1 = {1};array<int, 10>a2 = {0};auto beg1 = a1.begin();auto beg2 = a2.begin();cout << "swap之前:" << endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a : a2) {cout << a << " ";}cout << endl;cout << "a1.begin:"<< *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;swap(a1,a2);cout << "swap之后:"<<endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a:a2) {cout << a << " ";}cout << endl;cout << "a1.begin:" << *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;system("pause");return 0;
}

測試結果:

swap之前:
a1元素:1 0 0 0 0 0 0 0 0 0
a2元素:0 0 0 0 0 0 0 0 0 0
a1.begin:1
a2.begin:0
swap之后:
a1元素:0 0 0 0 0 0 0 0 0 0
a2元素:1 0 0 0 0 0 0 0 0 0
a1.begin:0
a2.begin:1

對vector進行測試的代碼:

int main() {vector<int>a1 = {1};vector<int>a2 = {0};auto beg1 = a1.begin();auto beg2 = a2.begin();cout << "swap之前:" << endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a : a2) {cout << a << " ";}cout << endl;cout << "a1.begin:"<< *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;swap(a1,a2);cout << "swap之后:"<<endl;cout << "a1元素:";for (auto a : a1) {cout << a << " ";}cout << endl;cout << "a2元素:";for (auto a:a2) {cout << a << " ";}cout << endl;cout << "a1.begin:" << *beg1 << endl;cout << "a2.begin:" << *beg2 << endl;system("pause");return 0;
}

測試結果:

swap之前:
a1元素:1
a2元素:0
a1.begin:1
a2.begin:0
swap之后:
a1元素:0
a2元素:1
a1.begin:1
a2.begin:0

關系運算符

每個容器都支持相等運算符(==和 !=),除了無序關聯容器外的所有容器都支持關系運算符(>,>=,<,<=),關系運算符左右兩邊的運算對象必須是相同類型的容器,且必須保存相同類型的元素。
比較兩個容器實際上是進行元素的逐對比較:

  • 如果兩個容器具有相同大小且所有元素都兩兩對應相等,則這兩個容器相等;否則兩個容器不等
  • 如果兩個容器大小不同,但較小容器中每個元素都等于較大容器中的對應元素,則較小容器小于較大容器
  • 如果兩個容器都不是另一個容器的前綴子序列,則它們的比較結果取決于第一個不相等的元素的比較結果

順序容器的特有操作

向順序容器添加元素

除array外,所有標準庫容器都提供靈活的內存管理,在運行時可以動態添加或刪除元素來改變容器大小。
在這里插入圖片描述

容器元素是拷貝

當我們用一個對象來初始化容器時,或將一個對象插入到容器中時,實際上放入到容器中的是對象值的一個拷貝,而不是對象本身。容器中的元素與提供值的對象之間沒有任何關聯,隨后對容器中元素的任何改變都不會影響到原始對象,反之亦然。

在容器中特定位置添加元素:insert

在新標準下,接受元素個數或范圍的insert版本返回指向第一個新加入元素的迭代器,如果范圍為空,不插入任何元素,insert操作會將第一個參數返回。
通過使用insert的返回值,可以在容器中一個特定位置反復插入元素。

s.iinsert(iter,"hello")"hello"添加到iter之前的位置
s.iinsert(iter,10,"hello")    將10個"hello"添加到iter之前的位置
s.insert(s.begin(),s2.begin(),s2.end())  將指定范圍中的元素插入到給定迭代器位置之前
s.insert(s.begin(),{"the","haha","heihei"}) 將初始化列表中的元素插入到給定位置之前
s.insert(s.begin(),s.begin(),s.end())  此句錯誤,拷貝的范圍不能指向與目的位置相同的容器

emplace操作

在這里插入圖片描述

訪問元素

在這里插入圖片描述

訪問成員函數返回的是引用

在容器中訪問元素的成員函數(即,front、back、下標和at)返回的都是引用。如果容器是一個const對象,則返回值是const的引用。如果容器不是const的,則返回值是普通引用,我們可以用來改變元素的值:
在這里插入圖片描述

刪除元素

在這里插入圖片描述

特殊的forward_list操作

在這里插入圖片描述

改變容器大小

在這里插入圖片描述
示例代碼如下:
在這里插入圖片描述

容器操作可能使迭代器失效

向容器中添加元素和從容器中刪除元素的操作可能會使指向容器元素的指針、引用或迭代器失效。一個失效的指針、引用或迭代器將不再表示任何元素。使用失效的指針、引用或迭代器是一種嚴重的程序設計錯誤,很可能會引起與使用未初始化指針一樣的問題。
在這里插入圖片描述
如果在一個循環中插入/刪除deque、string或vector中的元素,不要緩存end返回的迭代器,必須在每次操作后重新調用end(),而不能在循環開始前保存它返回的迭代器。

vector對象是如何增長的

在這里插入圖片描述
reserve并不改變容器中元素的數量,它僅影響vector預先分配多大的內存空間。

capacity和size

容器的size是指它已經保存的元素的數目;而capacity則是在不分配新的內存空間的前提下它最多可以保存多少元素。

額外的string操作

除了順序容器共同的操作之外,string類型還提供了一些額外的操作,這些操作中的大部分要么是提供string類和c風格字符數組之間的相互轉換,要么是增加了運行我們用下標代替迭代器的版本。

構造string的其他方法

在這里插入圖片描述
代碼示例:
在這里插入圖片描述

substr操作

在這里插入圖片描述
在這里插入圖片描述

從一個vector <char> 初始化一個string

vector提供了一個data成員函數,返回其內存空間的首地址

vector<char>vi{ 'a','b' ,'c','d'};
string s(vi.begin(),vi.end());
string s2(vi.data(),vi.size());

改變string的其他方法

在這里插入圖片描述
在這里插入圖片描述

string的下標版本的insert和erase版本

string類型支持順序容器的賦值運算符以及assign、insert和erase操作,除此之外,它還定義了下標版本的insert和erase版本:

	string s="0123456789";s.insert(5, 3, 'A'); //此時s是01234AAA56789,即在s[5]之前插入3個‘A’string s1 = "0123456789";s1.erase(5, 3);//此時s1是0123489,即刪除s[5]之后的3個元素,包括s[5]

string的c風格字符數組版本的insert和erase版本

	const char *cp = "0123456789";string s;s.assign(cp,5);  //s=="01234"s.insert(s.size(),cp+7);s=="01234789"
	string s = "some string";string s2 = "some other string ";s.insert(0,s2);//s=="some other string some string"// 在s[0]之前插入s2中s2[0]開始的s2.size()個字符s.insert(0,s2,0,s2.size());//s=="some other string some other string some string"

append和replace函數

string s="some ";
s.append("things"); //s=="some things"
s.replace(5,3,"hhhh");//s=="some hhhhngs"即從s[5]開始將3個元素,替換為“hhhh”

string搜索操作

string搜索操作,每個操作都返回一個string::size_type值,表示匹配位置的下標。如果搜索失敗,則返回一個名為string::npos的static成員。
在這里插入圖片描述
在這里插入圖片描述

string find

find查找參數指定的字符串,若找到,則返回第一個匹配位置的下標,否則返回npos

string name("AnnaBelleAnnaBelle");
auto pos1=name.find("Anna");//pos1==0
auto pos2 = name.find("Anna",1);//pos2==9 此處是從name[1]處開始查找"Anna",返回第一個匹配位置的下標

string find_first_of

	string numbers("0123456789");string name("n1inin4n");auto pos1 = name.find_first_of(numbers,2);//pos1==6auto pos1 = name.find_first_of(numbers);//pos1==1

string compare函數

根據s是等于、大于還是小于參數指定的字符串,s.compare返回0、正數或負數。
在這里插入圖片描述

數值轉換

	int i = 42;string s = to_string(i);//將整數i轉換為字符“42”double num = stod(s);// 將字符“42”轉換為浮點數42
	s = "00110011";int num = stoi(s,0,2);// 將s轉換為二進制,num==51

在這里插入圖片描述

容器適配器

除了順序容器外,標準庫還定義了三個順序容器適配器:stack、queue和priority_queue。
默認情況下,stack和queue是基于deque實現的,priority_queue是在vector之上實現的。
適配器是標準庫中的一個通用概念,容器、迭代器和函數都有適配器。本質上,一個適配器是一種機制,能使某種事物的行為看起來像另外一種事物一樣。一個容器適配器接受一種已有的容器類型,使其行為看起來像一種不同的類型。

所有容器適配器都支持的操作和類型

在這里插入圖片描述

棧適配器

stack定義在stack頭文件中,先進后出
在這里插入圖片描述

隊列適配器

queue和priority_queue定義在queue頭文件中。
queue,先進先出
priority_queue,允許我們為隊列中的元素建立優先級,新加入的元素會排在所有優先級比它低的已有元素之前。默認情況下,標準庫在元素類型上使用<運算符來確定相對優先級。
在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446561.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446561.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446561.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

常用單位換算

字節單位換算 B(byte)字節 bit 位 1B 8 bit 1KB&#xff08;Kilobyte&#xff0c;千字節&#xff09;1024B 2^10 B&#xff1b; 1MB&#xff08;Megabyte&#xff0c;兆字節&#xff0c;百萬字節&#xff0c;簡稱“兆”&#xff09;1024KB 2^20 B&#xff1b; 1GB&#xf…

牛客網C++面經 容器和算法

原文網址 參考網址 C語言中文網 請你來說一下map和set有什么區別&#xff0c;分別又是怎么實現的&#xff1f; map和set都是C的關聯容器&#xff0c;其底層實現都是紅黑樹&#xff08;RB-Tree&#xff09;。由于 map 和set所開放的各種操作接口&#xff0c;RB-tree 也都提供…

C語言指針-字符指針整型指針char*s int*a

案例代碼 #include<stdio.h> #include<stdlib.h> #include<string.h> int main() {//字符指針char *pstr"good dog ww";printf("字符指針指向的字符串內容:%s\n",pstr);printf("字符指針本身的地址:%p\n",&pstr);printf…

C++ primer 第10章 泛型算法

文章目錄概述findcount初識泛型算法只讀算法只讀算法accumulate只讀算法equal寫容器元素的算法算法fill算法fill_nback_inserter算法copy算法replace replace_copy重排容器元素的算法sortuniqueunique_copy定制操作向算法傳遞函數謂詞算法stable_sort算法partitionlambda表達式…

C語言常用字符串函數

概括 代碼 #include<stdlib.h> #include<stdio.h> #include<string.h> int main() {//常用字符串函數char a[]"abcSDFbnm";char b[]"SD";printf("a的字符串長度:%d\n",strlen(a));printf("b的字符串長度:%d\n",str…

C++ primer 第11章 關聯容器

文章目錄使用關聯容器map示例關聯容器概述定義關聯容器關聯容器值初始化multimap和multiset關鍵字類型的要求pair類型pair上的操作關聯容器操作關聯容器額外的類型別名關聯容器迭代器map迭代器set迭代器關聯容器和算法添加元素向map添加元素檢測insert的返回值使用insert代替下…

C++ primer 第12章 動態內存

文章目錄前言動態內存與智能指針shared_ptr類shared_ptr和unique_ptr都支持的操作shared_ptr獨有的操作make_shared 函數shared_ptr的拷貝和賦值shared_ptr自動銷毀所管理的對象shared_ptr還會自動釋放相關聯的內存程序使用動態內存出于以下原因直接管理內存使用new動態分配和初…

C語言順序查找二分查找

介紹 順序查找 按照順序一個個查找 #include<stdio.h> //順序查找 int search(int arr[],int len,int aim) {int i;for(i0;i<len;i){if(arr[i]aim){return i;//返回下標 }}return -1;//表示未查詢到} int main() {int arr[]{13,355,256,65,234,-1,35,-6,-3,-4,0};…

C++ primer 第12章 12.3 使用標準庫:文本查詢程序

文章目錄使用標準庫&#xff1a;文本查詢程序文本查詢程序設計數據結構在類之間共享數據自己的文本查詢程序書中的文本查詢程序使用標準庫&#xff1a;文本查詢程序 我們將實現一個簡單的文本查詢程序&#xff0c;作為標準庫相關內容學習的總結。 我們的程序允許用戶在一個給…

C語言二維數組 int arr[2][3]

基礎使用 先遍歷行再遍歷列 #include<stdio.h> //二維數組的基本使用 int main() {//二維數組的初始化int arr1[2][2]{{2,2},{0,0}};int arr2[2][3]{2,2,2,8,8,8};int arr3[6][9];int i,j;for(i0;i<6;i){for(j0;j<9;j){arr3[i][j]1;}}arr3[2][5]0;//打印printf(&…

牛客網C++面經 類和數據抽象

請你來說一下C中struct和class的區別 在C中&#xff0c;可以用struct和class定義類&#xff0c;都可以繼承。區別在于&#xff1a;structural的默認繼承權限和默認訪問權限是public&#xff0c;而class的默認繼承權限和默認訪問權限是private。另外&#xff0c;class還可以定義…

C++ primer 第13章 拷貝控制

文章目錄前言拷貝、賦值與銷毀拷貝構造函數合成拷貝構造函數拷貝初始化和直接初始化拷貝初始化的發生&#xff1a;參數和返回值拷貝初始化的限制拷貝賦值運算符重載賦值運算符合成拷貝賦值運算符析構函數析構函數完成的工作什么時候會調用析構函數合成析構函數代碼片段調用幾次…

C語言 指針自增自減加減運算 p++ p+i

介紹 自增自減代碼 #include<stdio.h> #include<string.h> //指針自增--short void increase(short *arr,int len) {int i;arr&arr[0];for(i0;i<len;i){printf("arr[%d]%d,address%p\n",i,*arr,arr);arr;} }//指針自減--char void decrease(char…

C++ 編譯與底層

原文鏈接 編譯與底層請你來說一下一個C源文件從文本到可執行文件經歷的過程&#xff1f; 對于C源文件&#xff0c;從文本到可執行文件一般需要四個過程&#xff1a;預處理階段&#xff1a;對源代碼文件中文件包含關系&#xff08;頭文件&#xff09;、預編譯語句&#xff08;…

C語言 指針數組-字符指針數組整型指針數組 char*s[3] int*a[5] 數組指針int(*p)[4]

基本介紹 1.指針數組:由n個指向整型元素的指針而組成,里面存放指針 Int *ptr[3]; 2.地址: ptr[i]:元素地址 &ptr[i]:指針地址 圖示 代碼: 內存布局: 代碼 #include<stdio.h> #include<string.h> //指針數組--int void pointer(int *arr,int len) {int …

uninitialized_copy測試代碼示例

原測試代碼如下&#xff1a; int main() {vector<int>v1{1,3,5,7,9,2,4,6,8};allocator<int>alloc;auto data alloc.allocate(9);uninitialized_copy(v1.begin(),v1.end(), data);auto end data 9;while(data!end) {cout << *data <<" "…

C語言的地址 內存

取地址在CPU的寄存器產生&#xff0c;不占據內存地址由計算器總線&#xff0c;地址作為常量不消耗內存指針 存儲不同的地址&#xff0c;間接賦值空類型指針 void* 類型指針 不可以取數據 或者修改數據 需要進行強制類型轉換int num 10;void *p &num;std::cout << …

C語言 多重指針--整型字符字符串 int**pp

介紹 多重指針:一個指針指向另一個指針 離值越近的指針級別越大:一級 內存布局 代碼 圖示: 多重指針–整型 #include<stdio.h> #include<string.h> //多重指針--整型//二級指針 void two() {printf("二級指針:\n");int a896;int *p&a,**pp&…

C++ primer 第13章 拷貝控制

文章目錄前言拷貝、賦值與銷毀拷貝構造函數合成拷貝構造函數拷貝初始化和直接初始化拷貝初始化的發生&#xff1a;參數和返回值拷貝初始化的限制拷貝賦值運算符重載賦值運算符合成拷貝賦值運算符析構函數析構函數完成的工作什么時候會調用析構函數合成析構函數代碼片段調用幾次…

牛客網C++面經 C++11

請問C11有哪些新特性&#xff1f; auto關鍵字&#xff1a;編譯器可以根據初始值自動推導出類型。但是不能用于函數傳參以及數組類型的推導nullptr關鍵字&#xff1a;nullptr是一種特殊類型的字面值&#xff0c;它可以被轉換成任意其它的指針類型&#xff1b;而NULL一般被宏定義…