1. auto 的改进auto 和 decltype 基础 –> 自动类型推导
C++14 对 auto 关键字进行了非常显著的增强,主要解决了 C++11 中 auto 使用起来比较繁琐的问题,并引入了两大核心改进:函数返回类型推导 和 泛型 lambda。
1.1 函数返回类型推导C++ 中的 auto 类型推导是 C++11 引入的核心特性之一。它主要遵循 模板类型推导 的规则,在 C++14 中允许函数使用 auto 推导返回类型(不含尾置返回类型)。
在 C++11 中必须使用尾置返回类型:
1auto func() -> int { return 42; }
在 C++14 中可以直接使用 auto 进行返回值类型推导:
1234567891011121314151617181920// 编译器自动推导为 doubleauto add(int x, double y) { return x + y;}// 甚至可以用于递归函数(但需要有一个非递归的返回语句)auto factorial(int n) { ...
1. 泛型 Lambda1.1 语法C++14 引入了泛型 Lambda,允许 Lambda 表达式的参数使用 auto 类型推导。这使得编译器能够为每个调用点自动推导参数类型,本质上编译器会生成一个函数对象模板。
1234567891011// 基本语法auto lambda = [](auto param1, auto param2, ...) { // 函数体};// 语法对比// C++11: 显式指定参数类型auto lambda1 = [](int x, int y) { return x + y; };// C++14: 使用 auto 推导参数类型auto lambda2 = [](auto x, auto y) { return x + y; };auto lambda3 = [](auto&& x) { return x * 2; };
每个 auto 参数都是独立的类型参数,也就是说param1,param2可以是不同的类型
例如:lambda2(5, 3.1 ...
1. constexpr 概述constexpr(常量表达式)是 C++11 引入的关键字,用于指定值或函数可以在编译时计算,是编译时计算的核心特性。其设计目标主要有以下几点:
编译时计算:将运行时计算转移到编译时
类型安全:编译时进行类型检查
性能优化:消除运行时开销
泛型编程:增强模板元编程能力
123456// 编译时常量constexpr int size = 100; // ✅ 编译时确定// 编译时函数constexpr int square(int x) { return x * x; }// 编译时使用int array[square(5)]; // ✅ 数组大小在编译时计算:25
关于constexpr的使用和const是类似的,下面的表格中将二者的特性进行是对比:
特性
const
constexpr
主要含义
只读,不可修改
编译时常量
初始化时机
运行时或编译时
必须编译时
能否修改
初始化后不可修改
初始化后不可修改
作用域
类型修饰符
类型修饰符 + 函数修饰符
C++版本
C++98
C++11+
...
1. 自定义字面量1.1 基本语法自定义字面量是C++11引入的特性,允许程序员为字面量定义自己的后缀,从而创建具有特定类型和值的对象。它的基本语法如下:
1234// 定义字面量运算符返回值类型 operator"" 后缀名(参数类型 参数) { // 转换逻辑}
如果详细进行划分,定义字面量的时候有四种重载形式:
整数字面量
12// 整数字面量ReturnType operator"" _suffix(unsigned long long);
浮点数字面量
12// 浮点字面量ReturnType operator"" _suffix(long double);
字符字面量
12// 字符字面量ReturnType operator"" _suffix(char);
字符串字面量
12// 字符串字面量ReturnType operator"" _suffix(const char*, size_t);
关于自定义字面量后缀的命名必须以下划线( ...
1. 基本语法C++14 引入了二进制字面量,允许开发者直接使用二进制数字表示整数,使代码在涉及位操作时更加直观和可读。
下面是基本语法格式:
12int a = 0b101010; // 二进制前缀 0b, 十进制的 42int b = 0B11110000; // 大写 B 也可以
二进制数 0b101010 每一位的权值从右向左依次是 20,21,22,…
二进制数 0B11110000 每一位的权值从右向左依次是 20,21,22,…
我们可以通过代码将指定的二进制数值以十进制的格式进行输出,示例代码如下:
12345678910111213141516#include <iostream>#include <bitset>int main() { // 二进制字面量 int binary1 = 0b1010; // 十进制 10 int binary2 = 0b11110000; // 十进制 240 int binary3 = 0b100000000; // 十进制 ...
1. 回溯算法概述回溯算法(backtracking algorithm)是一种通过穷举来解决问题的方法,它的核心思想是从一个初始状态出发,暴力搜索所有可能的解决方案,当遇到正确的解则将其记录,当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,直到找到解或者尝试了所有可能的选择都无法找到解为止。这种走不通就退回再走的技术称为回溯法,它是一种“优化的暴力搜索”,而满足回溯条件的某个状态的点称为“回溯点”。
回溯算法通常采用深度优先搜索来遍历解空间,前序、中序和后序遍历都属于深度优先搜索。回溯算法的核心思想有两点:
深度优先搜索:回溯算法基于深度优先搜索的思想,它会沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点所在的路径无法得到有效的解时,算法会回溯到上一个节点,尝试其他的路径继续搜索。
穷举与剪枝:本质上是对所有可能的解进行穷举搜索,但与纯粹的暴力枚举不同,回溯算法会在搜索过程中根据问题的约束条件进行剪枝操作,避免对一些明显不可能产生解的分支进行搜索,从而提高搜索效率。
1.1 子集树子集树解决的是选还是不选的问题,也就是组合问题。元素的顺序不重要,只关 ...
1. QtConcurrent 类概述QtConcurrent 是 Qt 提供的高级 API,位于 QtConcurrent 命名空间下。它是对 QThreadPool 和 QFuture 的高级封装,旨在简化多线程编程。
QtConcurrent 模块默认情况下并不自己创建线程,而是复用 QThreadPool::globalInstance()。
异步执行:任务被扔到线程池后,主线程立即返回,继续执行后续代码。
QFuture 代表了未来的结果,包括:状态查询,进度反馈,结果传递。
它的最大优势是:你不需要手动创建和管理线程,也不需要处理线程底层的同步逻辑,只需关注要执行的函数。它把怎么开启线程、怎么分配任务给哪个线程、怎么回收线程这些脏活累活都交给了 QThreadPool,只留给你 QFuture 作为接口,让你专注于做什么而不是怎么做。
1.1 准备工作在使用 QtConcurrent 之前,必须在项目文件(.pro 或 CMakeLists.txt)中引入 concurrent 模块:
.pro (qmake):
1QT += core concurrent
CMak ...
1. 分治算法概述分治算法(Divide and Conquer)是一种重要的算法设计策略,其基本思想是将一个规模较大的问题分解为若干个规模较小、相互独立且与原问题形式相同的子问题,然后递归地解决这些子问题,最后将子问题的解合并起来得到原问题的解。
分治算法通常包含三个步骤:
分解(Divide):将原问题分解为若干个规模较小、相互独立、与原问题形式相同的子问题。
解决(Conquer):若子问题规模较小而容易被解决则直接求解,否则递归地解各个子问题。
合并(Combine):将各个子问题的解合并为原问题的解。
2. 分支算法经典案例2.1 归并排序归并排序是分治算法的一个经典应用,它的基本思想是将一个数组分成两个子数组,分别对这两个子数组进行排序,然后将排好序的子数组合并成一个有序的数组。
归并排序算法
2.2 快速排序快速排序采用分治策略,通过递归地将数组分割成子数组来实现排序。其平均时间复杂度为 **O(n log n)**,在大多数情况下表现良好,因此在实际应用中广泛使用。
快速排序算法
2.3 合并K个有序单链表
给定一个链表数组,每个链表都已经按升序排列,要求使 ...
1. 贪心算法概述贪心算法(Greedy Algorithm)是一种基于局部最优选择的算法设计思想,其核心在于每一步都做出当前看起来最优的选择,并希望通过这些局部最优选择的累积,最终得到全局最优解。它不回溯,也不考虑未来的可能影响,而是“贪心”地选择当前最有利的选项。
在处理某些问题的时候使用贪心算法通常遵循以下步骤:
分解问题:将原问题分解为一系列子问题。
贪心选择:在每一个子问题中,都做出当前看起来最优的选择。
求解子问题:对每一个子问题求解,得到子问题的局部最优解。
合并解:将所有子问题的局部最优解合并起来,得到原问题的解。
贪心算法典型的应用场景:
问题类型
示例
贪心策略
区间调度问题
活动选择、无重叠区间
按结束时间排序,选最早结束的区间
最小生成树
Prim、Kruskal 算法
每次选权重最小的边
最短路径问题
Dijkstra 算法
每次选当前距离起点最近的节点
哈夫曼编码
数据压缩
合并频率最小的字符节点
部分背包问题
物品可分割的背包问题
按单位价值排序,优先选高价值物品
贪心算法与动态规划作为两种重要的算法设计策略,掌握贪心算 ...
1. 哈希表哈希表(Hash Table)是一种高效的数据结构,用于存储键值对(Key-Value Pair)。它通过哈希函数将键映射到数组中的特定位置,从而实现快速的插入、删除和查找操作。在 C++ 的标准模板库(STL)中,有多个容器基于哈希表实现,它们为开发者提供了高效的数据存储和查找方式:
std::unordered_map和std::unordered_set
std::unordered_multimap 和 std::unordered_multiset
作为一名专业的 C++ 程序员,我们不应仅仅满足于表面的认知,而要深入探寻事物背后的原理。就如同我们即将研究哈希表的底层实现一样,在开启这段深入探究之旅前,我们很有必要先了解一些关于哈希表的基础概念。这样一来,我们就能搭建起一个扎实的知识框架,为后续更深入地剖析哈希表的底层奥秘做好充分准备。
1.1 哈希函数哈希函数是哈希表的核心所在,它具备强大的功能,能够把任意大小的数据(即键)精准地映射为固定大小的数据,而这种固定大小的数据通常表现为整数。在理想的情形下,哈希函数理应满足以下几个至关重要的条件:
均匀分布特性 ...








































