13 STL概述

13 STL概述

什么是STL?

STL(Standard Template Library)是C++标准模板库的缩写,它是一个广泛使用的C++库,提供了一组通用的类和函数模板,旨在提高代码的复用性和效率。STL包含各种数据结构、算法以及迭代器,使得程序员能够以更加简洁和高效的方式进行编程。

STL的主要组成部分

STL主要由以下几部分组成:

  1. 容器(Containers): 用于存储数据的类模板。
  2. 算法(Algorithms): 用于对容器中数据进行操作的函数模板。
  3. 迭代器(Iterators): 连接容器与算法的中介,提供访问容器中元素的统一接口。
  4. 函数对象(Function Objects): 可以像函数一样使用的对象,通常用于自定义算法的行为。

STL容器

STL容器分为以下几类:

1. 序列容器(Sequence Containers)

这些容器按照特定顺序存储数据,常用的有:

  • vector: 动态数组,可以在尾部快速插入和删除元素。
  • deque: 双端队列,支持在两端快速插入和删除。
  • list: 双向链表,支持在任意位置的快速插入和删除。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
numbers.push_back(6); // 向vector尾部添加元素

for (int number : numbers) {
std::cout << number << " ";
}
return 0;
}

2. 关联容器(Associative Containers)

这些容器存储键值对,并自动排序,常用的有:

  • set: 不允许重复元素的集合,基于排序的内部结构。
  • map: 键值对的集合,允许根据键快速查找值。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <map>

int main() {
std::map<std::string, int> ageMap;
ageMap["Alice"] = 30;
ageMap["Bob"] = 25;

for (const auto& pair : ageMap) {
std::cout << pair.first << " is " << pair.second << " years old.\n";
}
return 0;
}

3. 无序关联容器(Unordered Associative Containers)

这些容器基于哈希表实现,不保证排序,常用的有:

  • unordered_set: 不允许重复元素的集合。
  • unordered_map: 基于哈希表的键值对集合。

STL算法

STL提供了大量算法,包括查找、排序、操作等。最常用的算法有:

  • std::sort: 排序容器中的元素。
  • std::find: 在容器中查找元素。
  • std::copy: 复制元素。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <vector>
#include <algorithm> // 引入算法库

int main() {
std::vector<int> numbers = {5, 3, 4, 1, 2};
std::sort(numbers.begin(), numbers.end()); // 对vector进行排序

for (int number : numbers) {
std::cout << number << " ";
}
return 0;
}

STL迭代器

迭代器是STL的核心组件之一,它提供了一种遍历容器元素的统一方法。STL有多种类型的迭代器,包括:

  • 输入迭代器: 只能读数据。
  • 输出迭代器: 只能写数据。
  • 前向迭代器: 可以读和写,且可以重复遍历。
  • 双向迭代器: 可以向前和向后遍历。
  • 随机访问迭代器: 可以直接访问任何元素。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <vector>

int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};

// 使用迭代器遍历vector
for (std::vector<int>::iterator it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
return 0;
}

结论

STL是C++中一个强大的工具,极大地简化了数据结构的实现和特定算法的使用。掌握STL能够帮助程序员更高效地编写、维护和优化代码。通过容器、算法和迭代器的结合使用,STL为许多常见的编程任务提供了便捷的解决方案。在实际开发中,合理利用STL将显著提升工作效率和代码质量。

13 C++ 小白教程 - 赋值运算符

13 C++ 小白教程 - 赋值运算符

在 C++ 中,赋值运算符是一个非常重要的概念,主要用于将一个变量的值赋给另一个变量。下面我们将详细介绍赋值运算符的用法和一些相关的注意事项。

赋值运算符基本概念

赋值运算符的符号是 =。它的基本用法是将右侧的值(或变量)赋给左侧的变量。

语法

1
变量名 = 表达式;

例子

1
2
int a;          // 声明一个整数变量 a
a = 10; // 使用赋值运算符将值 10 赋给 a

在上述代码中,a 最终的值将是 10

赋值运算符的用法

赋值运算符不仅可以用于基本数据类型,也可以用于自定义的类类型。我们将通过几种不同的情况讨论它的用法。

基本数据类型的赋值

对于基本数据类型,如 intfloatchar,赋值运算符的使用非常简单:

1
2
3
4
int x = 5;    // 初始化并赋值
float y;
y = 2.5; // 使用赋值运算符赋值
char ch = 'A'; // 初始化字符

赋值运算符与表达式

赋值运算符可以与表达式结合使用:

1
2
3
int a = 5;
int b = 3;
a = a + b; // a 的值现在是 8

在这个例子中,赋值运算符将表达式 a + b 的结果赋给变量 a

赋值运算符与数组

当使用数组时,赋值运算符只对指针进行赋值,而不是对数组的所有元素进行逐个赋值。

1
2
3
int arr1[3] = {1, 2, 3};
int arr2[3];
arr2 = arr1; // 编译错误:不能直接将一个数组赋值给另一个数组

为了正确复制数组,您需要逐个元素赋值:

1
2
3
for (int i = 0; i < 3; i++) {
arr2[i] = arr1[i];
}

自定义类的赋值运算符

在 C++ 中,当你定义一个类时,如果你希望支持赋值操作,需要重载赋值运算符。下面是如何重载赋值运算符的一个简单示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class MyClass {
public:
int value;

// 构造函数
MyClass(int val) : value(val) {}

// 重载赋值运算符
MyClass& operator=(const MyClass& other) {
if (this != &other) { // 防止自赋值
this->value = other.value; // 赋值
}
return *this; // 返回当前对象的引用
}
};

// 使用赋值运算符
MyClass obj1(10);
MyClass obj2(20);
obj2 = obj1; // 现在 obj2 的 value 也变成了 10

自赋值检查

在重载赋值运算符时,通常要添加自赋值检查,即在将一个对象自身赋值给自己时,防止不必要的操作。使用 if (this != &other) 可以避免这个问题。

注意事项

  1. 基本数据类型的赋值:使用赋值运算符时,左侧必须是一个可赋值的变量,右侧可以是常量、变量或表达式。
  2. 指针和引用:赋值运算符对指针操作时,赋值只会指向相同的地址,而不是复制数据。
  3. 类的赋值:在自定义类型中,如果没有重载赋值运算符,将默认进行逐位复制,但这可能会导致资源管理等问题,所以建议总是根据需要自定义赋值逻辑。

通过学习 C++ 中的赋值运算符,你可以更好地理解变量的管理和内存的操作。赋值运算符在编写复杂程序时尤为重要,因为它直接关系到数据的正确传递和对象的有效管理。

小节容器、迭代器与算法

小节容器、迭代器与算法

在 C++ 中,标准模板库(STL)提供了丰富的容器、迭代器和算法,使得开发者可以方便地处理各种数据结构和算法。以下将详细介绍容器、迭代器和算法的使用。

1. STL 容器

STL 提供了多种容器,可以根据需要选择合适的容器类型。主要容器分为五类:

1.1 序列容器

序列容器维护一个元素的线性集合。常用的序列容器包括:

  • vector:动态数组,支持随机访问。
  • deque:双端队列,支持在两端高效插入和删除。
  • list:双向链表,支持在任意位置插入和删除元素,但随机访问效率低。

示例:使用 vector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <vector>

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};

// 添加元素
vec.push_back(6);

// 访问元素
for (int i = 0; i < vec.size(); ++i) {
std::cout << vec[i] << " ";
}
return 0;
}

1.2 关联容器

关联容器用于快速查找键值对。常用的关联容器包括:

  • set:存储唯一元素的集合,基于红黑树实现。
  • map:键值对集合,键唯一,支持快速查找。
  • unordered_set:哈希表实现的集合。
  • unordered_map:哈希表实现的键值对集合。

示例:使用 map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <map>

int main() {
std::map<std::string, int> ages;
ages["Alice"] = 30;
ages["Bob"] = 25;

// 访问元素
for (const auto& pair : ages) {
std::cout << pair.first << " is " << pair.second << " years old." << std::endl;
}
return 0;
}

1.3 容器适配器

容器适配器是对基础容器的封装,提供了特定的接口:

  • stack:后进先出(LIFO)结构。
  • queue:先进先出(FIFO)结构。
  • priority_queue:优先队列,元素按优先级出队。

示例:使用 stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <stack>

int main() {
std::stack<int> stk;
stk.push(10);
stk.push(20);

// 弹出元素
while (!stk.empty()) {
std::cout << stk.top() << std::endl; // 打印栈顶元素
stk.pop();
}
return 0;
}

2. 迭代器

迭代器是 STL 中的关键概念,它们提供了一种统一的方式来遍历容器元素。主要的迭代器类型有:

  • 输入迭代器:只读访问。
  • 输出迭代器:只写访问。
  • 前向迭代器:可以读写,并且可以前进。
  • 双向迭代器:可以前进和后退。
  • 随机访问迭代器:可以使用算术运算符进行移动。

2.1 使用迭代器遍历容器

可以使用迭代器自如地遍历各种容器。

示例:使用 vector 迭代器

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <vector>

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};

// 使用迭代器遍历
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
return 0;
}

3. STL 算法

STL 算法提供了一组对容器进行操作的功能,常用的算法包括:

  • 排序:sort()stable_sort()
  • 查找:find()binary_search()
  • 变换:transform()for_each()
  • 统计:count()accumulate()

3.1 使用 STL 算法

在容器上应用算法可以大大简化代码。

示例:排序和查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <vector>
#include <algorithm>

int main() {
std::vector<int> vec = {5, 3, 1, 4, 2};

// 排序
std::sort(vec.begin(), vec.end());

// 查找元素
auto it = std::find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
std::cout << "Found: " << *it << std::endl;
}

// 打印排序后的容器
for (int num : vec) {
std::cout << num << " ";
}
return 0;
}

总结

掌握 STL 中的容器、迭代器和算法是 C++ 编程的重要步骤。使用合适的容器、有效的迭代器和强大的算法可以提高代码的可读性和性能。在实际应用中,应根据需求选择最优的方案。