C++11的一些语法
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++ 中提供了一种方便且灵活的方式来定义匿名函数,能够简化代码并提高可读性。在使用时,需要合理选择捕获方式(按值或按引用)以避免潜在的错误。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步