文章目录
- 数据结构
- 分治算法
- 布隆过滤器
- 一致id生成器
- KNN分类算法
- 加密算法
- 分布式一致性算法
- 一致性哈希
- 字典序算法
- 哈希表
- 解决冲突
- 扩容机制
- 树
- 完全二叉树
- 二叉搜索树
- AVL
- 红黑树
- B树
- B+树
- Trie树
- 图
- 图的遍历
- 最短路径算法
- 最小生成树
- 排序
- 快排
- 并查集
- 贪心算法和动态规划
- 字符串
- 字符串查找
数据结构
分治算法
1)计算大数乘法
2)找最大最小值
3)寻找中位数
布隆过滤器
用于检索一个元素是否在一个集合中
数据结构为位图,多个哈希函数,计算出多个哈希值,将相应的哈希值置为1,判断时计算相应的哈希值得到K个值,判断相应K个值的位置上是否为1,如果有一个不为1,则输入对象不在集合中
一致id生成器
Snowflake:根据时间戳和机器id和一定位的序列号生成id
KNN分类算法
输入没有标签的数据后,将这个没有标签的数据的每个特征与样本集中的数据对应的特征进行比较,然后提取样本中特征最相近的数据的分类标签
训练集T中找出与x最相近的k个样本点,把x的类别预测为这k个样本中类别数最多的那一类
加密算法
对称加密:加密和解密使用同一种密钥
计算量小、加密速度快、加密效率高
非对称加密算法:加密解密的过程使用不同的密钥
hash算法:单向,用户可以通过Hash算法对目标信息生成一段特定长度的唯一的Hash值
分布式一致性算法
一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的
竞争上岗,老大保持数据一致
一致性哈希
设置一个圆环,将服务器的ip除以2^32就是服务器在上面的点
防止hash环的倾斜:引入虚拟节点
(1)当后端是缓存服务器时,经常使用一致性哈希算法来进行负载均衡。使用一致性哈希的好处在于,增减集群的缓存服务器时,只有少量的缓存会失效,回源量较小。
(2)尽量减少数据丢失问题,减少移动数据的风险
字典序算法
从右至左找到第一个小于右邻数的数list[a],再从右边往左找第一个右边大于list[a]的第一个值,交换list[a]和list[b]的值,将i以后的元素重新按从小到大的顺序排列
哈希表
解决冲突
开放地址法;链地址法;再哈希法;建立公共溢出区
扩容机制
- STL vector里是次发现loadFactor==1时,就开辟一个原来桶数组的两倍空间(称为新桶数组),然后把原来的桶数组中元素全部转移过来到新的桶数组中(缺点:一次完成需要处理很久)
- Redis对于这一部分,采取的是分摊转移的方式。即当插入一个新元素x触发了扩容时,先转移第一个不为空的桶到新的哈希表,然后将该元素插入。而下一次再次插入时,继续转移旧哈希表中第一个不为空的桶,再插入元素。直至旧哈希表为空为止。这种策略就把第一个hash表所有元素的转移分摊为多次转移,而且每次转移的期望时间复杂度为O(1)
树
完全二叉树
二叉搜索树
若左子树非空其上所有值小于根节点,右子树非空其上所有值大于根节点。如果没有退化为链表,它的查找效率可以为Lgn
AVL
二叉搜索树且左右子树高度差不超过1,查找、插入和删除在平均和最坏情况下都是O(log n),它整体就比较稳定,但是增加或删除操作就可能需要多次旋转树,所以它适合插入或删除次数比较少的情况但查找比较多,比如Linux内核中的进程所用到的虚存空间就是用avl树来保存的,提高每一块虚存的查找速度
红黑树
是一种二叉查找树,必须满足五条性质
- 节点是红色或黑色;
- 根节点是黑色;叶节点是黑色;
- 每个红色节点的两个子节点为黑色;
- 任意节点到每个叶节点路径上包含相同数目的黑节点
它对平衡性没有avl树要求那么严格,它使用非严格的平衡来换取增删节点旋转次数的降低,任何不平衡都会在三次之内到达平衡,所以它的插入删除效率更高
自平衡:变色;左旋;右旋
B树
平衡多路查找树,每个节点拥有多个子节点,减少了树的高度,减少了查找时间,叶子节点都在同一层
B+树
B+的非叶子节点不保存关键字记录的指针,这样使得B+树每个节点所能保存的关键字大大增加
在B树的基础上每个节点存储的关键字数更多,树的层级更少所以查询数据更快,所有指关键字指针都存在叶子节点,所以每次查找的次数都相同所以查询速度更稳定。
应用场景: 用在磁盘文件组织 数据索引和数据库索引
Trie树
用于统计和排序大量的字符串
图
图的遍历
- BFS
- DFS
最短路径算法
1)dijkstra
采用的是一种贪心的策略
- 声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:T
- 初始时,原点 s 的路径权重被赋为 0 ,若对于顶点 s 存在能直接到达的边(s,m),则把dis[m]设为w(s, m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大。初始时,集合T只有顶点s。
- 然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到T中
- 然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。
- 然后,又从dis中找出最小值,重复上述动作,直到T中包含了图的所有顶点
2)Floyed
通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入两个矩阵,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。矩阵P中的元素b[i][j],表示顶点i到顶点j经过了b[i][j]记录的值所表示的顶点
边的权值可以为负数,时间复杂度为O(E)
3)Bellman-ford
dist[]:从original到其他顶点的最短路径长初始为无穷大,自然地,从original到original的距离为0。代表从original到各个顶点的最短路径长度。
pre[]:代表该点在最短路径中的上一个顶点。
1.初始化:除了起点的距离为0外(dist[original] = 0),其他均设为无穷大。
2.迭代求解:循环对边集合E的每条边进行松弛操作,使得顶点集合V中的每个顶点v的距离长逐步逼近最终等于其最短距离长;
3.验证是否负权环:再对每条边进行松弛操作。如果还能有一条边能进行松弛,那么就返回False,否则算法返回True
边的权重可为负数即负权边
4)SPFA算法
用数组dis记录每个结点的最短路径估计值,用邻接表或邻接矩阵来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止
最长路径:不能用dijkstra算法
可用bf算法,把图中每条边的权值取反
可用floyed算法对最长路径也满足最优子结构
拓扑排序+动态规划
最小生成树
(1)kruskal:加边,初始最小生成树边数为0,每迭代依次就选择一条满足条件的最小代价边,并且所选边的两个顶点属于不同的树,然后连接,直到所有顶点在一棵树内
(2)Prim:加点,每次迭代选择代价最小的边对应的点
排序
快排
选取某个数为主元,把前面的树逐一与其比较,小的放前面,大的放后面
1)选择标兵的方式
- 随机
- 三数取中
2)优化:
(1)当待排序序列的长度分割到一定大小后,使用插入排序,对于很小和部分有序的数组,快排不如插排好
(2)尾递归优化:递归调用是当前活跃期内最后一条待执行的语句,于是当这个调用返回时栈帧中并没有其他事情可做,因此也就没有保存栈帧的必要了。通过覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了
(3)聚集元素:在一次分割结束后,可以把与Key相等的元素聚在一起,继续下次分割时,不用再对与key相等元素分割
(4)多线程
并查集
并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。就比如交朋友,我们在是一个朋友圈的人就在同一颗树上,每个元素对应一个节点,每个组对应一棵树。在并查集中,哪个节点是哪个节点的父亲以及树的形状等信息无需多加关注,整体组成一个树形结构才是重要的。类似森林
贪心算法和动态规划
贪心算法并不从整体最优上加以考虑,它所做的选择只是在某种意义上的局部最优解。
动态规划将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
分治法:和动态规划类似,将大问题分解成小问题,但是这些小问题是独立的,没有重复的问题。独立问题取得解,再合并成大问题的解。
比如拿钱,有面值1,3,4的纸币,我要拿6块钱,用贪心就是先拿两张4元,再拿两张1元。
贪心解决不了就用动态规划,一般贪心算法的时间复杂度为O(nlgn),动态规划为O(n^2)或O(n),能用贪心解决就不用动态规划。在用贪心算法前要证明子最优解能构成最优解。
字符串
字符串查找
- kmp:找到每次匹配失败后模板串应移动的有效位数,有效位数就是前缀后缀最长公共元素长度,移动已匹配字符数-失配字符上一位字符对应的长度值,复杂度O(m+n)
- bm:
坏字符规则:从模式串的尾部开始匹配,如果到某一个字符失配了就移动坏字符在模式串中的位置 - 坏字符在模式串中最右出现的位置。若坏字符没有在右边出现就最右位置为-1.
好后缀规则:当字符失配时,后移位数 = 好后缀在模式串中的位置 - 好后缀在模式串上一次出现的位置,且如果好后缀在模式串中没有再次出现,则为 −1 。
移动的位数 = 坏字符在模式串中的位置 - 坏字符在模式串中最右出现的位置
后移位数 = 好后缀在模式串中的位置 - 好后缀在模式串上一次出现的位置
两个规则谁移动得多就选谁 - sunday算法:
跟bm相似,只是他是从前往后匹配,匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。该字符没有在模板串中出现过就直接跳到下下个字符,出现过就将模板串中该字符与匹配字符对齐。
次出现,则为 −1 。
移动的位数 = 坏字符在模式串中的位置 - 坏字符在模式串中最右出现的位置
后移位数 = 好后缀在模式串中的位置 - 好后缀在模式串上一次出现的位置
两个规则谁移动得多就选谁
- sunday算法:
跟bm相似,只是他是从前往后匹配,匹配失败时关注的是文本串中参加匹配的最末位字符的下一位字符。该字符没有在模板串中出现过就直接跳到下下个字符,出现过就将模板串中该字符与匹配字符对齐。 - 暴力查找