class IntCell {public:explicit IntCell(int value =0):value_(value){}int read()const{returnvalue_;}void write(int value){value_= value;}private:intvalue_;};
template<class T>T findMax(conststd::vector<T>& a){ T best = a.at(0);for(constauto& x : a){if(best < x){ best = x;}}return best;}
这使同一份容器代码可以用于整数、字符串和自定义对象。
泛型与比较接口
泛型代码需要明确“类型必须支持什么能力”。
在 C++ 中,可以通过模板和比较器表达:
template<class T,class Compare>T findBest(conststd::vector<T>& a, Compare cmp){ T best = a.at(0);for(constauto& x : a){if(cmp(best, x)){ best = x;}}return best;}
比较器会在排序、堆、搜索树和图算法中反复出现。读泛型算法时,先找清楚元素类型和比较规则。
C++ 模板:从具体类型到类型参数
如果不用模板,类似的函数往往会为不同类型重复写多份:
int maxInt(int a,int b){return a < b ? b : a;}double maxDouble(double a,double b){return a < b ? b : a;}
这里真正变化的是类型,算法步骤并没有变化。
模板把“类型”也变成参数:
template<class T>T maxValue(const T& a,const T& b){return a < b ? b : a;}
后面写线性表、栈、队列、堆和搜索树时,模板让同一个数据结构可以保存不同元素类型。
全课程代码会反复出现的 C++ 语法
后面章节的代码会集中使用这些语言工具:
语法或库
典型写法
用途
模板
template <class T>
写可复用容器和算法
引用
const T& value
避免复制,并表达只读参数
指针
Node<T>* next
表示链式结构和树结构连接
空指针
nullptr
表示没有后继、孩子或根
STL 容器
std::vector, std::list
保存顺序数据或辅助存储
读代码时先判断:这个名字表示“值”、 “引用”,还是“结构之间的连接”。
C++ 语法:STL 与工程表达
这些工具让代码更接近算法意图:
语法或库
典型写法
用途
STL 适配器
std::stack, std::queue, std::priority_queue
表达栈、队列和优先队列
自动类型
auto it = ...
简化迭代器和复杂类型
比较器
Compare cmp 或 lambda
定制排序、堆和最优选择规则
可选返回
std::optional<T>
表示查找可能失败
枚举类
enum class Tag
表达有限状态并避免名字污染
1. 先看容器
数据放在数组、链表、栈、队列、堆,还是集合中。
2. 再看连接
指针、下标和引用说明元素之间如何到达。
3. 找比较规则
排序、堆和搜索树都依赖比较器或顺序关系。
4. 看失败路径
optional、异常和状态值说明操作何时不能完成。
C++ 值语义与对象生命周期
C++ 容器通常直接保存对象值,例如 std::vector<int> 保存的是一段连续的 int。
std::vector<int> a;a.push_back(3);int x = a.at(0);std::vector<std::string> words;words.emplace_back("tree");
读 C++ 数据结构代码时,要特别注意对象何时被创建、复制、移动和销毁:
push_back(x):把已有对象放入容器,可能复制或移动
emplace_back(args...):在容器内部直接构造对象
const T&:只读引用,通常用于避免不必要复制
T&&:右值引用,常用于移动资源
异常处理
程序错误可以粗略分为:
语法错误:编译阶段能发现
运行时错误:执行时触发,例如越界、空指针、除零
逻辑错误:程序能运行,但结果不符合需求
数据结构代码需要明确异常边界:
空栈 pop
空堆 deleteMin
越界访问
输入格式错误
C++ 错误处理:异常与 optional
数据结构的失败情况要明确表达。C++ 中常见做法有两类:
操作无法继续时抛出异常
查找可能失败时返回 std::optional<T>
int pop(std::vector<int>& data){if(data.empty()){throwstd::underflow_error("pop from empty stack");}int value = data.back(); data.pop_back();return value;}std::optional<int> find(conststd::vector<int>& data,int key){for(int x : data)if(x == key)return x;returnstd::nullopt;}