1. STL容器
- 什么是STL容器,为什么使用它们。
- 向量(vector):使用向量存储数据。
- 列表(list):使用列表实现双向链表。
- 映射(map):使用映射实现键值对存储。
什么是STL容器?
STL容器是一种用于存储和管理数据的C++模板类,它们提供了多种数据结构,以满足不同的需求。STL容器分为序列容器(Sequence Containers)和关联容器(Associative Containers)两大类。序列容器类似于数组,关联容器则基于键值对存储数据。
向量(vector)
向量是序列容器中最常用的之一,它类似于动态数组。它具有自动扩展和收缩的能力,因此可以根据需要存储任意数量的元素。
#include <vector>
#include <iostream>
int main() {
std::vector<int> myVector; // 创建一个整数向量
// 向向量中添加元素
myVector.push_back(1);
myVector.push_back(2);
myVector.push_back(3);
// 遍历并输出向量中的元素
for (int i : myVector) {
std::cout << i << " ";
}
return 0;
}
列表(list)
列表是双向链表的实现,提供了高效的插入和删除操作。与向量不同,列表的元素在内存中不是连续存储的,因此适用于需要频繁插入和删除操作的情况。列表的简单示例:
#include <list>
#include <iostream>
int main() {
std::list<std::string> myList; // 创建一个字符串列表
// 向列表中添加元素
myList.push_back("Hello");
myList.push_back("World");
myList.push_front("C++");
// 遍历并输出列表中的元素
for (const std::string& str : myList) {
std::cout << str << " ";
}
return 0;
}
映射(map)
映射是关联容器,它将键与值关联起来,允许通过键快速查找对应的值。这在需要构建字典、查找表或关系映射时非常有用。以下是一个映射的简单示例:
#include <map>
#include <iostream>
int main() {
std::map<std::string, int> myMap; // 创建一个字符串到整数的映射
// 向映射中添加键值对
myMap["apple"] = 5;
myMap["banana"] = 3;
myMap["cherry"] = 8;
// 查找并输出映射中的值
std::cout << "The number of bananas is: " << myMap["banana"] << std::endl;
return 0;
}
STL容器的强大功能使它们成为C++开发中不可或缺的一部分。无论你的项目规模如何,STL都提供了各种工具,用于有效地管理和操作数据,让代码更加高效和可维护。
2. STL算法
- 什么是STL算法,它们的作用。
- 排序算法:介绍STL的排序算法。
- 查找算法:介绍STL的查找算法。
- 使用STL算法来处理容器中的数据。
什么是STL算法?
STL算法是一组通用的、可复用的算法,它们独立于特定的容器类型,可以用于处理各种数据结构。STL算法可以显著提高代码的可读性和可维护性,同时还能提供高效的性能。
排序算法
STL提供了多种排序算法,其中最常用的是std::sort()
函数,它可以对容器中的元素进行升序排序。排序算法:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {5, 2, 8, 1, 9};
// 使用std::sort()对向量进行升序排序
std::sort(numbers.begin(), numbers.end());
// 输出排序后的结果
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
查找算法
STL还提供了多种查找算法,其中包括std::find()
函数,它可以在容器中查找指定的元素。
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> numbers = {5, 2, 8, 1, 9};
int target = 8;
// 使用std::find()在向量中查找目标元素
auto result = std::find(numbers.begin(), numbers.end(), target);
// 检查查找结果
if (result != numbers.end()) {
std::cout << "Found " << target << " at position " << (result - numbers.begin()) << std::endl;
} else {
std::cout << target << " not found." << std::endl;
}
return 0;
}
使用STL算法处理容器中的数据
STL算法通常以迭代器作为参数,因此它们可以应用于各种容器,如向量、列表、映射等。这使得算法非常通用和灵活。你可以使用std::for_each()
、std::transform()
等算法来遍历容器中的元素,执行自定义的操作。
3. 自定义模板
- 什么是模板,为什么使用模板。
- 函数模板:创建可以处理不同数据类型的通用函数。
- 类模板:创建可以处理不同数据类型的通用类。
什么是模板?
模板是一种通用的代码蓝图,它允许你编写可以处理不同数据类型的代码。C++中有两种主要类型的模板:函数模板和类模板。
函数模板
函数模板允许你编写通用的函数,这些函数可以接受不同类型的参数。函数模板的定义以template
关键字开始,后跟模板参数列表和函数声明。
简单的函数模板,用于交换两个值:
template <typename T>
void swapValues(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
double a = 3.14, b = 2.71;
swapValues(x, y); // 交换整数
swapValues(a, b); // 交换双精度浮点数
return 0;
}
函数模板的typename T
部分表示模板参数,它可以是任何数据类型。
类模板
类模板允许你编写通用的类,这些类可以处理不同类型的成员变量和成员函数。类模板的定义以template
关键字开始,后跟模板参数列表和类定义。
类模板,用于创建通用的栈数据结构:
template <typename T>
class Stack {
public:
Stack() : top(-1) {}
void push(T item) {
if (top < MaxSize - 1) {
data[++top] = item;
}
}
T pop() {
if (top >= 0) {
return data[top--];
} else {
// 处理栈为空的情况
throw std::runtime_error("Stack is empty");
}
}
private:
static const int MaxSize = 100;
T data[MaxSize];
int top;
};
int main() {
Stack<int> intStack;
intStack.push(5);
intStack.push(10);
int x = intStack.pop(); // 弹出值为10的元素
Stack<double> doubleStack;
doubleStack.push(3.14);
doubleStack.push(2.71);
double y = doubleStack.pop(); // 弹出值为2.71的元素
return 0;
}
类模板的typename T
部分表示模板参数,可以是任何数据类型。
为什么使用模板?
使用模板可以使代码更加通用和灵活,无需为不同的数据类型编写重复的代码。模板还有助于提高代码的可维护性,只需编写一次通用代码,即可适用于多种数据类型。
4. 示例和练习
使用STL容器
使用STL容器的示例代码,演示向量(vector)的用法,包括添加元素、遍历容器和查找元素:
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers; // 创建整数向量
// 向向量添加元素
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);
// 遍历向量并输出元素
for (int num : numbers) {
std::cout << num << " ";
}
// 查找元素是否存在
int target = 2;
auto it = std::find(numbers.begin(), numbers.end(), target);
if (it != numbers.end()) {
std::cout << "\n" << target << " found at position " << std::distance(numbers.begin(), it);
} else {
std::cout << "\n" << target << " not found";
}
return 0;
}
使用STL算法
使用STL算法的示例代码,演示排序和查找算法的用法:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
// 排序向量
std::sort(numbers.begin(), numbers.end());
// 输出排序后的向量
for (int num : numbers) {
std::cout << num << " ";
}
// 使用二分查找查找元素
int target = 5;
if (std::binary_search(numbers.begin(), numbers.end(), target)) {
std::cout << "\n" << target << " found";
} else {
std::cout << "\n" << target << " not found";
}
return 0;
}
使用模板
使用函数模板的示例代码,如何创建一个通用的函数来比较两个值:
#include <iostream>
template <typename T>
bool isEqual(T a, T b) {
return a == b;
}
int main() {
int x = 5, y = 5;
double a = 3.14, b = 2.71;
if (isEqual(x, y)) {
std::cout << "x and y are equal\n";
} else {
std::cout << "x and y are not equal\n";
}
if (isEqual(a, b)) {
std::cout << "a and b are equal\n";
} else {
std::cout << "a and b are not equal\n";
}
return 0;
}
练习题
创建一个向量,存储一组学生的分数,并计算平均分。
#include <iostream>
#include <vector>
int main() {
std::vector<double> scores; // 创建一个双精度浮点数向量来存储学生的分数
// 向向量添加学生分数
scores.push_back(85.5);
scores.push_back(92.0);
scores.push_back(78.5);
scores.push_back(88.0);
scores.push_back(90.5);
// 计算平均分
double sum = 0.0;
for (double score : scores) {
sum += score;
}
double average = sum / scores.size();
// 输出平均分
std::cout << "平均分: " << average << std::endl;
return 0;
}
运行结果:
解答:
- 首先,包含
<iostream>
和<vector>
头文件来使用C++的标准输入输出和向量容器。 - 然后,创建一个
std::vector<double>
类型的向量,用于存储学生的分数。 - 使用
push_back
函数将分数添加到向量中。 - 通过迭代向量中的分数,计算它们的总和并除以向量的大小来获得平均分。
- 最后,输出平均分。
使用STL的列表容器存储一组单词,并按字母顺序排序。
#include <iostream>
#include <list>
#include <algorithm>
int main() {
std::list<std::string> words; // 创建一个字符串列表来存储单词
// 向列表添加单词
words.push_back("apple");
words.push_back("banana");
words.push_back("cherry");
words.push_back("date");
words.push_back("fig");
// 使用STL的排序算法对单词进行排序
words.sort();
// 遍历并输出排序后的单词
for (const std::string& word : words) {
std::cout << word << " ";
}
return 0;
}
运行结果:
解答:
- 包含了
<iostream>
和<list>
头文件,以便使用C++的标准输入输出和列表容器。 - 然后,创建一个
std::list<std::string>
类型的列表,用于存储单词。 - 使用
push_back
函数将单词添加到列表中。 - 使用
sort
函数对列表中的单词进行字母顺序排序。 - 最后,遍历并输出排序后的单词。
创建一个通用的函数模板,用于计算两个数的最大值。
#include <iostream>
template <typename T>
T findMax(T a, T b) {
return (a > b) ? a : b;
}
int main() {
int intMax = findMax(42, 17);
double doubleMax = findMax(3.14, 2.71);
std::cout << "最大整数值: " << intMax << std::endl;
std::cout << "最大双精度浮点数值: " << doubleMax << std::endl;
return 0;
}
运行结果:
解答:
- 定义一个通用函数模板
findMax
,它可以接受任何类型的参数a
和b
。 - 函数模板的返回类型也是参数的类型。
- 在
main
函数中,演示如何使用这个模板函数来查找整数和双精度浮点数的最大值。
创建一个类模板,表示二维坐标点,包括x和y坐标。
#include <iostream>
template <typename T>
class Point {
public:
Point(T x, T y) : x_(x), y_(y) {}
void display() const {
std::cout << "X坐标: " << x_ << ", Y坐标: " << y_ << std::endl;
}
private:
T x_;
T y_;
};
int main() {
Point<int> intPoint(2, 3);
Point<double> doublePoint(1.5, 2.0);
std::cout << "整数坐标点:" << std::endl;
intPoint.display();
std::cout << "双精度浮点数坐标点:" << std::endl;
doublePoint.display();
return 0;
}
运行结果:
解答:
- 定义一个类模板
Point
,它有两个模板参数typename T
,表示x和y坐标的类型。 - 类模板有一个构造函数,可以接受两个参数,分别用于初始化x和y坐标。
- 类模板还有一个成员函数
display
,用于显示坐标点的值。 - 在
main
函数中,我们演示了如何创建不同类型的坐标点。
使用STL的映射容器存储学生的姓名和分数,然后按姓名查找分数。
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, double> studentScores; // 创建一个映射容器,姓名映射到分数
// 向映射容器添加学生和分数
studentScores["Alice"] = 90.5;
studentScores["Bob"] = 88.0;
studentScores["Charlie"] = 92.5;
studentScores["David"] = 85.0;
// 按姓名查找分数
std::string nameToFind = "Bob";
if (studentScores.find(nameToFind) != studentScores.end()) {
double score = studentScores[nameToFind];
std::cout << nameToFind << " 的分数是 " << score << std::endl;
} else {
std::cout << "找不到学生:" << nameToFind << std::endl;
}
return 0;
}
运行结果:
解答:
- 使用
std::map
容器来创建一个学生姓名到分数的映射。 - 使用方括号操作符
[]
添加学生和分数的映射。 - 使用
find
函数按姓名查找分数,如果找到,就输出分数;如果找不到,就输出找不到的消息。