最近遇到的问题
计算图
找到一条正确的计算图,其实就是拓扑排序,2年前学过,忘了。。
拓扑排序,每次寻找入度为0的放入队列,然后依次更新子节点的入度,循环,直到退出,贪心的思想。
1 | from collections import deque |
cnn
cnn计算过程,n c h w 输入,kernel是c_out c_in k k,理解一下内部循环计算过程,直观上很简单,写出来还是有点细节需要注意
1 | import numpy as np |
并查集+Kruskal
既然提到了DAG有向无环图,顺带也学习一下最小生成树吧,即找到最短的边,构成一个图,但不能成环
环的问题可以用并查集解决,并查集没什么好说的,直接记模板,union、find两个关键函数,在此基础上,结合贪心,就是Kruskal
1 | from typing import List, Tuple |
A*
提到了图,那就顺带再复习一下经典的Dijkstra和A*吧
A*就是在Dijkstra加上贪心,选择合适的启发式函数,是能够保证最短的(有数学证明)。
常见的启发式函数包括:曼哈顿距离、对角线距离、欧氏距离
1 | import time |
岛屿问题
既然复习到图了,那就再看看经典的岛屿问题吧,顺带复习下BFS和DFS
DFS
1 | from typing import List |
BFS
1 | from typing import List |
1 | from typing import List |
堆的问题
最小堆和最大堆问题,底层红黑树,细节就先管了,topk问题是最小堆问题
一些c++问题
move和forward
move
1 | // 位于 <utility> 头文件中 |
template<typename T>模板参数,类型TT&& t万能引用,接受任意类型std::remove_reference<T>::type&&表示移除掉T的引用,得到T类型本身,也就是type,然后加一个&&,即表示右引用本身- 本质上就是把任意类型的T,不管这个T是左值还是右值,都转换成右值,那么左值和右值到底有什么区别?编译器看到的有区别,左值有地址,右值一般放在寄存器上,作为程序员,我们知道右值是临时变量,主要是拿来移动,可以进行移动构造就够了。
forward
1 | // 位于 <utility> 头文件中 |
-
template<typename T>模板参数,这里必须显示指定,因为需要根据T的类型,去决定返回值 -
typename std::remove_reference<T>::type& t接受一个左值引用的参数 -
static_cast<T&&>(t)把传入的类型t视为T&& 类型 -
本质上,就是根据传入的类型T,永远接受一个左值引用,然后根据T的类型,决定返回左值还是右值
-
应用场景,同时有拷贝构造和移动构造的的时候,用forward可以自动根据参数,决定走哪一个构造函数,而不是统统走拷贝构造,节省性能
-
template<typename F, typename... Args> auto wrapper(F&& f, Args&&... args) { return std::forward<F>(f)(std::forward<Args>(args)...); } std::forward<F>(f) // 第1步:获取一个可调用的对象 ( // 第2步:调用它 std::forward<Args>(args)... // 传入参数 )- 通过这样的wrapper类,它接收任何可调用对象和参数,原封不动地传递给底层函数,同时保持所有类型信息和值类别,实现零开销的抽象
关于c和c++相互调用
这块直接问AI吧,extern c+额外写一层胶水代码,利用void*万能指针
cuda
感觉可以拿来作为入门