vector 的用法
在 C++ 中,std::vector
是一個動態陣列,它可以在執行時調整大小,std::vector
是 C++ 標準模板庫 (STL) 中的一個重要容器類。
基本用法
在使用 std::vector
之前,需要包含標頭檔案 <vector>
。
#include <iostream>
#include <vector>
當然,現在包含萬能頭 <bits/stdc++.h> 檔案也是可以的。
1. 建立和初始化 std::vector
可以使用不同的方式來建立和初始化 std::vector
:
int main() {
// 建立一個空的 vector
std::vector<int> vec1;
// 使用初始大小(預設值為0)
std::vector<int> vec2(5); // 包含5個預設值(通常是0)
// 使用初始大小和指定值
std::vector<int> vec3(5, 10); // 包含5個值為10的元素
// 使用初始化列表
std::vector<int> vec4 = {1, 2, 3, 4, 5};
return 0;
}
2. 新增和刪除元素
std::vector
提供多種方法來新增和刪除元素:
int main() {
std::vector<int> vec;
// 新增元素
vec.push_back(1);
vec.push_back(2);
vec.push_back(3); // 現在 vec 包含 {1, 2, 3}
// 在指定位置插入元素,
vec.insert(vec.begin() + 1, 4); // 在索引1插入4,現在 vec 為 {1, 4, 2, 3}
// 注意:插入元素是O(N)的時間複雜度,因為在插入之前需要移動該位置及右邊的所有元素。
// 刪除元素
vec.pop_back(); // 刪除最後一個元素,現在 vec 為 {1, 4, 2}
vec.erase(vec.begin() + 1); // 刪除索引1的元素,現在 vec 為 {1, 2}
//刪除元素也是$O(n)$的時間複雜度
return 0;
}
3. 訪問元素
可以使用下標運算子或迭代器訪問 std::vector
中的元素:
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用下標運算子訪問元素
std::cout << "First element: " << vec[0] << std::endl; // 輸出: First element: 1
// 使用 `.at()` 方法訪問元素(帶邊界檢查)
std::cout << "Second element: " << vec.at(1) << std::endl; // 輸出: Second element: 2
// 使用迭代器訪問元素
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " "; // 輸出: 1 2 3 4 5
}
std::cout << std::endl;
return 0;
}
4. 常用成員函式
(1)、 resize(size_type count)
:更改 vector
的大小。
resize 用於調整 vector 的大小。
如果新的大小大於當前大小,vector 將會增加元素以達到這個新大小,新增的元素會被初始化為預設值。
如果新的大小小於當前大小,vector 將會刪除多餘的元素。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3};
// 調整大小為 5,新增的元素為 0
vec.resize(5);
std::cout << "After resize to 5: ";
for (int num : vec) {
std::cout << num << " "; // 輸出: 1 2 3 0 0
}
std::cout << std::endl;
// 調整大小為 2,丟棄後面的元素
vec.resize(2);
std::cout << "After resize to 2: ";
for (int num : vec) {
std::cout << num << " "; // 輸出: 1 2
}
std::cout << std::endl;
return 0;
}
(2)、 capacity()
:返回當前分配的容量。
capacity 返回 vector 當前可以容納的元素數量,而不需要重新分配記憶體。它可能大於或等於 vector 的大小,表示記憶體的預分配。
#include <bits/stdc++.h>
int main() {
std::vector<int> vec;
// 新增一些元素
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
std::cout << "Size: " << vec.size() << std::endl; // 輸出: 3
std::cout << "Capacity: " << vec.capacity() << std::endl; // 輸出可能是 4 或更大
// 繼續新增元素,超出當前容量
vec.push_back(4);
std::cout << "Size after adding more: " << vec.size() << std::endl; // 輸出: 4
std::cout << "Capacity after adding more: " << vec.capacity() << std::endl; // 輸出可能是 4 或更大
return 0;
}
(3)、clear()
:移除所有元素。
清空 vector
中的所有元素,使得大小變為 0,但不會改變 capacity
。
(4)、empty()
:檢查 vector
是否為空。
判斷 vector
是否為空。如果 vector
的大小為 0,返回 true
;否則返回 false
。
(5)、size()
:返回當前元素數量。
示例
```cpp
#include <iostream>
#include <vector>
int main() {
// 建立一個 vector
std::vector<int> vec;
// 檢查 vector 是否為空
if (vec.empty()) {
std::cout << "Vector is empty." << std::endl; // 輸出: Vector is empty.
}
// 向 vector 新增一些元素
vec.push_back(5);
vec.push_back(10);
vec.push_back(15);
// 檢查 vector 的狀態
std::cout << "Size: " << vec.size() << std::endl; // 輸出: Size: 3
std::cout << "Capacity: " << vec.capacity() << std::endl; // 可能輸出: Capacity: 4 或更大
std::cout << "Is vector empty? " << (vec.empty() ? "Yes" : "No") << std::endl; // 輸出: No
// 清空 vector
vec.clear();
std::cout << "After clear -> Size: " << vec.size() << std::endl; // 輸出: After clear -> Size: 0
std::cout << "Is vector empty? " << (vec.empty() ? "Yes" : "No") << std::endl; // 輸出: Yes
// 再次檢查容量
std::cout << "Capacity after clear: " << vec.capacity() << std::endl; // 輸出容量可能保持不變
return 0;
}
```
### 輸出結果
執行以上程式碼,將會得到以下輸出(具體的 `capacity` 值可能因編譯器和環境而異):
```
Vector is empty.
Size: 3
Capacity: 4
Is vector empty? No
After clear -> Size: 0
Is vector empty? Yes
Capacity after clear: 4
```
- 在開始時,
vector
為空,使用empty()
返回true
。 - 新增元素後,
empty()
返回false
,且size()
返回當前元素數量。 - 呼叫
clear()
後,vector
中的所有元素被移除,size()
變為 0,empty()
返回true
,但capacity
可能不變。
小結
std::vector
是 C++ 中非常有用的容器,適合儲存不定數量的元素。它提供了靈活的操作和高效的訪問方式,適合動態處理資料。
它具有如下特點:
- 支援陣列下標
- 可以動態調整大小
- 比陣列稍慢
- 有許多自定義函式(方法)可以使用
- 支援插入和刪除操作,但如果插入和刪除的位置不在末尾,則比較慢
C++ 中list的用法
在 C++ 中,std::list
是一個雙向連結串列容器,它提供了快速的插入和刪除操作,適合需要頻繁插入和刪除元素的場景。與 std::vector
不同,std::list
的元素在記憶體中不是連續儲存的,因此訪問元素的速度相對較慢,但在對元素進行插入和刪除時表現得更有效率。
基本用法
在使用 std::list
之前,需要包含標頭檔案 <list>
。
#include <iostream>
#include <list>
1. 建立和初始化 std::list
可以使用不同的方式來建立和初始化 std::list
:
int main() {
// 建立一個空的 list
std::list<int> myList;
// 使用初始大小和指定值
std::list<int> myList2(5, 10); // 將包含5個值為10的元素
// 使用初始化列表
std::list<int> myList3 = {1, 2, 3, 4, 5};
return 0;
}
2. 新增和刪除元素
std::list
提供多種方法來新增和刪除元素:
push_back(); //在末尾插入
push_front(); //在開頭插入
pop_back(); //在末尾刪除
pop_front(); //在開頭刪除
remove(a); //刪除值為a的元素
示例:
int main() {
std::list<int> myList;
// 新增元素
myList.push_back(1); // 在末尾新增
myList.push_back(2);
myList.push_front(0); // 在開頭新增
// 現在 myList 為 {0, 1, 2}
// 刪除元素
myList.pop_back(); // 刪除末尾元素,現在 myList 為 {0, 1}
myList.pop_front(); // 刪除開頭元素,現在 myList 為 {1}
myList.remove(1); // 刪除值為1的元素,現在 myList 為空
return 0;
}
3. 訪問元素
(1)、std::list
不支援隨機訪問(如下標運算子),但可以使用迭代器訪問元素:
int main() {
std::list<int> myList = {1, 2, 3, 4, 5};
// 使用迭代器訪問元素
for (auto it = myList.begin(); it != myList.end(); ++it) {
std::cout << *it << " "; // 輸出: 1 2 3 4 5
}
std::cout << std::endl;
return 0;
}
(2)、迭代器也支援自減運算, 可以從後往前訪問連結串列,但是要注意初始值不能是end()
,
因為end()
表示的是連結串列尾部元素的下一個位置,那個位置是沒有元素的**
#include <iostream>
#include <list>
int main() {
// 建立一個 list,並新增一些元素
std::list<int> myList = {1, 2, 3, 4, 5};
// 使用迭代器從 list 的末尾迭代到開頭
for (auto p = myList.end(); p != myList.begin();) {
--p; // 先將迭代器減少到最後一個有效元素
std::cout << *p << " "; // 輸出: 5 4 3 2 1
}
std::cout << std::endl;
return 0;
}
(3)、 反向迭代器
可以使用 std::list 的反向迭代器 rbegin() 和 rend() 進行反向訪問。
#include <iostream>
#include <list>
int main() {
// 建立一個 list,並新增一些元素
std::list<int> myList = {1, 2, 3, 4, 5};
// 使用 auto 和反向迭代器反向訪問 list
std::cout << "Elements in the list in reverse order:" << std::endl;
for (auto it = myList.rbegin(); it != myList.rend(); ++it) {
std::cout << *it << " "; // 輸出: 5 4 3 2 1
}
std::cout << std::endl;
return 0;
}
4. 常用成員函式
size()
:返回當前元素數量。empty()
:檢查list
是否為空。clear()
:移除所有元素。sort()
:對元素進行排序。reverse()
:反轉列表。
int main() {
std::list<int> myList = {5, 2, 3, 1, 4};
// 排序列表
myList.sort(); // 現在 myList 為 {1, 2, 3, 4, 5}
// 反轉列表
myList.reverse(); // 現在 myList 為 {5, 4, 3, 2, 1}
std::cout << "Size: " << myList.size() << std::endl; // 輸出: Size: 5
// 清空列表
myList.clear();
std::cout << "Size after clear: " << myList.size() << std::endl; // 輸出: Size after clear: 0
if (myList.empty()) {
std::cout << "List is empty." << std::endl;
}
return 0;
}
小結
std::list
是 C++ 中非常有用的容器,適合需要頻繁插入和刪除的場景。它提供了靈活的操作,但由於不支援隨機訪問,相較於 std::vector
在訪問元素時可能會慢一些。瞭解其基本用法和成員函式,能夠幫助更好地管理動態資料結構。
三、 C++ queue的用法
在 C++ 中,std::queue
是一個適用於先進先出(FIFO)原則的容器介面卡,它通常用於處理資料流,確保元素以新增的順序被訪問。std::queue
只能在隊尾新增元素(enqueue),並在隊頭刪除元素(dequeue)。
要使用 std::queue
,需要包含標頭檔案 <queue>
。
基本用法
#include <iostream>
#include <queue>
int main() {
// 建立一個空的 queue
std::queue<int> myQueue;
// 向佇列中新增元素(enqueue)
myQueue.push(1);
myQueue.push(2);
myQueue.push(3); // 現在佇列為 {1, 2, 3}
// 訪問佇列的頭元素
std::cout << "Front element: " << myQueue.front() << std::endl; // 輸出: 1
// 刪除佇列的頭元素(dequeue)
myQueue.pop(); // 現在佇列為 {2, 3}
// 再次訪問頭元素
std::cout << "Front element after pop: " << myQueue.front() << std::endl; // 輸出: 2
// 檢查佇列是否為空
if (!myQueue.empty()) {
std::cout << "Queue size: " << myQueue.size() << std::endl; // 輸出: 2
}
// 清空佇列
while (!myQueue.empty()) {
myQueue.pop(); // 逐步刪除元素
}
std::cout << "Queue size after clearing: " << myQueue.size() << std::endl; // 輸出: 0
return 0;
}
常用成員函式
push(const T& val)
:在佇列的末尾新增一個元素。pop()
:刪除佇列的頭元素。front()
:訪問佇列的頭元素。back()
:訪問佇列的尾元素。empty()
:檢查佇列是否為空。size()
:返回佇列中元素的數量。
實際應用示例
#include <iostream>
#include <queue>
int main() {
std::queue<std::string> taskQueue;
// 新增任務到佇列中
taskQueue.push("Task 1");
taskQueue.push("Task 2");
taskQueue.push("Task 3");
// 執行佇列中的任務
while (!taskQueue.empty()) {
std::cout << "Processing: " << taskQueue.front() << std::endl; // 訪問頭元素
taskQueue.pop(); // 執行完任務後移除
}
return 0;
}
優先佇列的用法
在 C++ 中,std::priority_queue
是一種基於堆(heap)實現的容器介面卡,它允許我們以優先順序的方式訪問元素。std::priority_queue
可以用於實現最大堆或最小堆,其預設行為是構建最大堆,確保最大的元素總是在佇列的頂部。
要使用 std::priority_queue
,需要包含標頭檔案 <queue>
。
1、基本用法
(1)、預設是大根堆,
std::priority_queue<int> myque1; //定義整數大根堆
std::priority_queue<double> myque2; // 定義double型別的大根堆
大根堆例項:
#include <iostream>
#include <queue>
int main() {
// 建立一個空的優先佇列
std::priority_queue<int> pq;
// 新增元素(預設是最大堆)
pq.push(10);
pq.push(30);
pq.push(20);
// 輸出優先佇列的頂端元素(最大元素)
std::cout << "Top element: " << pq.top() << std::endl; // 輸出: 30
// 刪除頂端元素
pq.pop(); // 移除最大元素
std::cout << "Top element after pop: " << pq.top() << std::endl; // 輸出: 20
// 檢查優先佇列是否為空
if (!pq.empty()) {
std::cout << "Size of the priority queue: " << pq.size() << std::endl; // 輸出: 2
}
// 清空優先佇列
while (!pq.empty()) {
pq.pop(); // 逐步刪除元素
}
std::cout << "Size after clearing: " << pq.size() << std::endl; // 輸出: 0
return 0;
}
(2)、自定義優先順序
priority_queue<int, vector<int>, less<int>> myq1; //定義整數大根堆
priority_queue<int, vector<int>, greater<int>>; //定義整數小根堆
priority_queue<doulbe, vector<double>, greater<double>>; //定義double型別的小根堆
struct node{
int a;
bool operator < (const node &t) const{
return a > t.a;
}
};
std::priority_queue<node> myq; // a越小優先順序越高
小根堆示例:
#include <iostream>
#include <list>
#include <queue>
using namespace std;
struct node{
int a;
node(int t = 0) {a = t;}
bool operator < (const node &t) const{
return a > t.a;
}
};
int main() {
priority_queue<node> myq; // a越小優先順序越高
myq.push(node(5));
myq.push(node(3));
myq.push(node(9));
while(!myq.empty()){
cout << myq.top().a << ' ' ; //輸出3 5 9
myq.pop();
}
return 0;
}
常用成員函式
push(const T& value)
:在優先佇列中插入一個新元素。pop()
:刪除優先佇列中最高優先順序的元素(頂部元素)。top()
:訪問最高優先順序的元素。empty()
:檢查優先佇列是否為空。size()
:返回優先佇列中元素的數量。
map的使用
C++中的std::map
是一個關聯容器,用於儲存鍵值對(key-value pair)。這些鍵是唯一的,使用鍵可以快速查詢對應的值。std::map
通常實現為紅黑樹,以保持元素的有序性,使其支援對數時間複雜度的插入、刪除和查詢操作。
基本特性
- 鍵唯一:每個鍵只能出現一次。
- 有序性:元素按照鍵的順序排列。
- 鍵值對:儲存的元素為鍵值對,可以透過鍵來訪問值。
包含標頭檔案
在使用std::map
之前,需要包含 <map>
標頭檔案:
#include <map>
建立和初始化
可以使用花括號初始化,或者透過 insert
方法新增元素:
#include <iostream>
#include <map>
int main() {
// 建立一個空的 map
std::map<int, std::string> myMap;
// 使用 insert 新增元素
myMap.insert(std::make_pair(1, "Apple"));
myMap.insert(std::pair<int, std::string>(2, "Banana"));
// 使用花括號初始化
std::map<int, std::string> anotherMap{
{3, "Cherry"},
{4, "Date"}
};
return 0;
}
插入元素
可以使用 insert
方法或 []
運算子插入元素:
myMap[3] = "Orange"; // 使用 [] 運算子插入元素
訪問元素
可以使用 []
運算子或 at()
方法訪問元素:
std::cout << "Key 1: " << myMap[1] << std::endl; // 輸出: Apple
std::cout << "Key 2: " << myMap.at(2) << std::endl; // 輸出: Banana
注意,當使用 []
運算子訪問不存在的鍵時,會插入一個預設值(如空字串),而 at()
方法會丟擲異常。
刪除元素
可以使用 erase
方法刪除元素:
myMap.erase(2); // 刪除鍵為2的元素
查詢元素
使用 find
方法來查詢元素,返回一個迭代器。如果找到了元素,迭代器指向該元素;如果未找到,則指向 end()
:
auto it = myMap.find(1);
if (it != myMap.end()) {
std::cout << "Found: " << it->second << std::endl; // 輸出: Found: Apple
} else {
std::cout << "Not found!" << std::endl;
}
遍歷元素
可以使用範圍 for
迴圈或迭代器來遍歷 map
:
for (const auto &pair : myMap) {
std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
}
其他操作
- 大小:可以使用
size()
方法獲取元素數量。 - 空檢查:透過
empty()
方法檢查 map 是否為空。
完整示例
以下是一個完整的示例,展示了上述所有特性:
#include <iostream>
#include <map>
int main() {
// 建立一個 map
std::map<int, std::string> myMap;
// 插入元素
myMap.insert({1, "Apple"});
myMap[2] = "Banana";
myMap[3] = "Cherry";
// 訪問元素
std::cout << "Key 1: " << myMap[1] << std::endl; // 輸出: Apple
// 刪除元素
myMap.erase(2); // 刪除鍵為2的元素
// 查詢元素
auto it = myMap.find(2);
if (it != myMap.end()) {
std::cout << "Found: " << it->second << std::endl;
} else {
std::cout << "Key 2 not found!" << std::endl; // 輸出: Key 2 not found!
}
// 遍歷元素
for (const auto &pair : myMap) {
std::cout << "Key: " << pair.first << ", Value: " << pair.second << std::endl;
}
return 0;
}
set的使用
C++中的std::set
是一個關聯容器,用於儲存唯一的元素。std::set
是自動排序的,元素是以特定順序儲存的,且不允許重複元素。這個容器的實現通常是基於紅黑樹,因此支援\(O(logN)\)時間複雜度的插入、刪除和查詢操作。
基本特性
- 唯一性:集合中的元素是唯一的,不允許儲存重複的值。
- 排序性:元素自動按升序(預設)排列,插入的順序並不保證。
- 不可修改性:集合中的元素是隻讀的,不能直接修改已有的元素。
包含標頭檔案
在使用 std::set
之前,需要包含 <set>
標頭檔案:
#include <set>
建立和初始化
可以透過多種方式建立 std::set
,例如:使用預設建構函式,使用花括號初始化等。
#include <iostream>
#include <set>
int main() {
// 建立一個空的 set
std::set<int> mySet;
// 使用 insert 新增元素
mySet.insert(10);
mySet.insert(20);
mySet.insert(30);
//mySet:{10, 20, 30}
// 使用花括號初始化
std::set<int> Set2{3, 1, 4, 1, 5}; // Set2:{1,3,4,5}
return 0;
}
插入元素
可以使用 insert
方法新增元素:
mySet.insert(15); // 插入新元素
注意,如果嘗試插入一個已存在的元素,insert
不會變化集合,並返回一個指向該元素的迭代器。
刪除元素
可以使用 erase
方法刪除元素:
mySet.erase(20); // 刪除元素20
查詢元素
使用 find
方法來查詢元素。如果找到了,返回指向該元素的迭代器,否則返回 end()
:
auto it = mySet.find(10);
if (it != mySet.end()) {
std::cout << "Found: " << *it << std::endl; // 輸出: Found: 10
} else {
std::cout << "Not found!" << std::endl;
}
遍歷元素
可以使用範圍 for
迴圈或迭代器來遍歷 set
:
for (const auto &elem : mySet) {
std::cout << elem << " "; // 輸出: 10 15 30
}
大小和空檢查
可以使用 size()
方法獲取元素數量,也可以使用 empty()
方法檢查 set
是否為空:
std::cout << "Size: " << mySet.size() << std::endl; // 輸出: Size: 3
if (mySet.empty()) {
std::cout << "Set is empty!" << std::endl;
}
合併集合
可以透過 insert
方法將一個集合的元素插入到另一個集合中,自動處理重複值:
mySet.insert(anotherSet.begin(), anotherSet.end());
完整示例
以下是一個完整的示例,展示了上述所有特性:
#include <iostream>
#include <set>
int main() {
// 建立一個 set
std::set<int> mySet;
// 插入元素
mySet.insert(10);
mySet.insert(20);
mySet.insert(30);
mySet.insert(20); // 嘗試插入重複元素,忽略
// 刪除元素
mySet.erase(20); // 刪除元素20
// 查詢元素
auto it = mySet.find(10);
if (it != mySet.end()) {
std::cout << "Found: " << *it << std::endl; // 輸出: Found: 10
} else {
std::cout << "Not found!" << std::endl;
}
// 遍歷元素
std::cout << "Elements in mySet: ";
for (const auto &elem : mySet) {
std::cout << elem << " "; // 輸出: 10 30
}
std::cout << std::endl;
// 檢視大小和空狀態
std::cout << "Size of mySet: " << mySet.size() << std::endl;
if (mySet.empty()) {
std::cout << "mySet is empty!" << std::endl;
} else {
std::cout << "mySet is not empty!" << std::endl;
}
return 0;
}
小結
std::set
是一個強大的資料結構,適用於需要高效查詢和無重複元素的場景,如儲存唯一值、集合操作等。掌握其基本用法可以幫助開發者高效管理和操作集合資料。
C++中匿名函式的使用
在 C++ 中,匿名函式通常被稱為“Lambda 表示式”。它們允許在程式碼中定義未命名的函式,通常用於短小的、臨時的功能。Lambda 表示式在 C++11 標準中引入,並在之後的標準中得到了增強。
Lambda 表示式的基本語法
[capture](parameters) -> return_type {
// function body
}
capture
:捕獲外部變數的方式,可以是按值捕獲或按引用捕獲。parameters
:引數列表,如同普通函式。return_type
:返回型別,可以省略,編譯器會自動推斷。function body
:函式體。
示例
以下是一些使用 Lambda 表示式的示例。
1. 簡單的 Lambda 表示式
#include <iostream>
int main() {
auto greet = []() {
std::cout << "Hello, World!" << std::endl;
};
greet(); // 呼叫 Lambda 表示式
return 0;
}
2. 帶引數的 Lambda 表示式
#include <iostream>
int main() {
auto add = [](int a, int b) {
return a + b;
};
int sum = add(5, 3);
std::cout << "Sum: " << sum << std::endl; // 輸出: Sum: 8
return 0;
}
3. 捕獲外部變數
#include <iostream>
int main() {
int x = 10;
int y = 20;
auto add = [x, y]() { // 按值捕獲 x 和 y
return x + y;
};
std::cout << "Sum: " << add() << std::endl; // 輸出: Sum: 30
return 0;
}
4. 按引用捕獲
#include <iostream>
int main() {
int x = 10;
auto increment = [&x]() { // 按引用捕獲 x
x++;
};
increment();
std::cout << "Incremented x: " << x << std::endl; // 輸出: Incremented x: 11
return 0;
}
5. 結合 STL
Lambda 表示式常與 STL 演算法結合使用,例如 std::sort
:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> vec = {5, 3, 8, 1, 2};
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return a < b; // 自定義排序:升序
});
for (const auto &value : vec) {
std::cout << value << " ";
}
std::cout << std::endl;
return 0;
}
小結
Lambda 表示式在 C++ 中提供了一種方便且靈活的方式來定義匿名函式,能夠簡化程式碼並提高可讀性。在使用時,需要合理選擇捕獲方式(按值或按引用)以避免潛在的錯誤。