综述:
💞目的:本系列是个人整理为了秋招算法
的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于网上知识点
进行的,每个代码参考热门博客和GPT3.5,其中也可能含有一些的个人思考。
🤭结语:如果有帮到你的地方,就点个赞和关注一下呗,谢谢🎈🎄🌷!!!
🌈数据结构基础知识总结篇
文章目录
ACM模式
- 基础输入要点
- 引用库需要自己加上对应的库,如
#include <algorithm>
- 输入使用
while (cin >> a ){ 算法主体 }
- 输出使用
cout
,注意删除自己的测试输出,不能使用return
,否则会一直报错语法错误
#include <iostream> using namespace std; int main() { int a, b; while (cin >> a >> b) { // 注意 while 处理多个 case // 64 位输出请用 printf("%lld") cout << a + b << endl; } }
- 引用库需要自己加上对应的库,如
- 二维数组的初始化
vector<vector<int>> dp(rows, vector<int>(cols, 0));// 注意要进行初始化 for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { cin >> dp[i][j];// 不能使用push_back()进行处理 }
- 输入一行以回车结尾的数字
vector<int> vec; int tmp = 0; do {// 不能使用while(){},因为会丢失第一个输入 cin >> tmp; vec.push_back(tmp); } while (cin.get() != '\n');
需要整理的基本输入https://zhuanlan.zhihu.com/p/494535515
cpp算法工具函数
概述
- 需要包含
#include<algorithm>
头文件- 作用:包含了对于容器的常用操作
- 来源:大量基于迭代器的非成员模版函数
- 调用形式
- 函数指针
- 仿函数
- 匿名函数
#include <iostream> // std::cout #include <algorithm> // std::for_each #include <vector> // std::vector // 函数形式 void myfunction (int i) { // function: std::cout << ' ' << i; } // 仿函数形式 struct myclass { // function object type: void operator() (int i) {std::cout << ' ' << i;} } myobject;// 注意声明时就定义了类对象 // 匿名函数形式 auto anonymous_function = [](int i){ cout << i << ' '; }; int main () { std::vector<int> myvector = {10, 20, 30}; for_each (myvector.begin(), myvector.end(), myfunction); for_each (myvector.begin(), myvector.end(), myobject); for_each (myvector.begin(), myvector.end(), anonymous_function); return 0; }
基本工具函数
- for_each(iterator_start, iteratro_end, functor)
- 输入
- iterator_start:容器的起始迭代器,指向起始位置的指针
- iteratro_end:容器的结束迭代器,指向结束位置的指针
- functor:函数对象,如匿名函数、仿函数和函数指针等
- 以下工具函数的调用参数含义均如上所示
- 输出
- 遍历指定容器迭代器范围内的元素,并交由functor进行处理
- 其他
- 函数对象的形参必须是指定的迭代容器元素类型
- 输入
- find(iterator_start, iteratro_end, 子序列值)
- 输出:返回迭代容器范围内
匹配子序列值的起始位置迭代器
- 输出:返回迭代容器范围内
- count(ivec.begin() , ivec.end() , searchValue)
- 输出:返回查询值出现的
次数
- 输出:返回查询值出现的
- sort
- equal()
- search()
- swap()
- replace()
- remove()
- unique()
- sort()
- min()
- max()
// for_each的使用
vector<int> vec = {1, 2, 3, 4};
struct functor {
void operator()(int i) { cout << i << ' ';}
}func;
for_each(vec.begin(), vec.end(), func);
// find函数的使用
string str = "hello world";
auto itr = find(str.begin(), str.end(), "ll");
if (it != str.end())
cout << "查找成功";
// count函数的使用
string m = "1233445";
cout << count(m.begin(), m.end(),'3') << endl;
算法模板
基本函数模板
-
基本算法模型
// 输入部分 // 健壮性检查 if (输入参数不符合情况) { doing(); return false; } // 初始化:给工作变量赋初值,符合要求的第一次循环条件 int initial_value = 0;// 会被算法初始化的也应该赋初值 // 算法递推 while (工作变量符合算法循环条件) {// 注意考虑最后不足算法增量的部分 doing();// 对结果序列操作的函数 工作变量的迭代;// 注意工作变量在使用完成后已经被污染 } // 收尾 处理不足最后一次算法增量的部分
-
优化(降低重复性)
- 对于多次查找的情况,可以通过建表进行索引。
- 对于多次重复的操作,可以封装一个匿名函数
-
数学归纳法(动态规划核心公式的推导)
- 推导前五个简单的输入和输出,从而假设递进关系式
- 再使用两个进行验证
函数式/无状态编程模板
-
基本理解的角度
- 单向数据流:将多个函数连成“管道”,前一个函数的输出作为后一个函数的输入,依次传递,组成一个线性工作流
- 流水线加工:将原始数据看作“原材料”,每个函数是对原材料的一次加工,使用函数流水线组成一条数据加工的生产线。
-
特点:
-
不可变性:函数式编程通常需要使用不可变的数据结构,即不允许修改数据的原始状态。它强调通过创建新的数据结构来表示修改后的状态。
-
惰性求值:函数式编程通常使用惰性求值,即只在需要时才求值。这样可以避免不必要的计算,提高程序的效率。
-
无副作用:函数式编程也强调避免副作用,即函数执行不应该对外部环境产生影响。本质是函数内部不改变规定数据对象和规定动作范围外的状态。
-
函数作为一等公民:函数与数据地位相同,相互独立(解决了代码本质也是数据)。函数可以像数据一样被传递,赋值和返回。这使得函数式编程具有高阶函数和函数组合等特性。
编程范式 抽象对象 特性 面向过程 计算的运行步骤 数据+算法 = 程序 面向对象 实体的属性和动作 对象的状态和改变自身状态的动作 函数式 数据和动作 值经过动作映射成新值
-
-
设计高效的不可变的数据结构Chris Okasaki 的博士论文https://link.zhihu.com/?target=https%3A//www.cs.cmu.edu/~rwh/theses/okasaki.pdf
-
表观函数和状态转移函数。每一次迭代中,状态转移函数负责将当前这个状态变成下一个状态,而表观函数则负责将状态转化成用户需要看到的值,
状态机编程模板
- 面向对象,符合cpu处理的基本逻辑
常用容器
unordered_map
// 引入头文件
#include <unordered_map>
vector<int> vec = {1,1,3,4,5,5,5};
// 定义unordered_map对象
unordered_map<char, int> umap;
// 增加
for(const auto &i : vec){ // 将vector容器中的元素输入到unordered_map对象中
umap[i]++; // key:有键值i则将其值+1,没有则插入
}
// unordered_map中对于值的访问和更改
unordered_map<char, int>::iterator itr;
for(const auto &c : str){
itr = umap.find(c);
if(itr != umap.end())
doing(itr->second);
}
unordered_set
#include <unordered_set>
using namespace std;
// 定义对象
unordered_set<string> uset;
// 增加
uset.emplace("apple"); // 如果uset中含有相同元素则不添加
// 删除
uset.erase("orange");
// 查找
unordered_set<string>::iterator itr;
itr = uset.find("apple");
if (itr != uset.end()) {
return true;
}
输出字符相关转换
字符串的转换
- 字符转换成字符串
char c = 'c'; string s = ""; // 1. 调用append函数 s.append(1, c); // 2. 使用 += s += c;
- 将
int/float/double
转换成字符串int i = 110; string s = ""; s += to_string(i);
- 将字符串转换成
int
string str = "123"; int num = stoi(str);
- 字符串截取
string str = "Hello, World!"; string sub_str = str.substr(7, 5); // 从第7个开始截取后面5个字符(从0开始计数) cout << sub_str << endl; // 输出 "World"
字符串和十进制的转换
atoi
和itoa
函数// 注意需要包含的头文件 #include <iostream> using namespace std; // string转换成char或者char* char ch[20]; string s="123456"; strcpy(ch,s.c_str()); // c_str()返回的const char * char* p=const_cast<char*>(a_str()); // char *转换为string,直接赋值即可 string s; char* p ="hello"; s = p; // atoi() // 功能:字符串转换成十进制数 // 特点:直到遇上数字或正负符号才开始做转换, // 而再遇到 非数字 或 字符串结束时(’\0’) 才结束转换,并将结果返回 const char *s = " 134"; int num = atoi(s); cout << num; //输出:134 // itoa() // 功能:十进制转换成任意进制的字符串 // 特点:将十进制转换成2~36中任意进制的字符串 int num = 100; char str[25]; itoa(num, str, 2);// 转换成2~36进制的字符串 cout << str; //输出100 // strtol() // 功能:将一个任意2-36进制数转化为long型的10进制数 char str[30] = "1000"; char *substring; long number; number = strtol(str, &substring, 2);
进制数的输出格式
-
在C++语言(hex、oct、itoa)
// 所需头文件 #include <iostream> using namespace std; int num = 0; cin >> hex >> num; cin >> num; cin >> oct>> num; cout << hex <<num<< endl; // 十六进制 cout << num <<endl; // 十进制 cout << oct <<num<<endl; // 八进制 // 二进制 char s[10]; //自定义二进制数的位数,输出位数是实际所需位数 itoa(num,s,2);//转成字符串,进制为2 cout << s <<endl;// 二进制
-
在C语言中
printf("%x",35); //按十六进制格式输出 printf("%d",35); //按十进制格式输出 printf("%o",35); //按八进制格式输出 // 按二进制进行输出 char s[10]; //自定义二进制数的位数,输出位数是实际所需位数 itoa(num,s,2);//转成字符串,基数为2 printf("%s",s);
十进制的二级制形式运算
// 按位与&:全1为1
int AND = 1 & 2; // 01 & 10 = 0b00 = 0
// 按位或|:有1为1
int OR = 1 | 2; // 01 | 10 = 0b11 = 3
// 非运算~:int类型为16位全部取反
~6; // ~0000 0000 0000 0110 = 1111 1111 1111 1001 = 1000 0000 0000 0110+1(保留符号位,全部取反+1) = -7
// 异或运算^:不同为1
// a ^ b ^ a = b;
int XOR = 1 ^ 2; // 01 ^ 10 = 0b11 = 3
// 同或运算 ~(a ^ b):相同为1
int SAME_OR = ~(1 ^ 2); // ~(01 | 10) = 0
// 左移运算(oper << n):向左移1位,末尾添0。相当于十进制乘以2
3 << 1; // 0000 0000 0000 0011 -> 0000 0000 0000 0110 = 3*2 = 6
// 右移运算(oper >> n):向右移1位
(-6 >> 1); // 相当于除以2