C++基礎知識面試必備、複習細節 (6)
常見的順序容器
順序容器類型 | 特點 |
---|---|
vector | 可變大小的數組。支持快速隨機訪問。在尾部之外的位置插入或刪除元素代價較高 |
list | 雙向鏈表。支持雙向順序訪問。任意位置的插入刪除都效率較高,不支持快速訪問 |
forward_list | 單向鏈表。支持單向順序訪問,任意位置插入刪除效率較高。 |
string | 可變大小的保存字符的容器。支持快速隨機訪問。尾部插入刪除速度快 |
array | 固定大小數組。支持快速隨機訪問。不能添加或刪除元素 |
deque | 雙端隊列。支持快速隨機訪問,頭尾插入較快。 |
-
通常使用vector,除非有更好的理由選擇其他容器
-
如果程序需要在容器中間插入刪除,使用list或forward_list效率較高
-
如果程序需要隨機訪問元素,則使用vector或deque較好
-
迭代器的範圍: [begin,end),即begin代表第一個元素,而end是最後一個元素之後的一個元素
-
vector的初始化:vector<int>爲例
vector<int> a; //默認構造函數 vector<int> a(10); //初始化size爲10的vector vector<int> a(10,1); //10個元素,初始值均爲1 vector<int> a{1,2,3,4,5}; //初始化列表拷貝
-
array的初始化
array<int,40> a; //大小爲40的int數組 array<int,10> b={1}; //第一個元素爲1,其餘爲0 //內置數組不支持拷貝或賦值,但是array支持,只需要操作合法即可 array<int,10> c={0,1,2,3,4,5,6,7,8,9}; array<int,10> d=c;
vector對象是如何增長的
-
vector支持快速隨機訪問元素,因此必須將元素連續存儲,又支持容量動態改變
-
vector實現時記錄有兩個大小:size 和 capacity
size是已經保存的元素的數目,capacity是在不分配新的內存空間的前提下最多能容納的元素數量
vector<int> f(5,1); cout << f.size()<<' '<<f.capacity()<<' '; // 5,5 f.push_back(1); cout << f.size() << ' ' << f.capacity() << ' '; //6 10
-
Vector通過一個連續的數組存放元素,如果集合已滿,在新增數據的時候,就要分配一塊更大的內存,將原來的數據複製過來,釋放之前的內存,在插入新增的元素
-
不同的編譯器實現的擴容方式不一樣,VS2015中以1.5倍擴容,GCC以2倍擴容。
-
擴容倍數實際上是時間和空間的一種權衡,當倍數大時對空間浪費嚴重,倍數小時可能導致頻繁的擴容。
string的一些方法
- s.substr(pos,n) 返回一個字符串,返回s中從pos開始的n個字符串的拷貝
- s.insert(pos,args) 在pos之前插入args制定的字符,pos爲下標或迭代器
- s.find(s1) 在s中查找s1,如果有返回第一個匹配位置的下標,否則返回 npos
- s.compare(s1) 比較兩個字符串,判斷s是否等於、大於或小於s1,返回0、正數或負數
- to_string(T a) 將a轉換爲string類型返回,通常轉換的是數值類型
容器適配器
容器適配器名稱 | 特點 |
---|---|
stack | 先入後出。頭文件 <stack> top()返回棧頂部元素 push()加入元素 pop()刪除元素 |
queue | 先入先出。頭文件<queue> front()返回隊列首元素 back()返回隊列尾元素 push()加入元素 pop()刪除元素 |
priority_queue | 帶優先級的隊列。根據設立的優先級規則進行隊列的排序。 頭文件<queue> 默認是最大堆 push()加入元素 pop()刪除元素 |
priority_queue<Type, Container, Functional>
//
priority_queue <int,vector<int>,greater<int> > q; //最小堆
priority_queue <int,vector<int>,less<int> > q; //最大堆
常用的泛型算法
- find(vec.cbegin(),vec.cend(),val) 如果val出現在vec中,則返回第一次出現的位置,否則返回vec.end()
- accumulate(vec.cbegin(),vec.cend(),val) 返回vec中元素的和,val爲sum的初值
- fill(vec.begin(),vec.end(),val) 將每個元素都填爲val
- sort(vec.begin(),vec.end(),cmp) 排序vec ,可以重寫cmp
lambda表達式
-
C++ 11 中的 Lambda 表達式用於定義並創建匿名的函數對象,簡化編程工作
-
lambda表達式常用於algorithm庫中的一些泛型函數的參數
-
lambda的語法:
[capture list] (parameter list)-> return type{function body} //capture list:捕獲列表 lambda所在函數中定義的局部變量列表 //paremeter list:形參列表 //return type:返回類型 //function body:函數體
-
可以忽略參數列表和返回類型,但必須永遠包含捕獲列表和函數體
-
寫一個lambda函數來調用sort從大到小排序
vector<int> nums{1,3,2,5,4}; sort(nums.begin(), nums.end(), [](int a1,int a2) { return a1 > a2; }); for(auto &i:nums) cout << i << ' '; //5,4,3,2,1
-
用lambda函數作爲for_each的參數執行操作
vector<int> nums{1,3,2,5,4}; sort(nums.begin(), nums.end(), [](int &a1,int &a2) { return a1 > a2; }); for_each(nums.begin(), nums.end(), [](int &a) { cout << a << ' '; });
-
注意lambda函數的值捕獲與引用捕獲
//---------------引用捕獲----------- int a = 1; auto f2 = [&a] { return a; }; a = 0; auto j = f2(); cout << j << endl; //輸出爲0,因爲捕獲的a發生了變化將隨之變化 //----------------值捕獲------------- int a = 1; auto f2 = [a] { return a; }; a = 0; auto j = f2(); cout << j << endl; //輸出爲1,在a改爲0之前其值已經被拷貝並捕獲,a發生變化不影響
因此如果希望在lambda函數中修改局部變量的值,則使用引用捕獲
-
可以通過將捕獲列表的值設爲 = , 則將值捕獲所有的該函數可見的局部變量;
將捕獲類別的值設爲 &,則將引用捕獲所有的函數可見的局部變量
-
默認情況下,如果一個lambda體包含return之外的任何語句,則編譯器認爲該lambda返回爲空
//兩個函數等價 [](int i){return i<0?-i:i;}; [](int i)->int{if(i<0) return -i;else return i;}; //必須聲明返回->int