算法基础课(持续更新中)
算法基础课
基础算法(一)
快速排序
1 | void quick_sort(int q[],int l,int r) |
归并排序
1 | void merge_sort(int q[],int l,int r) |
二分
整数二分
1 | bool check(int x) {/* ... */} // 检查x是否满足某种性质 |
浮点数二分
1 | bool check(double x) {/* ... */} // 检查x是否满足某种性质 |
基础算法(二)
高精度
高精度加法
本质上是模拟人进行列竖式加法的过程,即$a_1$+…+$a_n$+t,其中当$a$的退一位加起来不超过10则$t=0$否则$t=1$,以此类推
1 |
|
vector相关知识点
-
vector定义
vector是 C++ 标准模板库(STL)中的一个容器,它可以看作是一个动态数组。它能存储一系列相同类型的元素,并且可以根据需要自动调整大小。使用vector需要包含<vector>头文件。 -
vector数组相关操作(最后面)增加用
.push_back(一个数),(最后面)删除.pop_back(一个数),指定位置插入.insert(向量,指定位置),指定位置删除.erase(向量,指定位置),清空.clear(),查看大小.size() -
vector元素的索引和数组一样,也是从 0 开始存储的
-
vector和普通数组区别
1.大小灵活性
- 普通数组:大小在定义时就必须确定,且在程序运行过程中不能改变。例如
int arr[10];定义了一个大小为 10 的整数数组,之后无法再改变其大小。 - vector:可以动态调整大小。可以使用
push_back()方法在末尾添加元素,当空间不足时,vector会自动分配更大的内存空间来存储元素。
2.内存管理
- 普通数组:由程序员手动管理内存。如果数组在栈上分配,其生命周期受限于所在的代码块;如果在堆上分配(使用
new),则需要手动使用delete释放内存,否则会造成内存泄漏。 - vector:自动管理内存。当
vector不再使用时,其占用的内存会自动释放,无需程序员手动干预。
3.功能丰富度
- 普通数组:只提供基本的元素访问功能,操作相对有限。
- vector:提供了丰富的成员函数,如
size()获取元素数量、empty()判断是否为空、clear()清空元素等,使用起来更加方便。
- 普通数组:大小在定义时就必须确定,且在程序运行过程中不能改变。例如
-
使用 vector 而不用数组的原因
在大整数相加的场景中,输入的数字长度是不确定的。如果使用普通数组,需要预先定义一个足够大的数组来存储数字的每一位,但这样可能会浪费大量的内存空间。而
vector可以根据输入数字的实际长度动态调整大小,避免了内存的浪费,并且其提供的push_back()方法可以方便地将数字的每一位添加到容器中,同时在处理进位时也更加方便。因此,使用vector能更好地适应这种动态长度的需求。
add函数运行示例
假设我们要计算两个四位数 a = 1234 和 b = 5678 的和。
在代码中,输入的数字以字符串形式存储,然后将其逆序存储到 vector<int> 中,这样做是为了方便处理进位。对于 a = 1234,存储在 vector<int> 中为 A = {4, 3, 2, 1};对于 b = 5678,存储在 vector<int> 中为 B = {8, 7, 6, 5}。
具体步骤:
-
[x] 初始化
-
vector<int> C;:用于存储相加结果的向量,初始为空。 -
int t = 0;:用于存储每一位相加后的结果以及进位信息,初始值为 0。 -
[x] 循环处理每一位
循环条件为 i < A.size() || i < B.size(),这意味着只要 A 或 B 还有未处理的位,就会继续循环。
-
[ ] 第一次循环(
i = 0) -
if(i < A.size()) t += A[i];:因为i = 0小于A.size()(4),所以t = t + A[0] = 0 + 4 = 4。 -
if(i < B.size()) t += B[i];:因为i = 0小于B.size()(4),所以t = t + B[0] = 4 + 8 = 12。 -
C.push_back(t % 10);:将t % 10(即 2)添加到C中,此时C = {2}。 -
t /= 10;:t除以 10,得到进位 1,即t = 1。 -
[ ] 第二次循环(
i = 1) -
if(i < A.size()) t += A[i];:t = t + A[1] = 1 + 3 = 4。 -
if(i < B.size()) t += B[i];:t = t + B[1] = 4 + 7 = 11。 -
C.push_back(t % 10);:将t % 10(即 1)添加到C中,此时C = {2, 1}。 -
t /= 10;:t除以 10,得到进位 1,即t = 1。 -
[ ] 第三次循环(
i = 2) -
if(i < A.size()) t += A[i];:t = t + A[2] = 1 + 2 = 3。 -
if(i < B.size()) t += B[i];:t = t + B[2] = 3 + 6 = 9。 -
C.push_back(t % 10);:将t % 10(即 9)添加到C中,此时C = {2, 1, 9}。 -
t /= 10;:t除以 10,得到进位 0,即t = 0。 -
[ ] 第四次循环(
i = 3) -
if(i < A.size()) t += A[i];:t = t + A[3] = 0 + 1 = 1。 -
if(i < B.size()) t += B[i];:t = t + B[3] = 1 + 5 = 6。 -
C.push_back(t % 10);:将t % 10(即 6)添加到C中,此时C = {2, 1, 9, 6}。 -
t /= 10;:t除以 10,得到进位 0,即t = 0。 -
[x] 处理最后可能的进位
if(t) C.push_back(1);
因为此时 t = 0,所以不需要添加额外的进位,C 仍然为 {2, 1, 9, 6}。
- [x] 返回结果
return C;:返回存储相加结果的向量 C。
在 main 函数中,将 C 逆序输出,得到最终结果 6912,即 1234 + 5678 = 6912。
auto的用法
auto是C++11的新特性,可以自动识别变量属性。比如auto C=add(A,B);就自动识别了add返回的类型,因此auto C <=> vector<int>c
a[i] - '0' 的作用:将字符串每一位由ASCII码转为整数
在 C++ 中,当你从输入读取一个数字字符串时,比如 "123",字符串中的每个字符(如 '1'、'2'、'3')实际上存储的是字符的 ASCII 码值,而不是对应的数值。字符 '0' 到 '9' 的 ASCII 码是连续的,'0' 的 ASCII 码值是 48,'1' 是 49,以此类推,'9' 是 57。
b[i] - '0' 的作用就是将字符形式的数字转换为对应的整数值。例如,当 b[i] 为 '1' 时,'1' 的 ASCII 码值是 49,'0' 的 ASCII 码值是 48,那么 '1' - '0' 就等于 49 - 48 = 1,这样就把字符 '1' 转换为了整数 1。
如果没有 b[i] - '0' 这个操作,直接将字符存储到 vector<int> 中,那么存储的是字符的 ASCII 码值,而不是对应的数值,这会导致后续的计算出现错误。