一. 類型轉換
二. STL
1. 容器
1.1 Vector(常用)
1.1.1 概述?
特性:
動態數組:?想象成一個會自動變長變短的數組。起始在內存中是連續存儲的。
隨機訪問:?通過
[]
運算符或at()
方法,可以瞬間(O(1)復雜度)?訪問任意位置的元素(就像數組下標)。這是它最大的優勢之一。尾部高效:?在末尾添加(
push_back
)或刪除(pop_back
)元素非常快(通常是O(1),除非需要重新分配內存)。中間/頭部低效:?在中間或開頭插入(
insert
)或刪除(erase
)元素比較慢(O(n)復雜度),因為它需要移動后面的所有元素來保持連續性。內存管理:?當添加元素導致當前內存不夠時,
vector
會自動申請一塊更大的新內存(通常是翻倍),把舊元素復制過去,再釋放舊內存。這個操作(reallocation
)開銷較大,所以如果你預先知道大概要存多少元素,用reserve()
提前分配足夠空間能顯著提升性能。大小可變:?
size()
告訴你當前有多少元素,capacity()
告訴你當前分配的內存最多能放多少元素(size
?<=?capacity
)。適用場景:?當你需要像數組一樣快速隨機訪問元素,并且主要在尾部添加/刪除元素時(例如:存儲游戲中的得分列表、讀取文件內容到內存、實現動態數組需求)。
新手注意:?在中間插入刪除很慢!頻繁操作中間位置考慮
list
或deque
。預先reserve()
可以避免頻繁內存分配,提升性能。
1.1.2 vector概念與特性
`vector` 是C++標準模板庫(STL)中的一個動態數組容器,它可以存儲相同類型的元素,并且可以根據需要自動調整大小。以下是 `vector` 的一些主要特性:
1. **動態大小**:`vector` 能夠在運行時動態地增加或減少其大小。當插入新元素時,如果當前容量不足,`vector` 會自動分配更大的內存空間,并將原有的元素復制到新的內存區域。
2. **隨機訪問**:可以使用下標運算符 `[]` 或 `at()` 函數對 `vector` 中的元素進行隨機訪問,時間復雜度為O(1)。
3. **連續存儲**:`vector` 中的元素在內存中是連續存儲的,這使得它可以高效地進行隨機訪問,但在插入或刪除元素時可能需要移動大量元素,時間復雜度較高。
4. **元素類型支持**:`vector` 是一個模板類,可以存儲任意類型的元素,包括內置類型(如 `int`、`double` 等)和自定義類型。
5. **迭代器支持**:`vector` 提供了多種迭代器,如 `begin()`、`end()` 等,可以方便地遍歷容器中的元素。
1.1.3 vector容器的構造函數:
初始化列表構造函數:vector(initializer_list<T> init);?
? ? 該構造函數允許使用初始化列表來創建vector容器,方便一次性初始化多個元素。例如:vector<int> v = {1, 2, 3}; 會創建一個包含元素1、2、3的vector容器。
?1. 默認構造函數:創建一個空的vector容器,模板參數T指定容器中元素的類型。
? ? 例如:vector<int> v; ?會創建一個存儲int類型元素的空容器。?2. 范圍構造函數:vector(v.begin(), v.end());?
? ? 該構造函數會將另一個vector容器v中從開始迭代器,v.begin()到結束迭代器v.end()之間的所有元素拷貝到新創建的vector容器中。?3. 填充構造函數:vector(n, elem);?
? ? 此構造函數會創建一個包含n個元素的vector容器,每個元素的值都為elem。?4. 拷貝構造函數:vector(const vector &vec);?
? ? 用于創建一個新的vector容器,該容器是另一個vector容器vec的副本。
1.1.4?vector的賦值操作:?
1. 重載等號操作符:vector& operator = (const vector &vec);?
? ? 允許將一個vector容器賦值給另一個vector容器,會將vec中的元素復制到當前容器中。?2. assign(beg, end);?
? ? 將從迭代器beg到end之間的元素拷貝賦值給當前vector容器。?3. assign(n, elem);?
? ? 將n個值為elem的元素賦值給當前vector容器。
1.1.5 vector容器和大小的操作:
1. empty();?
? ? 用于判斷vector容器是否為空,如果容器中沒有元素,返回true,否則返回false。2. capacity();?
? ? 返回vector容器當前的容量,即容器在不重新分配內存的情況下可以存儲的元素數量。3. size();?
? ? 返回vector容器中當前實際存儲的元素個數。
4. resize(int num);?
? ? 重新指定容器的長度為num。如果num大于當前容器的大小,容器會變長,新增的位置會用默認值填充;
? ? 如果num小于當前容器的大小,容器會變短,末尾超出容器長度的元素會被刪除。5. resize(int num, elem);?
? ? 同樣是重新指定容器的長度為num,但當容器變長時,新增的位置會用elem值填充。
1.1.6?vector的插入和刪除操作:
1. push_back(elem);?
? ?在vector容器的尾部插入一個新元素elem。2. pop_back();?
? ?刪除vector容器的最后一個元素。
3. insert(const_iterator pos, elem);?? ?在迭代器pos指向的位置插入一個元素elem。
4. insert(const_iterator pos, int count, elem);?
? ?在迭代器pos指向的位置插入count個元素elem。5. erase(const_iterator pos);?
? ?刪除迭代器pos指向的元素。6. erase(const_iterator start, const_iterator end);?
? ?刪除從迭代器start到end之間的所有元素。7. clear();?
? ?刪除vector容器中的所有元素,使容器變為空容器。
1.1.7?vector容器中的數據存取操作:
1. at(int idx);?
? ?返回索引idx所指的數據,如果索引越界,會拋出out_of_range異常。2. operator[];?
? ?同樣返回索引idx所指的數據,但不進行越界檢查,使用時需要確保索引在有效范圍內。3. front();?
? ?返回vector容器中第一個數據元素。
4. back();?
? ?返回vector容器中最后一個數據元素。
1.1.8 vector互換容器操作:
swap(vec);?
? ?將當前vector容器與另一個vector容器vec中的元素進行互換。
1.1.9 vector容器預留空間操作:
reserve(int len);?
? ?容器預留len個元素長度的內存空間,但這些預留位置不會被初始化,元素也不可訪問。
? ?這樣做可以減少在插入元素時頻繁進行內存重新分配的開銷。
?1.1.10 代碼示例:
#include <iostream>
#include <vector>
using namespace std;void VectorApiTest()
{// vector的數據結構我還沒看,注意!// 初始化 vector 的不同方式,由此可知,vector支持重載初始化std::vector<int> myVector; // 創建一個存儲整數的空 vectorstd::vector<int> myVector1(5); // 創建一個包含 5 個整數的 vector,每個值都為默認值(0)vector<int> myVector2(5, 10); // 創建一個包含 5 個整數的 vector,每個值都為 10// 插入vector尾部// 添加的是第一個初始化的值myVector.push_back(1); // 將整數 7 添加到 vector 的末尾myVector.push_back(2);myVector1.push_back(1);myVector1.push_back(2);myVector2.push_back(1);myVector2.push_back(2);// 訪問元素--通過下標來訪問--與數組一致// 注意:vector 不支持負索引,即 myVector[-1] 是無效的// 注意:vector 不支持越界訪問,即 myVector[10] 是無效的int x = myVector[0]; // 獲取第一個元素int y = myVector.at(1); // 獲取第二個元素int x1 = myVector1[0]; // 獲取第一個元素int y1 = myVector1.at(1); // 獲取第二個元素int x2 = myVector2[0]; // 獲取第一個元素int y2 = myVector2.at(1); // 獲取第二個元素// 獲取vector大小int size = myVector.size(); // 獲取 vector 中的元素數量int size1 = myVector1.size();int size2 = myVector2.size();// 迭代vector,由于size()代表其長度for (int i = 0; i < myVector.size(); i++){std::cout << myVector[i] << " "; // 輸出 vector 中的元素}std::cout << std::endl;for (int i = 0; i < myVector1.size(); i++){std::cout << myVector1[i] << " "; // 輸出 vector 中的元素}std::cout << std::endl;for (int i = 0; i < myVector2.size(); i++){std::cout << myVector2[i] << " "; // 輸出 vector 中的元素}// vector的動態擴容機制// 當 vector 中的元素數量超過其容量時,vector 會自動重新分配更大的內存空間來存儲元素。// 這種機制使得 vector 可以動態地調整大小,而不需要手動管理內存。擴容倍數為2倍// 注意:vector 的動態擴容機制可能會導致性能下降,特別是當 vector 中的元素數量很大時。// 因此,在使用 vector 時,應該盡量避免頻繁的插入和刪除操作,以避免性能問題。// 可以使用 reserve() 函數來預先分配內存空間,以避免頻繁的擴容操作。// 可以使用 shrink_to_fit() 函數來釋放未使用的內存空間,以減少內存占用。// 寫出vector的擴容機制的代碼,當vector的size等于capacity時,vector會重新分配內存空間,指針重新指向新的內存空間
}
void VectorApiTest2()
{// 使用構造函數初始化vectorstd::vector<int> myVector = {1, 2, 3, 4, 5};// 使用深拷貝構造函數std::vector<int> myVector1;// assign()函數的作用是將一個vector的內容賦值給另一個vector,屬于深拷貝myVector1.assign(myVector.begin(), myVector.end());for (int i = 0; i < myVector1.size(); i++){std::cout << myVector1[i];}std::cout << std::endl;for (int i = 0; i < myVector.size(); i++){std::cout << myVector[i];}
}
void VectorApiTest3()
{// 調用vector類內置函數std::vector<int> myVector = {1, 2, 3, 4, 5};
}int main(int argc, char const *argv[])
{VectorApiTest(); // 創建對象,調用構造函數,初始化對象,調用析構函數,銷毀對象std::cout << std::endl;VectorApiTest2(); // 深拷貝對象return 0;
}
1.2 String(不想說了)
1.2.1 概述
特性:
專門存儲字符序列:?本質上就是一個專門用來存放
char
(或wchar_t
等)的vector
!它繼承了vector
的核心特性(動態數組、連續內存、隨機訪問、尾部高效)。豐富的字符串操作:?提供了大量方便的方法來處理文本:連接(
+
,?append
)、查找(find
,?rfind
)、子串(substr
)、比較(compare
)、替換(replace
)、插入(insert
)、刪除(erase
)、大小寫轉換等。這些是普通vector
沒有的。C風格兼容:?可以用
c_str()
方法獲得一個指向內部字符數組的const char*
指針,以便與舊的C庫函數交互。自動內存管理:?和
vector
一樣,自動處理內存的分配和釋放。適用場景:?所有需要存儲和操作文本(字符串)的地方。它是C++處理字符串的首選工具。
新手注意:?把它當作一個功能超級強大的字符數組或字符串類型來用就行了。它的底層就是
vector
,所以隨機訪問快,尾部操作快,中間操作慢的特點同樣適用。
1.3 Deque(序列式容器)
1.3.1 概述
特性:
雙端隊列:?全稱是“Double-Ended Queue”。想象成可以在頭尾兩端都進行高效操作的動態數組。
頭尾高效:?在頭部(
push_front
,?pop_front
)?和尾部(push_back
,?pop_back
)?添加/刪除元素都非常快(O(1)復雜度)。這是它相對于vector
的最大優勢。隨機訪問:?支持通過
[]
或at()
進行隨機訪問,速度接近vector
(也是O(1),但常數時間可能略慢一點點)。中間低效:?在中間插入(
insert
)或刪除(erase
)元素比較慢(O(n)復雜度),需要移動元素。內存結構:?內部通常由多塊連續的內存塊(稱為“緩沖區”或“塊”)和一個中央索引(稱為“映射器”)組成。元素不是存儲在單一連續內存塊中,而是分布在多個連續塊里。這使得它在頭尾增長時不需要像
vector
那樣大規模復制整個數組(只需分配新塊或釋放空塊)。適用場景:?需要頻繁在頭部和尾部添加/刪除元素,并且還需要隨機訪問時(例如:實現一個排隊系統,人可以從隊尾加入,也可以從隊頭離開;實現一個滑動窗口算法)。
新手注意:?如果你主要在頭尾操作,選它比
vector
好。內存不是完全連續的(雖然分段連續),這點和vector
不同。隨機訪問速度依然很快,不用擔心。
1.3.2 deque容器的構造函數:
? ? 初始化列表構造函數:deque(initializer_list<T> init);?
? ? 該構造函數允許使用初始化列表來創建deque容器,方便一次性初始化多個元素。例如:deque<int> d = {1, 2, 3}; 會創建一個包含元素1、2、3的deque容器。
1. 默認構造函數:創建一個空的deque容器,模板參數T指定容器中元素的類型。
? ? 例如:deque<int> d; ?會創建一個存儲int類型元素的空容器。2. 范圍構造函數:deque(d.begin(), d.end());?
? ? 該構造函數會將另一個deque容器d中從開始迭代器d.begin()到結束迭代器d.end()之間的所有元素拷貝到新創建的deque容器中。3. 填充構造函數:deque(n, elem);?
? ? 此構造函數會創建一個包含n個元素的deque容器,每個元素的值都為elem。4. 拷貝構造函數:deque(const deque &d);?
? ? 用于創建一個新的deque容器,該容器是另一個deque容器d的副本。
1.3.3 deque的賦值操作:
1. 重載等號操作符:deque& operator = (const deque &d);?
? ? 允許將一個deque容器賦值給另一個deque容器,會將d中的元素復制到當前容器中。2. assign(beg, end);?
? ? 將從迭代器beg到end之間的元素拷貝賦值給當前deque容器。3. assign(n, elem);?
? ? 將n個值為elem的元素賦值給當前deque容器。
1.3.4 deque容器和大小的操作:
1. empty();?
? ? 用于判斷deque容器是否為空,如果容器中沒有元素,返回true,否則返回false。2. size();?
? ? 返回deque容器中當前實際存儲的元素個數。
? ??
3. resize(int num);?
? ? 重新指定容器的長度為num。如果num大于當前容器的大小,容器會變長,新增的位置會用默認值填充;
? ? 如果num小于當前容器的大小,容器會變短,末尾超出容器長度的元素會被刪除。4. resize(int num, elem);?
? ? 同樣是重新指定容器的長度為num,但當容器變長時,新增的位置會用elem值填充。
1.3.5 deque的插入和刪除操作:
1. push_back(elem);?
? ?在deque容器的尾部插入一個新元素elem。2. push_front(elem);?
? ?在deque容器的頭部插入一個新元素elem。3. pop_back();?
? ?刪除deque容器的最后一個元素。4. pop_front();?
? ?刪除deque容器的第一個元素。5. insert(const_iterator pos, elem);?
? ?在迭代器pos指向的位置插入一個元素elem。6. insert(const_iterator pos, int count, elem);?
? ?在迭代器pos指向的位置插入count個元素elem。7. erase(const_iterator pos);?
? ?刪除迭代器pos指向的元素。8. erase(const_iterator start, const_iterator end);?
? ?刪除從迭代器start到end之間的所有元素。9. clear();?
? ?刪除deque容器中的所有元素,使容器變為空容器。
1.3.6?deque容器中的數據存取操作:
1. at(int idx);?
? ?返回索引idx所指的數據,如果索引越界,會拋出out_of_range異常。2. operator[];?
? ?同樣返回索引idx所指的數據,但不進行越界檢查,使用時需要確保索引在有效范圍內。3. front();?
? ?返回deque容器中第一個數據元素。
4. back();?
? ?返回deque容器中最后一個數據元素。
1.3.7 deque互換容器操作:
swap(d);?
? ?將當前deque容器與另一個deque容器d中的元素進行互換。
?1.3.8 代碼示例:
#include <iostream>
#include <deque>
using namespace std;void printDeque(const deque<int> &d)
{for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++){cout << *it << " ";}cout << endl;
}int main()
{deque<int> d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);deque<int> d2(d1.begin(), d1.end());printDeque(d2);deque<int> d3(5, 100);printDeque(d3);deque<int> d4(d3);printDeque(d4);return 0;
}
1.4 Stack?容器適配器 - 通常基于deque/list/vector)
1.4.1 概述
特性:
后進先出 (LIFO):?像一摞盤子。你只能訪問或拿走最頂上的那個盤子(最后放上去的)。
限制接口:?只允許在棧頂進行操作:
push()
: 將元素壓入棧頂 (入棧)
pop()
: 移除棧頂元素 (出棧) -?注意:它不返回被移除的元素值!?需要先用top()
獲取。
top()
: 獲取棧頂元素的引用(不刪除)
empty()
: 檢查棧是否為空
size()
: 獲取棧中元素數量底層容器:?
stack
本身不管理內存,它是對底層容器(默認是deque
,也可以用list
或vector
)的封裝,只暴露棧的操作接口。底層容器決定了內存管理的細節。適用場景:?任何需要LIFO行為的地方:函數調用棧、表達式求值(如括號匹配)、撤銷操作(Undo)、深度優先搜索(DFS)。
新手注意:?
pop()
不返回值!先用top()
拿到值,再pop()
移除它。理解LIFO思想是關鍵。它只是個適配器,底層可以是deque
、list
或vector
(默認deque
性能最好)。
1.4.2?stack容器的構造函數:
### 默認構造函數:stack<T, Container = deque<T>> s;?
? ? 創建一個空的stack容器,模板參數T指定容器中元素的類型,Container指定底層容器的類型,默認使用deque。
? ? 例如:stack<int> s; ?會創建一個存儲int類型元素的空棧,底層使用deque。
1.4.3?stack的賦值操作:
由于 `stack` 沒有提供直接的賦值操作符重載,但可以通過創建新的 `stack` 并復制元素來實現賦值。
1.4.4?stack容器和大小的操作:
1. empty();?
? ? 用于判斷stack容器是否為空,如果棧中沒有元素,返回true,否則返回false。2. size();?
? ? 返回stack容器中當前實際存儲的元素個數。
1.4.5?stack的插入和刪除操作:
1. push(elem);?
? ?在stack容器的棧頂插入一個新元素elem。2. pop();?
? ?刪除stack容器的棧頂元素。
1.4.6 stack容器中的數據存取操作:
1. top();?
? ?返回stack容器中棧頂的數據元素,但不刪除該元素。
?1.4.7 代碼示例
#include <iostream>#include <stack>using namespace std;void printStack(const stack<int>& s) {stack<int> tmp = s;while (!tmp.empty()) {cout << tmp.top() << " ";tmp.pop();}cout << endl;}int main() {stack<int> s;s.push(1);s.push(2);s.push(3);printStack(s);cout << s.size() << endl;cout << s.top() << endl;s.pop();printStack(s);}
1.5 Queue
1.5.1 概述
特性:
先進先出 (FIFO):?像排隊買票。先來的人站在隊頭,先買到票離開。
限制接口:?操作限定在隊尾添加,隊頭移除:
push()
?/?enqueue()
: 在隊尾添加元素 (入隊)
pop()
?/?dequeue()
: 從隊頭移除元素 (出隊) -?同樣不返回移除的元素值!
front()
: 獲取隊頭元素的引用(不刪除)
back()
: 獲取隊尾元素的引用(不刪除)
empty()
,?size()
底層容器:?需要底層容器支持高效的前端刪除(
pop_front
)?和尾部添加(push_back
)。默認是deque
(因為頭尾操作都高效)。也可以用list
(頭尾操作也高效)。不能用vector
做默認底層容器,因為vector
的頭部刪除(pop_front
)效率太低(O(n))!適用場景:?任何需要FIFO行為的地方:消息隊列、任務調度、廣度優先搜索(BFS)、打印任務隊列。
新手注意:?
pop()
不返回值!先用front()
拿到隊頭值,再pop()
移除它。理解FIFO思想。底層默認是deque
,也可以用list
,不能用vector
。
1.5.2?queue容器的構造函數:
### 默認構造函數:queue<T, Container = deque<T>> q;?
? ? 創建一個空的queue容器,模板參數T指定容器中元素的類型,Container指定底層容器的類型,默認使用deque。
? ? 例如:queue<int> q; ?會創建一個存儲int類型元素的空隊列,底層使用deque。
1.5.3?queue的賦值操作:
由于 `queue` 沒有提供直接的賦值操作符重載,但可以通過創建新的 `queue` 并復制元素來實現賦值。
1.5.4?queue容器和大小的操作:
1. empty();?
? ? 用于判斷queue容器是否為空,如果隊列中沒有元素,返回true,否則返回false。2. size();?
? ? 返回queue容器中當前實際存儲的元素個數。
1.5.5?queue的插入和刪除操作:
1. push(elem);?
? ?在queue容器的隊尾插入一個新元素elem。2. pop();?
1.5.6?queue容器中的數據存取操作:
1. front();?
? ?返回queue容器中隊頭的數據元素,但不刪除該元素。2. back();?
? ?返回queue容器中隊尾的數據元素,但不刪除該元素。
1.5.7 代碼示例
#include <iostream>
#include <queue>
using namespace std;
void printQueue(const queue<int> &q)
{queue<int> tmp = q;while (!tmp.empty()){cout << tmp.front() << " ";tmp.pop();}cout << endl;
}
int main()
{queue<int> q;q.push(1);q.push(2);q.push(3);printQueue(q);cout << q.size() << endl;cout << q.front() << endl;cout << q.back() << endl;q.pop();printQueue(q);// queue的常用接口// 構造函數queue<int> q1;queue<int> q2(q1);queue<int> q3(5, 100);// 賦值操作queue<int> q4;q4 = q3;// 大小操作cout << q4.size() << endl;// 判空操作cout << q4.empty() << endl;// 入隊操作q4.push(100);printQueue(q4);// 出隊操作q4.pop();printQueue(q4);// 訪問隊頭元素cout << q4.front() << endl;// 訪問隊尾元素cout << q4.back() << endl;// 交換操作queue<int> q5;q5.push(1000);q5.push(2000);printQueue(q5);q4.swap(q5);printQueue(q4);printQueue(q5);
}
1.6 List(序列式容器)
1.6.1 概述
特性:
雙向鏈表:?想象成一串珍珠項鏈。每個元素(珍珠)都包含數據和兩個指針,分別指向前一個元素和后一個元素。
任意位置高效插入/刪除:?在任何位置(包括頭部和尾部)插入(
insert
)或刪除(erase
)一個元素都非常快(O(1)復雜度),只要你知道位置(迭代器)。因為只需要修改幾個指針,不需要移動其他元素。這是它最大的優勢!不支持隨機訪問:?不能用
[]
或at()
瞬間跳到第n個元素。要訪問第n個元素,必須從鏈表頭(或尾)開始一個一個(O(n)復雜度)遍歷過去。額外操作:?提供鏈表特有的高效操作:
splice()
: 把另一個鏈表的一部分(或全部)移動到當前鏈表的指定位置(只改指針,超快)。
merge()
: 合并兩個已排序鏈表(高效)。
sort()
: 鏈表自身的排序算法(通常比algorithm
里的std::sort
對鏈表更高效,因為std::sort
需要隨機訪問)。
unique()
: 移除連續的重復元素(常與sort()
配合使用去重)。內存開銷:?每個元素除了數據本身,還需要額外的空間存儲前后指針(通常是兩個指針的大小)。
內存不連續:?元素分散在內存各處,對CPU緩存不友好(相比
vector
,?deque
)。適用場景:?需要頻繁在任意位置(尤其是中間)插入或刪除元素,并且不需要隨機訪問時(例如:實現一個隨時可能插入刪除中間項的播放列表、實現LRU緩存淘汰算法)。
新手注意:?隨機訪問很慢!遍歷用迭代器,別嘗試用下標。插入刪除快是優勢。內存開銷比
vector
大。forward_list
是單向鏈表(只支持向前遍歷),開銷更小,但功能也少些。
1.6.2?list容器的構造函數:
### 初始化列表構造函數:list(initializer_list<T> init);?
? ? 該構造函數允許使用初始化列表來創建list容器,方便一次性初始化多個元素。例如:list<int> l = {1, 2, 3}; 會創建一個包含元素1、2、3的list容器。
1. 默認構造函數:創建一個空的list容器,模板參數T指定容器中元素的類型。
? ? 例如:list<int> l; ?會創建一個存儲int類型元素的空容器。2. 范圍構造函數:list(l.begin(), l.end());?
? ? 該構造函數會將另一個list容器l中從開始迭代器l.begin()到結束迭代器l.end()之間的所有元素拷貝到新創建的list容器中。3. 填充構造函數:list(n, elem);?
? ? 此構造函數會創建一個包含n個元素的list容器,每個元素的值都為elem。4. 拷貝構造函數:list(const list &l);?
? ? 用于創建一個新的list容器,該容器是另一個list容器l的副本。
1.6.3 list的賦值操作:
1. 重載等號操作符:list& operator = (const list &l);?
? ? 允許將一個list容器賦值給另一個list容器,會將l中的元素復制到當前容器中。2. assign(beg, end);?
? ? 將從迭代器beg到end之間的元素拷貝賦值給當前list容器。3. assign(n, elem);?
? ? 將n個值為elem的元素賦值給當前list容器。
1.6.4?list容器和大小的操作:
1. empty();?
? ? 用于判斷list容器是否為空,如果容器中沒有元素,返回true,否則返回false。2. size();?
? ? 返回list容器中當前實際存儲的元素個數。
? ??
3. resize(int num);?
? ? 重新指定容器的長度為num。如果num大于當前容器的大小,容器會變長,新增的位置會用默認值填充;
? ? 如果num小于當前容器的大小,容器會變短,末尾超出容器長度的元素會被刪除。4. resize(int num, elem);?
? ? 同樣是重新指定容器的長度為num,但當容器變長時,新增的位置會用elem值填充。
1.6.5?list的插入和刪除操作:
1. push_back(elem);?
? ?在list容器的尾部插入一個新元素elem。2. push_front(elem);?
? ?在list容器的頭部插入一個新元素elem。3. pop_back();?
? ?刪除list容器的最后一個元素。4. pop_front();?
? ?刪除list容器的第一個元素。5. insert(const_iterator pos, elem);?
? ?在迭代器pos指向的位置插入一個元素elem。6. insert(const_iterator pos, int count, elem);?
? ?在迭代器pos指向的位置插入count個元素elem。7. erase(const_iterator pos);?
? ?刪除迭代器pos指向的元素。8. erase(const_iterator start, const_iterator end);?
? ?刪除從迭代器start到end之間的所有元素。9. clear();?
? ?刪除list容器中的所有元素,使容器變為空容器。
1.6.6?list容器中的數據存取操作:
由于 `list` 不支持隨機訪問,沒有 `at()` 和 `operator[]` 操作。可以通過迭代器訪問元素。
1. front();?
? ?返回list容器中第一個數據元素。
? ?
2. back();?
? ?返回list容器中最后一個數據元素。
1.6.7?list互換容器操作:
swap(l);?
? ?將當前list容器與另一個list容器l中的元素進行互換。
1.6.8 代碼示例?
#include <iostream>
#include <list>
using namespace std;
void printList(const list<int> &l)
{list<int> tmp = l;while (!tmp.empty()){cout << tmp.front() << " ";tmp.pop_front();}cout << endl;
}
int main()
{list<int> l1;for (int i = 0; i < 10; i++){l1.push_back(i);}printList(l1);// 構造函數list<int> l2(l1.begin(), l1.end());printList(l2);// 賦值操作list<int> l3;l3 = l2;printList(l3);// 大小操作cout << l3.size() << endl;// 判空操作cout << l3.empty() << endl;// 插入操作l3.push_back(10);printList(l3);l3.push_front(20);printList(l3);// 刪除操作l3.pop_back();printList(l3);l3.pop_front();printList(l3);// 插入操作l3.insert(l3.begin(), 100);printList(l3);// 刪除操作l3.erase(l3.begin());printList(l3);// 清空操作l3.clear();printList(l3);// 反轉操作l3.reverse();printList(l3);// 排序操作l3.sort();printList(l3);// 合并操作list<int> l4;l4.push_back(100);l4.push_back(200);l4.push_back(300);printList(l4);// 交換操作l3.swap(l4);printList(l3);printList(l4);// 移除操作l3.remove(100);printList(l3);// 拷貝操作list<int> l5(l3);printList(l5);// 賦值操作l5 = l3;printList(l5);// 比較操作cout << (l3 == l5) << endl;cout << (l3 != l5) << endl;cout << (l3 < l5) << endl;cout << (l3 > l5) << endl;cout << (l3 <= l5) << endl;cout << (l3 >= l5) << endl;// 訪問操作cout << l3.front() << endl;cout << l3.back() << endl;// 迭代器操作list<int>::iterator it = l3.begin();while (it != l3.end()){cout << *it << " ";it++;}cout << endl;// 反向迭代器操作list<int>::reverse_iterator rit = l3.rbegin();while (rit != l3.rend()){cout << *rit << " ";rit++;}
}
1.7 MultiSet/Set?
1.7.1 概述
特性 (Set):
唯一鍵集合:?存儲唯一的
Key
。每個元素就是鍵本身(Key = Value
)。自動排序:?元素總是按鍵(
Key
)自動升序排序(默認<
比較,可自定義比較規則)。你無法控制元素的物理存儲順序。高效查找:?基于排序,查找(
find()
,?count()
,?lower_bound()
,?upper_bound()
)一個元素的速度非常快(O(log n)復雜度),使用二分查找思想。插入/刪除效率:?插入(
insert
)和刪除(erase
)元素也是O(log n)復雜度,因為需要維護排序和樹的平衡。鍵不可修改:?一旦元素插入,其鍵值(
Key
)就不能被直接修改(因為會破壞排序)。要修改,通常需要先刪除舊元素,再插入新元素。特性 (MultiSet):
多重鍵集合:?允許存儲多個值相同的元素(多個相同的
Key
)。除了允許重復鍵之外,其他特性(自動排序、高效查找、O(log n)插入刪除)與
set
完全相同。查找時
count(key)
可能大于1,equal_range(key)
返回一個包含所有該key
的迭代器范圍。底層結構:?通常實現為紅黑樹(一種自平衡的二叉搜索樹),這保證了操作的O(log n)復雜度。
適用場景 (Set):?需要存儲唯一值并需要快速查找、自動排序(例如:維護一個不重復的用戶ID集合、字典單詞集合)。
適用場景 (MultiSet):?需要存儲可能重復的值并需要快速查找、自動排序(例如:統計成績,允許有多個相同分數;記錄日志時間戳,允許重復時間)。
新手注意:?元素自動排序!
set
里元素唯一,multiset
允許重復。查找插入刪除都很快(O(log n))。鍵值不可直接改。理解“鍵(Key
)”就是元素本身。
?1.7.2?
1.7.3?
1.7.4?
1.7.5?
1.7.6?
1.7.7
1.7.8?
1.7.9
1.7.10?
1.8 MultiMap/Map
?1.7.2?
1.7.3?
1.7.4?
1.7.5?
1.7.6?
1.7.7
1.7.8?
1.7.9
1.7.10?
1.8.1 概述
特性 (Map):
鍵值對集合:?存儲的元素是
pair<const Key, Value>
。Key
是鍵,用于查找和排序;Value
是與鍵關聯的值。唯一鍵:?每個
Key
在map
中必須是唯一的。按鍵自動排序:?元素總是按鍵(
Key
)自動升序排序(默認<
比較,可自定義)。高效查找:?基于鍵(
Key
)進行查找(find()
,?count()
,?operator[]
,?at()
,?lower_bound()
,?upper_bound()
)非常快(O(log n)復雜度)。插入/刪除效率:?插入(
insert
)和刪除(erase
)也是O(log n)復雜度。鍵不可修改:?插入后,元素的鍵(
Key
)是const
的,不能被修改(會破壞排序)。值(Value
)可以修改。
operator[]
:?map[key]
?是一個強大的操作:
如果
key
存在,返回對應Value
的引用。如果
key
不存在,則自動插入一個pair<key, Value()>
(用Value
類型的默認構造函數創建新值),然后返回這個新Value
的引用。這個特性使得用map
計數 (map[key]++
) 非常方便,但也容易不小心插入新元素。
at()
:?map.at(key)
?會檢查key
是否存在。存在則返回Value
的引用;不存在則拋出std::out_of_range
異常。更安全。特性 (MultiMap):
多重鍵鍵值對集合:?允許多個元素擁有相同的鍵(
Key
),但它們的值(Value
)可以不同(也可以相同)。除了允許重復鍵之外,其他特性(按鍵排序、高效查找、O(log n)插入刪除)與
map
完全相同。查找時
count(key)
可能大于1,equal_range(key)
返回一個包含所有該key
的鍵值對的迭代器范圍。底層結構:?通常也實現為紅黑樹。
適用場景 (Map):?需要建立唯一鍵(
Key
)到值(Value
)?的映射關系,并需要按鍵快速查找、自動按鍵排序(例如:電話簿<姓名, 號碼>、學生信息系統<學號, 學生信息>、單詞計數器<單詞, 出現次數>)。適用場景 (MultiMap):?需要建立鍵(
Key
)到值(Value
)?的映射關系,且一個鍵可能對應多個值,并需要按鍵快速查找、自動按鍵排序(例如:作者著作索引<作者名, 書名>、日期事件記錄<日期, 事件描述>)。新手注意:?存儲的是
鍵值對
(key-value pair)。map
鍵唯一,multimap
鍵可重復。按鍵自動排序!查找插入刪除都很快(O(log n))。鍵(Key
)不可修改。map[key]
會創建新元素,map.at(key)
更安全。理解鍵(Key
)和值(Value
)的區別。
1.9 總結?
容器 | 類型 | 順序/排序 | 主要特性 | 插入/刪除效率 (典型) | 查找效率 (典型) | 隨機訪問 | 重復元素 | 備注 |
---|---|---|---|---|---|---|---|---|
vector | 序列式 | 插入順序 | 動態數組,連續內存,尾快,隨機訪問快 | 尾: O(1) 中/頭: O(n) | O(n) | O(1) | 允許 | 最常用,隨機訪問首選 |
string | 序列式 | 插入順序 | 字符專用的vector ,豐富字符串操作 | 尾: O(1) 中/頭: O(n) | O(n) | O(1) | 允許 | 文本處理核心 |
deque | 序列式 | 插入順序 | 雙端隊列,頭尾操作都快,分段連續內存,隨機訪問接近vector | 頭/尾: O(1)?中: O(n) | O(n) | ~O(1) | 允許 | 頭尾操作頻繁時選它 |
stack | 適配器 | LIFO (后進先出) | 只允許在棧頂操作 (push ,?pop ,?top ) | O(1) (頂) | - | No | 允許 | 基于deque (默認)/list /vector |
queue | 適配器 | FIFO (先進先出) | 只允許隊尾加(push ),隊頭刪(pop ) (front ,?back ) | O(1) (尾加/頭刪) | - | No | 允許 | 基于deque (默認)/list |
list | 序列式 | 插入順序 | 雙向鏈表,任意位置插入刪除快,內存不連續 | 任意位置: O(1)?(已知迭代器) | O(n) | No | 允許 | 中間頻繁插入刪除時選它 |
set | 關聯式 | 按鍵自動排序 | 唯一Key 集合 (Key=Value ),自動排序,查找快 | O(log n) | O(log n) | No | No | 唯一鍵集合,排序,查找 |
multiset | 關聯式 | 按鍵自動排序 | 多重Key 集合 (Key=Value ),自動排序,查找快 | O(log n) | O(log n) | No | 允許 | 可重復鍵集合,排序,查找 |
map | 關聯式 | 按鍵自動排序 | 唯一Key 到Value 的映射,自動按鍵排序,按鍵查找快 | O(log n) | O(log n)?(by Key) | No | No?(Key) | 鍵值對,鍵唯一,按鍵排序查找 |
multimap | 關聯式 | 按鍵自動排序 | 多重Key 到Value 的映射,自動按鍵排序,按鍵查找快 | O(log n) | O(log n)?(by Key) | No | 允許 (Key) | 鍵值對,鍵可重復,按鍵排序查找 |
2. 算法
2.1 查找算法
2.1.1 概述
STL 查找算法詳解
?一、線性查找算法
1. std::find
- 特點 :通用的查找算法,對容器中的元素逐個進行比較,直至找到目標元素或者遍歷完整個容器。不要求容器中的元素有序,實現簡單,但在數據量較大時效率較低。
- 底層原理 :借助迭代器從容器的起始位置開始,逐個訪問元素并和目標值進行比較,直到找到匹配元素或者到達容器末尾。
- 分類 :線性查找算法。
- 使用方法 :需要包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器以及要查找的目標值。函數返回一個迭代器,若找到目標值,該迭代器指向目標元素;若未找到,則返回結束迭代器。
- 要求 :容器需提供雙向迭代器或者前向迭代器。2. std::find_if
- 特點 :能夠使用自定義的謂詞函數來查找滿足特定條件的元素,同樣不要求容器元素有序。可根據不同的查找條件靈活使用。
- 底層原理 :使用迭代器遍歷容器,對每個元素調用謂詞函數,直到找到使謂詞函數返回 true 的元素或者遍歷完整個容器。
- 分類 :線性查找算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器以及一個一元謂詞函數。返回一個迭代器,指向第一個使謂詞函數返回 true 的元素,若未找到則返回結束迭代器。
- 要求 :容器需提供雙向迭代器或者前向迭代器,謂詞函數必須是一元函數。二、二分查找算法
1. std::binary_search
- 特點 :要求容器元素已經按照升序排列,通過不斷將搜索區間縮小一半來查找目標元素,查找效率較高,時間復雜度為 $O(log n)$。
- 底層原理 :每次把搜索區間分成兩部分,比較中間元素和目標值的大小,依據比較結果縮小搜索區間,直到找到目標元素或者搜索區間為空。
- 分類 :二分查找算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器以及要查找的目標值。函數返回一個布爾值,表示是否找到目標元素。
- 要求 :容器元素必須有序,容器需提供隨機訪問迭代器。### 2. std::lower_bound
- 特點 :返回第一個不小于目標值的元素的迭代器,要求容器元素有序。可用于查找滿足特定條件的最小元素。
- 底層原理 :基于二分查找算法,不斷縮小搜索區間,最終找到第一個不小于目標值的元素。
- 分類 :二分查找算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器以及目標值。返回一個迭代器,指向第一個不小于目標值的元素。
- 要求 :容器元素必須有序,容器需提供隨機訪問迭代器。### 3. std::upper_bound
- 特點 :返回第一個大于目標值的元素的迭代器,要求容器元素有序。可用于查找滿足特定條件的最小上界。
- 底層原理 :基于二分查找算法,不斷縮小搜索區間,最終找到第一個大于目標值的元素。
- 分類 :二分查找算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器以及目標值。返回一個迭代器,指向第一個大于目標值的元素。
- 要求 :容器元素必須有序,容器需提供隨機訪問迭代器。## 三、其他查找算法
### 1. std::find_end
- 特點 :在一個序列中查找最后一次出現的子序列,不要求序列有序。適用于查找子序列最后一次出現的位置。
- 底層原理 :從主序列的末尾開始,逐個檢查是否存在與子序列匹配的部分。
- 分類 :子序列查找算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入主序列的起始迭代器、結束迭代器,以及子序列的起始迭代器、結束迭代器。返回一個迭代器,指向主序列中最后一次出現子序列的起始位置。
- 要求 :主序列和子序列需提供雙向迭代器。### 2. std::find_first_of
- 特點 :在一個序列中查找第一個出現在另一個序列中的元素,不要求序列有序。可用于查找兩個序列中的公共元素。
- 底層原理 :遍歷第一個序列,對于每個元素,檢查是否存在于第二個序列中。
- 分類 :元素查找算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,以及第二個序列的起始迭代器、結束迭代器。返回一個迭代器,指向第一個序列中第一個出現在第二個序列中的元素。
- 要求 :兩個序列需提供前向迭代器。
?2.1.2 代碼示例:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;void printVector(vector<int> &v)
{for (int data : v){cout << data << "\t";}cout << endl;
}int MultiNum(int num)
{return num * 10;
}
int main()
{vector<int> v = {10, 20, 30, 40, 50};// 常用查找算法/*find-在容器中查找指定數據需要指定條件 find(v.begin(), v.end(), 30)1. v.begin()迭代器起始 v.end()迭代器結束2 .30是要查找的數據*/vector<int>::iterator it = find(v.begin(), v.end(), 30);if (it == v.end()){cout << "沒有找到" << endl;}else{cout << "找到了" << endl;}/*find_if1. 查找指定條件的數據2. 查找條件需要自己定義3. 函數對象 仿函數 函數指針 匿名函數 都可以作為find_if的第三個參數find_if(v.begin(), v.end(), [](int num));*/vector<int>::iterator it2 = find_if(v.begin(), v.end(), [](int num){ return num > 20; });if (it2 == v.end()){cout << "沒有找到" << endl;}else{cout << "找到了" << endl;}/*
adjacent_find1.查找相鄰重復元素2.返回相鄰元素的第一個位置的迭代器3.如果找不到返回最后一個元素的迭代器,即v.end()adjacent_find(v.begin(), v.end())*/vector<int>::iterator it3 = adjacent_find(v.begin(), v.end());if (it3 == v.end()){cout << "沒有找到" << endl;}else{cout << "找到了" << endl;}/*
binary_search1.二分查找法2.在有序序列中查找指定元素3.找到返回true,否則返回false4.底層是利用lower_bound實現的5.binary_search(v.begin(), v.end(), 30) 30為要查找的元素*/bool ret = binary_search(v.begin(), v.end(), 30);if (ret){cout << "找到了" << endl;}else{cout << "沒有找到" << endl;}/*count1.統計元素個數2.count(v.begin(), v.end(), 30) 30為要查找的元素3.返回為找找的元素個數,返回值為int*/int num = count(v.begin(), v.end(), 30);cout << "num = " << num << endl;// count_ifint num2 = count_if(v.begin(), v.end(), [](int num){ return num > 20; });cout << "num2 = " << num2 << endl;/*transform1.搬運容器到另一個容器中2.需要指定源容器和目標容器的起始迭代器3.需要指定要執行的操作4.需要指定容器的大小*/vector<int> v2;v2.resize(v.size());transform(v.begin(), v.end(), v2.begin(), MultiNum);printVector(v2);/*for_each1.遍歷容器2.需要指定容器的起始迭代器和結束迭代器3.需要指定要執行的操作4.不需要指定容器的大小for_each(v2.begin(), v2.end(), [](int &num);[*/for_each(v2.begin(), v2.end(), [](int &num){ num *= 10; });printVector(v2);printVector(v2);
}
2.2 遍歷算法
2.2.1 概述
# STL 遍歷算法詳解
## 一、基本遍歷算法
### 1. std::for_each
- 特點 :對容器中的每個元素應用指定的函數,不修改容器中的元素,適用于對容器元素進行批量處理。實現簡單,使用靈活。
- 底層原理 :借助迭代器遍歷容器,對每個元素調用指定的函數對象。
- 分類 :基本遍歷算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器以及一個函數對象。函數返回傳入的函數對象。
- 要求 :容器需提供前向迭代器。### 2. std::transform
- 特點 :可以將一個或兩個序列中的元素通過指定的操作轉換到另一個序列中,支持原地轉換和目標序列轉換。可用于對容器元素進行批量修改。
- 底層原理 :使用迭代器遍歷源序列,對每個元素應用指定的操作,并將結果存儲到目標序列中。
- 分類 :轉換遍歷算法。
- 使用方法 :包含 <algorithm> 頭文件,對于單序列轉換,調用時傳入源序列的起始迭代器、結束迭代器,目標序列的起始迭代器以及一個一元操作函數;對于雙序列轉換,還需傳入第二個源序列的起始迭代器和一個二元操作函數。返回指向目標序列中最后一個被寫入元素的下一個位置的迭代器。
- 要求 :源序列需提供前向迭代器,目標序列需提供可寫的前向迭代器。## 二、并行遍歷算法(C++17 及以后)
### 1. std::for_each_n
- 特點 :對序列中的前 n 個元素應用指定的函數,可用于部分遍歷。
- 底層原理 :使用迭代器遍歷序列的前 n 個元素,對每個元素調用指定的函數對象。
- 分類 :部分遍歷算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、元素數量 n 以及一個函數對象。函數返回傳入的函數對象。
- 要求 :序列需提供前向迭代器。### 2. std::for_each_parallel
- 特點 :并行地對容器中的每個元素應用指定的函數,可提高處理效率,適用于大規模數據處理。
- 底層原理 :將容器劃分為多個子區間,并行地對每個子區間中的元素調用指定的函數對象。
- 分類 :并行遍歷算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入執行策略(如 `std::execution::par`)、容器的起始迭代器、結束迭代器以及一個函數對象。函數返回傳入的函數對象。
- 要求 :容器需提供隨機訪問迭代器,函數對象需是可并行執行的。
2.2.2 代碼示例
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
/*
遍歷算法for_each: 遍歷容器transform: 搬運容器到另一個容器中
*/
int main()
{vector<int> v = {10, 20, 30, 40, 50};// 使用lambda表達式遍歷容器for_each(v.begin(), v.end(), [](int value) -> void{ cout << value << "\t"; });cout << endl;// 使用transform搬運容器到另一個容器中vector<int> v2;v2.resize(v.size()); // 需要提前使用v1的容量開辟空間。transform(v.begin(), v.end(), v2.begin(), [](int value) -> int{ return value; });for_each(v2.begin(), v2.end(), [](int value) -> void{ cout << value << "\t"; });
}
2.3 排序算法
2.3.1 概述
# STL 排序算法詳解
## 一、基本排序算法
### 1. std::sort
- 特點 :對容器中的元素進行升序排序,使用快速排序、堆排序和插入排序的混合算法,平均時間復雜度為 $O(n log n)$。排序效率較高,但會改變元素的相對順序。
- 底層原理 :根據數據規模和分布情況,選擇合適的排序算法。當數據規模較小時,使用插入排序;當數據規模較大時,使用快速排序;當快速排序的遞歸深度過大時,使用堆排序。
- 分類 :基本排序算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器,也可以傳入一個比較函數來指定排序規則。函數無返回值。
- 要求 :容器需提供隨機訪問迭代器。### 2. std::stable_sort
- 特點 :對容器中的元素進行升序排序,保證相等元素的相對順序不變,使用歸并排序算法,時間復雜度為 $O(n log n)$。排序效率較高,但空間復雜度較高。
- 底層原理 :將容器劃分為多個子區間,對每個子區間進行排序,然后將排序好的子區間合并。
- 分類 :穩定排序算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、結束迭代器,也可以傳入一個比較函數來指定排序規則。函數無返回值。
- 要求 :容器需提供隨機訪問迭代器。## 二、部分排序算法
### 1. std::partial_sort
- 特點 :對容器中的前 n 個元素進行排序,將最小的 n 個元素放到容器的前 n 個位置,時間復雜度為 $O(n log n)$。適用于只需要部分排序的場景。
- 底層原理 :使用堆排序算法,維護一個大小為 n 的最大堆,遍歷容器中的元素,將比堆頂元素小的元素替換堆頂元素,并調整堆。
- 分類 :部分排序算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、指向第 n 個元素的迭代器、結束迭代器,也可以傳入一個比較函數來指定排序規則。函數無返回值。
- 要求 :容器需提供隨機訪問迭代器。### 2. std::nth_element
- 特點 :將容器中的第 n 個元素放到其排序后的位置,使得該位置之前的元素都小于等于它,之后的元素都大于等于它,時間復雜度為 $O(n)$。適用于查找第 n 小的元素。
- 底層原理 :使用快速選擇算法,通過不斷劃分區間,縮小查找范圍,直到找到第 n 個元素。
- 分類 :選擇排序算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入容器的起始迭代器、指向第 n 個元素的迭代器、結束迭代器,也可以傳入一個比較函數來指定排序規則。函數無返回值。
- 要求 :容器需提供隨機訪問迭代器。
2.3.2 代碼示例
2.4 拷貝與替換算法
2.4.1 概述
# STL 拷貝與替換算法詳解
## 一、拷貝算法
### 1. std::copy
- 特點 :將一個序列中的元素復制到另一個序列中,不改變源序列中的元素,適用于序列元素的復制。
- 底層原理 :使用迭代器遍歷源序列,將每個元素復制到目標序列中。
- 分類 :基本拷貝算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入源序列的起始迭代器、結束迭代器,以及目標序列的起始迭代器。返回指向目標序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :源序列需提供輸入迭代器,目標序列需提供輸出迭代器。### 2. std::copy_n
- 特點 :將源序列中的前 n 個元素復制到目標序列中,適用于部分元素的復制。
- 底層原理 :使用迭代器遍歷源序列的前 n 個元素,將每個元素復制到目標序列中。
- 分類 :部分拷貝算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入源序列的起始迭代器、元素數量 n 以及目標序列的起始迭代器。返回指向目標序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :源序列需提供輸入迭代器,目標序列需提供輸出迭代器。## 二、替換算法
### 1. std::replace
- 特點 :將序列中的所有等于指定值的元素替換為另一個值,適用于批量替換元素。
- 底層原理 :使用迭代器遍歷序列,將所有等于指定值的元素替換為另一個值。
- 分類 :基本替換算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、結束迭代器、要被替換的值以及替換后的值。函數無返回值。
- 要求 :序列需提供前向迭代器。### 2. std::replace_if
- 特點 :將序列中所有滿足指定謂詞條件的元素替換為另一個值,可根據自定義條件進行替換。
- 底層原理 :使用迭代器遍歷序列,對每個元素調用謂詞函數,將滿足條件的元素替換為另一個值。
- 分類 :條件替換算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、結束迭代器、一個一元謂詞函數以及替換后的值。函數無返回值。
- 要求 :序列需提供前向迭代器,謂詞函數必須是一元函數。
2.4.2 代碼示例
2.5 算術生成算法
2.5.1 概述
# STL 算術生成算法詳解
## 一、求和算法
### 1. std::accumulate
- 特點 :對序列中的元素進行累加操作,也可以自定義二元操作進行元素的累積計算。適用于計算序列元素的總和或其他累積結果。
- 底層原理 :使用迭代器遍歷序列,將初始值與序列中的元素依次進行二元操作,最終得到累積結果。
- 分類 :基本求和算法。
- 使用方法 :包含 <numeric> 頭文件,調用時傳入序列的起始迭代器、結束迭代器以及初始值,也可以傳入一個自定義的二元操作函數。返回累積結果。
- 要求 :序列需提供輸入迭代器,二元操作函數必須是二元函數。### 2. std::partial_sum
- 特點 :計算序列中元素的部分和,將結果存儲在另一個序列中。可以自定義二元操作進行部分累積計算。
- 底層原理 :使用迭代器遍歷序列,依次計算并存儲部分和,每一步的結果是當前元素與之前所有元素的累積和(或自定義操作結果)。
- 分類 :部分求和算法。
- 使用方法 :包含 <numeric> 頭文件,調用時傳入輸入序列的起始迭代器、結束迭代器以及輸出序列的起始迭代器,也可以傳入一個自定義的二元操作函數。返回輸出序列的結束迭代器。
- 要求 :輸入序列需提供輸入迭代器,輸出序列需提供輸出迭代器,二元操作函數必須是二元函數。### 3. std::adjacent_difference
- 特點 :計算序列中相鄰元素的差值(或自定義二元操作結果),將結果存儲在另一個序列中。
- 底層原理 :使用迭代器遍歷序列,計算相鄰元素的差值(或自定義操作結果)并存儲在輸出序列中。
- 分類 :相鄰元素操作算法。
- 使用方法 :包含 <numeric> 頭文件,調用時傳入輸入序列的起始迭代器、結束迭代器以及輸出序列的起始迭代器,也可以傳入一個自定義的二元操作函數。返回輸出序列的結束迭代器。
- 要求 :輸入序列需提供輸入迭代器,輸出序列需提供輸出迭代器,二元操作函數必須是二元函數。### 4. std::inner_product
- 特點 :計算兩個序列的內積(對應元素相乘后累加),也可以自定義二元操作進行計算。
- 底層原理 :使用迭代器同時遍歷兩個序列,將對應元素進行自定義操作(默認是相乘),然后將結果進行累積操作(默認是相加)。
- 分類 :序列內積算法。
- 使用方法 :包含 <numeric> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,第二個序列的起始迭代器,初始值,還可以傳入兩個自定義的二元操作函數(分別用于元素操作和累積操作)。返回累積結果。
- 要求 :序列需提供輸入迭代器,自定義的二元操作函數必須是二元函數。## 二、填充算法
### 1. std::fill
- 特點 :將序列中的所有元素設置為指定的值,適用于批量初始化序列元素。
- 底層原理 :使用迭代器遍歷序列,將每個元素賦值為指定的值。
- 分類 :基本填充算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、結束迭代器以及要填充的值。函數無返回值。
- 要求 :序列需提供前向迭代器。### 2. std::fill_n
- 特點 :將序列中的前 n 個元素設置為指定的值,適用于部分初始化序列元素。
- 底層原理 :使用迭代器遍歷序列的前 n 個元素,將每個元素賦值為指定的值。
- 分類 :部分填充算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、元素數量 n 以及要填充的值。函數無返回值。
- 要求 :序列需提供前向迭代器。### 3. std::generate
- 特點 :將序列中的每個元素設置為一個生成器函數的返回值,適用于批量生成有規律的元素。
- 底層原理 :使用迭代器遍歷序列,對每個元素調用生成器函數,并將返回值賦值給該元素。
- 分類 :生成填充算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、結束迭代器以及一個生成器函數。函數無返回值。
- 要求 :序列需提供前向迭代器,生成器函數必須是無參數的可調用對象。### 4. std::generate_n
- 特點 :將序列中的前 n 個元素設置為一個生成器函數的返回值,適用于部分生成有規律的元素。
- 底層原理 :使用迭代器遍歷序列的前 n 個元素,對每個元素調用生成器函數,并將返回值賦值給該元素。
- 分類 :部分生成填充算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入序列的起始迭代器、元素數量 n 以及一個生成器函數。函數無返回值。
- 要求 :序列需提供前向迭代器,生成器函數必須是無參數的可調用對象。## 三、隨機數生成算法
### 1. std::iota
- 特點 :將序列中的元素依次設置為從指定值開始的連續遞增的值,適用于生成連續數值序列。
- 底層原理 :使用迭代器遍歷序列,將每個元素依次賦值為從指定值開始的連續遞增的值。
- 分類 :序列生成算法。
- 使用方法 :包含 <numeric> 頭文件,調用時傳入序列的起始迭代器、結束迭代器以及起始值。函數無返回值。
- 要求 :序列需提供前向迭代器。## 四、其他算術相關算法
### 1. std::sample
- 特點 :從輸入序列中隨機選取指定數量的元素,存儲到輸出序列中。適用于隨機抽樣場景。
- 底層原理 :使用隨機數生成器,通過蓄水池抽樣算法等方式從輸入序列中隨機選取元素。
- 分類 :隨機抽樣算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入輸入序列的起始迭代器、結束迭代器,輸出序列的起始迭代器、結束迭代器,抽樣數量以及一個隨機數生成器。返回指向輸出序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :輸入序列需提供輸入迭代器,輸出序列需提供輸出迭代器,隨機數生成器需滿足相應要求。
2.5.2 代碼示例
2.6 集合算法
2.6.1 概述
# STL 集合算法詳解
## 一、集合合并算法
### 1. std::merge
- 特點 :將兩個有序序列合并為一個有序序列,不改變原序列中的元素,適用于合并有序序列。
- 底層原理 :使用迭代器遍歷兩個有序序列,比較元素大小,將較小的元素依次放入目標序列中。
- 分類 :基本合并算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,第二個序列的起始迭代器、結束迭代器,以及目標序列的起始迭代器,也可以傳入一個比較函數來指定排序規則。返回指向目標序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :兩個原序列需提供輸入迭代器,目標序列需提供輸出迭代器,且兩個原序列必須是有序的。## 二、集合查找算法
### 1. std::includes
- 特點 :判斷一個有序序列是否包含另一個有序序列中的所有元素,適用于判斷集合的包含關系。
- 底層原理 :使用迭代器遍歷兩個有序序列,比較元素大小,判斷是否所有元素都被包含。
- 分類 :集合包含判斷算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,第二個序列的起始迭代器、結束迭代器,也可以傳入一個比較函數來指定排序規則。返回一個布爾值,表示第一個序列是否包含第二個序列中的所有元素。
- 要求 :兩個序列需提供輸入迭代器,且兩個序列必須是有序的。## 三、集合運算算法
### 1. std::set_difference
- 特點 :計算兩個有序序列的差集,即存在于第一個序列但不存在于第二個序列中的元素組成的集合,適用于計算集合的差集。
- 底層原理 :使用迭代器遍歷兩個有序序列,比較元素大小,將只存在于第一個序列中的元素放入目標序列中。
- 分類 :集合差集算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,第二個序列的起始迭代器、結束迭代器,以及目標序列的起始迭代器,也可以傳入一個比較函數來指定排序規則。返回指向目標序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :兩個原序列需提供輸入迭代器,目標序列需提供輸出迭代器,且兩個原序列必須是有序的。### 2. std::set_intersection
- 特點 :計算兩個有序序列的交集,即同時存在于兩個序列中的元素組成的集合,適用于計算集合的交集。
- 底層原理 :使用迭代器遍歷兩個有序序列,比較元素大小,將同時存在于兩個序列中的元素放入目標序列中。
- 分類 :集合交集算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,第二個序列的起始迭代器、結束迭代器,以及目標序列的起始迭代器,也可以傳入一個比較函數來指定排序規則。返回指向目標序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :兩個原序列需提供輸入迭代器,目標序列需提供輸出迭代器,且兩個原序列必須是有序的。### 3. std::set_symmetric_difference
- 特點 :計算兩個有序序列的對稱差集,即存在于第一個序列但不存在于第二個序列,或者存在于第二個序列但不存在于第一個序列中的元素組成的集合,適用于計算集合的對稱差集。
- 底層原理 :使用迭代器遍歷兩個有序序列,比較元素大小,將只存在于一個序列中的元素放入目標序列中。
- 分類 :集合對稱差集算法。
- 使用方法 :包含 <algorithm> 頭文件,調用時傳入第一個序列的起始迭代器、結束迭代器,第二個序列的起始迭代器、結束迭代器,以及目標序列的起始迭代器,也可以傳入一個比較函數來指定排序規則。返回指向目標序列中最后一個被復制元素的下一個位置的迭代器。
- 要求 :兩個原序列需提供輸入迭代器,目標序列需提供輸出迭代器,且兩個原序列必須是有序的。
2.6.2 代碼示例
3. 迭代器
1. 迭代器是什么?為什么需要它?
是什么??迭代器是一個對象(或者行為類似指針的對象),它指向容器中的一個元素(或尾后位置)。你可以把它想象成一個智能指針,封裝了對容器內部元素的訪問細節。
為什么需要?
統一訪問接口:?STL的核心思想是泛型編程。算法(如?
sort
,?find
,?copy
)需要能處理任何容器。如果沒有迭代器,每個算法都要為?vector
,?list
,?map
?等寫不同的版本。迭代器提供了訪問容器元素的標準方法,算法只需要操作迭代器,就能作用于不同的容器。遍歷容器:?這是迭代器最基本、最常用的功能。無論容器內部是連續內存(
vector
)、鏈表(list
)還是樹(map
),你都可以用相似的?++it
,?*it
?語法遍歷所有元素。訪問元素:?通過解引用迭代器(
*it
),你可以讀取或修改它指向的元素的值。連接容器與算法:?幾乎所有STL算法都通過迭代器范圍?
[begin, end)
?來操作容器。begin
?指向第一個元素,end
?指向最后一個元素之后的位置(尾后迭代器)。這個左閉右開區間?[begin, end)
?是STL的標準約定。2. 迭代器的核心操作(基礎語法)
迭代器的行為模仿指針,支持以下基本操作:
*it
:解引用。獲取迭代器?it
?指向元素的引用。可以讀值也可以賦值修改值。
it->member
: 如果迭代器指向的是一個結構體或類對象,可以用?->
?直接訪問其成員(等價于?(*it).member
)。
++it
?/?it++
:前綴/后綴遞增。將迭代器移動到指向容器中的下一個元素。(最常見操作)
--it
?/?it--
:前綴/后綴遞減(僅適用于雙向和隨機訪問迭代器)。將迭代器移動到指向容器中的上一個元素。
it1 == it2
?/?it1 != it2
:比較。判斷兩個迭代器是否指向同一個元素(或是否都是尾后迭代器)。通常用?!=
?作為循環結束條件。
=
:賦值。將一個迭代器的值賦給另一個迭代器(讓它們指向同一個位置)。3. 如何獲取迭代器?
每個STL容器都提供了成員函數來獲取迭代器:
.begin()
: 返回指向容器第一個元素的迭代器。
.end()
: 返回指向容器最后一個元素之后位置的迭代器(尾后迭代器)。重要!end()
?指向的不是最后一個元素本身!?它標志著容器的結束。
.cbegin()
?/?.cend()
: 返回?const
?迭代器。通過它們只能讀取元素,不能修改元素(類似指向常量的指針?const T*
)。
.rbegin()
?/?.rend()
: 返回反向迭代器。rbegin()
?指向最后一個元素,rend()
?指向第一個元素之前的位置。++
?操作會使反向迭代器向前(即容器順序的逆序)移動。
.crbegin()
?/?.crend()
: 返回?const
?反向迭代器。4. 迭代器分類(類別/能力)
不是所有迭代器的能力都一樣!STL根據迭代器支持的操作,將它們分為5類(能力從弱到強):
輸入迭代器 (Input Iterator):
能力:?只能單向向前移動 (
++it
),只能讀取元素 (*it
),且只能讀取一次(就像一個只讀的單向數據流,如從鍵盤讀取)。不支持:?寫操作、遞減(
--
)、隨機訪問。示例:?讀取文件流 (
istream_iterator
)。輸出迭代器 (Output Iterator):
能力:?只能單向向前移動 (
++it
),只能寫入元素 (*it = value
),且通常只能寫入一次(就像一個只寫的單向數據流,如寫入屏幕)。不支持:?讀操作(解引用只能出現在賦值左邊)、遞減(
--
)、隨機訪問。示例:?寫入文件流 (
ostream_iterator
)。前向迭代器 (Forward Iterator):
能力:?單向向前移動 (
++it
),可以多次讀寫同一個元素 (*it
)。它組合了輸入和輸出迭代器的功能,并且支持多次讀寫。不支持:?遞減(
--
)、隨機訪問。示例:?
forward_list
?(單向鏈表) 的迭代器。雙向迭代器 (Bidirectional Iterator):
能力:?在前向迭代器基礎上,增加了向后移動 (
--it
?/?it--
) 的能力。不支持:?隨機訪問(不能瞬間跳到任意位置)。
示例:?
list
,?set
,?multiset
,?map
,?multimap
,?deque
?的迭代器。deque
?雖然支持隨機訪問,但其迭代器通常被歸類為雙向以滿足最低要求(實際實現可能更強)。隨機訪問迭代器 (Random Access Iterator):
能力:?在雙向迭代器基礎上,提供了完整的指針算術運算能力,就像操作普通數組指針一樣:
瞬間跳到任意位置:
it + n
,?it - n
,?it += n
,?it -= n
計算距離:
it1 - it2
下標訪問:
it[n]
?(等價于?*(it + n)
)比較大小:
it1 < it2
,?it1 > it2
,?it1 <= it2
,?it1 >= it2
示例:?
vector
,?deque
,?array
,?string
?的迭代器。原生數組指針也是隨機訪問迭代器。為什么分類重要?
算法選擇:?STL算法會指定它需要什么類別的迭代器。例如:
sort
?需要隨機訪問迭代器(因為它需要快速跳到中間元素)。
list::sort
?是?list
?的成員函數,它只需要雙向迭代器(鏈表不能隨機訪問)。
find
?只需要輸入迭代器(它順序查找)。效率提示:?隨機訪問迭代器支持的操作通常是最快的(O(1)),而前向或雙向迭代器的移動是線性的(O(n))。
5. 迭代器失效:一個極其重要的陷阱!
問題:?當你對容器進行修改操作(如插入、刪除)時,指向容器元素的迭代器可能會變得無效!繼續使用這些失效的迭代器會導致未定義行為(程序崩潰、數據錯誤等)。
原因:?修改操作可能改變容器的內部結構:
vector
/string
: 在中間或頭部?insert
/erase
,或者?push_back
?導致內存重分配 (reallocation
),會使所有指向該容器元素的迭代器、引用和指針失效!重分配后,即使尾后迭代器?.end()
?也失效。
deque
: 在中間?insert
/erase
?會使所有迭代器失效。在頭尾?push
/pop
?通常只使指向被操作元素的迭代器失效(但?push
?可能導致內存塊分配,使所有迭代器失效,具體實現相關)。
list
/forward_list
/關聯容器(set
,?map
等):?insert
?操作不會使任何現有迭代器失效。erase
?操作僅使指向被刪除元素的迭代器失效。指向其他元素的迭代器仍然有效。如何避免?
修改后更新:?在對容器進行修改操作(尤其是?
insert
,?erase
,?push_back
/pop_back
?可能引發重分配時)之后,如果需要繼續使用迭代器,重新獲取迭代器(如?it = vec.begin();
)。使用返回值:?
erase
?操作通常會返回一個迭代器,指向被刪除元素之后的位置。利用這個返回值更新你的循環迭代器:for (auto it = myList.begin(); it != myList.end(); /* 這里不寫 ++it */) {if (condition(*it)) {it = myList.erase(it); // erase 返回下一個有效迭代器} else {++it;} }
警惕循環內修改:?在遍歷容器(特別是?
vector
,?deque
,?string
)的循環中修改容器(插入/刪除)要格外小心,很容易導致迭代器失效。優先考慮使用上述?erase
?返回值的模式。使用算法:?盡可能使用?
remove_if
?配合?erase
?(擦除-移除慣用法) 來刪除元素,或使用 C++11 的范圍?for
?循環(但其內部也是迭代器,修改容器同樣會導致迭代器失效!范圍?for
?中一般不應修改容器結構)。6. 迭代器與范圍?
for
?循環 (C++11)C++11 引入的范圍?
for
?循環 (for (auto element : container)
) 是遍歷容器的簡潔語法糖。底層就是使用迭代器實現的!?編譯器會自動將其展開為類似下面的代碼:{auto && __range = container; // 獲取容器引用auto __begin = __range.begin(); // 獲取起始迭代器auto __end = __range.end(); // 獲取尾后迭代器for (; __begin != __end; ++__begin) {auto element = *__begin; // 解引用迭代器得到元素 (注意這里是拷貝!)// 循環體} }
優點:?語法極其簡潔清晰,不易出錯(只要不在循環體內修改容器結構導致迭代器失效)。
注意:
element
?默認是容器元素的拷貝。如果想避免拷貝,使用引用?for (auto &element : container)
。如果元素不可修改,使用?const
?引用?for (const auto &element : container)
。在范圍?
for
?循環體內,絕對不要對正在遍歷的容器進行添加或刪除元素的操作!?這會直接導致底層迭代器失效,引發未定義行為。如果需要修改容器結構,請使用顯式的迭代器循環和上述?erase
?返回值的技巧。7. 總結:
迭代器是通用指針:?它是訪問和遍歷所有STL容器的標準方式。
核心操作:?
*it
,?it->member
,?++it
,?--it
?(部分),?it1 == it2
,?it1 != it2
。獲取方式:?
.begin()
,?.end()
,?.cbegin()
,?.cend()
,?.rbegin()
,?.rend()
。分類重要:?理解5類迭代器(輸入、輸出、前向、雙向、隨機訪問)及其能力差異,這決定了哪些算法能用。
失效陷阱:?時刻警惕修改容器(插入、刪除、可能導致重分配的
push_back
)導致的迭代器失效!這是STL編程中最常見的錯誤來源之一。修改后及時重新獲取迭代器或使用?erase
?的返回值。優先用范圍?
for
:?對于簡單的遍歷,優先使用范圍?for
?循環,語法簡潔不易錯(但同樣要避免在循環內修改容器結構)。
auto
?是好幫手:?聲明迭代器時多用?auto
?(如?auto it = vec.begin();
),省去冗長的類型書寫。比較用?
!=
:?循環條件判斷一般用?it != container.end()
,而不是?<
(只有隨機訪問迭代器才支持?<
)。實踐出真知:?多寫代碼,嘗試用迭代器遍歷不同的容器 (
vector
,?list
,?map
),使用不同的算法 (find
,?sort
?- 注意?sort
?需要隨機訪問),體會迭代器的用法和失效的場景。
4. 仿函數
5. 適配器
1.適配器概述
使用場景:當一個函數有三個參數,你想傳入四個參數,這時候,就可以使用適配器
2. 適配器
代碼示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;// 修改函數名,避免與標準庫函數沖突
bool isEqual(int a, int b)
{return a == b;
}int main()
{vector<int> v = {10, 20, 30, 40, 50};// 正確使用 bind 綁定器,將二元謂詞轉換為一元謂詞auto it = bind(isEqual, placeholders::_1, 10);// 修改變量名,避免命名沖突auto result = find_if(v.begin(), v.end(), it);if (result != v.end()){cout << "找到值了" << endl;}else{// 修正拼寫錯誤cout << "無值" << endl;}return 0;
}
3. 成員函數適配器
代碼示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>// 重載小括號的類,被稱為函數對象(仿函數)
class Demo
{
public:int id;Demo(int id = 0) : id(id){this->id = id;}void PrintData(int value){std::cout << this->id * value << std::endl;}
};int main()
{std::vector<Demo> v;v.push_back(Demo(1));v.push_back(Demo(2));v.push_back(Demo(3));v.push_back(Demo(4));v.push_back(Demo(5));auto res = std::bind(Demo::PrintData, std::placeholders::_1, 10);for_each(v.begin(), v.end(), res);return 0;
}
4.?函數對象適配器
代碼示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>// 重載小括號的類,被稱為函數對象(仿函數)
class Demo
{
public:void operator()(int value, int num) const{value *= num; // value = value * num;std::cout << value << "\t";}
};int main()
{std::vector<int> v = {10, 20, 30, 40, 50};// 修正語法錯誤,添加分號auto res = std::bind(Demo(), std::placeholders::_1, 10);std::for_each(v.begin(), v.end(), res);std::cout << std::endl;return 0;
}
6. 空間配置器(無)
三. Lanmda(c++11新特性)
1. 概述
Lambda表達式是現代C++在C ++ 11和更高版本中的一個新的語法糖 ,在C++11、C++14、C++17和C++20中Lambda表達的內容還在不斷更新。 lambda表達式(也稱為lambda函數)是在調用或作為函數參數傳遞的位置處定義匿名函數對象的便捷方法。通常,lambda用于封裝傳遞給算法或異步方法的幾行代碼 。本文主要介紹Lambda的工作原理以及使用方法。
2. 捕獲列表
捕獲列表用于指定拉姆達表達式可以訪問的外部變量。捕獲列表有以下幾種形式:
[]:不捕獲任何變量。
[var]:按值捕獲變量var。
[&var]:按引用捕獲變量var。
[=]:按值捕獲所有外部變量。
[&]:按引用捕獲所有外部變量。
[this]:按值捕獲當前的this指針。
5. 代碼示例:?
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;void test()
{// lambda表達式,其實就是匿函數/*[](){};[]: 捕獲列表,空的即為不捕獲任何變量[]: 捕獲外部變量,可以捕獲局部變量,也可以捕獲全局變量,也可以捕獲this指針[=]: 捕獲外部變量,以值的方式捕獲,不可以修改外部變量[&]: 捕獲外部變量,以引用的方式捕獲,可以修改外部變量外部的定義為lambda表達式以外的():參數列表{}: 函數體;: 函數結尾*/auto add = [](int a, int b) -> int{return a + b;};cout << add(10, 20) << endl;
}//& 捕獲外部變量,以引用的方式捕獲,可以修改外部變量
void test1()
{int a = 10;int b = 20;auto add = [&](int x = 50, int y = 100) -> int{a = 100;b = 200;return x + y;};cout << add() << endl;
}//= 捕獲外部變量,以值的方式捕獲,不可以修改外部變量
void test3()
{int a = 10;int b = 20;auto add = [=](int x = 50, int y = 100) -> int{// a = 100; // 錯誤,不能修改外部變量// b = 200; // 錯誤,不能修改外部變量return x + y;};
}// 使用lambda遍歷容器
void test4()
{vector<int> v = {10, 20, 30, 40, 50};// 使用lambda表達式,遍歷容器for_each(v.begin(), v.end(), [](int data) -> void{ cout << data << "\t"; });
}// 使用lambda表達式利用transform把值賦予v2
void test5()
{vector<int> v = {10, 20, 30, 40, 50};vector<int> v2;// 必須要先resize,否則會報錯,resize作用是為v2開辟空間v2.resize(v.size());// 使用lambda表達式,遍歷容器transform(v.begin(), v.end(), v2.begin(), [](int value) -> int{ return value; });for_each(v2.begin(), v2.end(), [](int value) -> void{ cout << value << "\t"; });
}int main(int argc, char const *argv[])
{test5();return 0;
}