21 | 哈希算法(上):如何防止数据库中的用户信息被脱库?
1. 哈希算法要满足什么条件?
(1) 从哈希值不能反向推导出原始数据
(2) 原始数据只修改了一个 Bit,最后得到的哈希值也不相同
(3) 散列冲突的概率要很小
(4) 哈希算法的执行效率要尽量高效,针对较长的文本,也能快速地计算出哈希值。
2. 哈希算法的七个应用
(1) 安全加密,比如:
MD5 消息摘要算法,SHA 安全散列算法,DES 数据加密标准, AES 高级加密标准
(2) 唯一标识,比如:
生成图片的唯一标识。从图片的二进制码串开头取 100 个字节,中间取 100 个字节,最后再取 100 个字节,然后将这 300 个字节放到一块,通过哈希算法(比如 MD5),得到一个哈希字符串,用它作为图片的唯一标识.
(3) 数据校验
通过相同的哈希算法,对下载好的文件块逐一求哈希值,然后跟种子文件中保存的哈希值比对。
(4) 散列函数
为了将一堆数据实现平均分布,以及高效率。
(5) 负载均衡 (6) 数据分片 (7) 分布式存储 : 下一节讲。
3. 如何防止数据库中的用户信息被脱库?、
(1) 通过哈希算法,对用户密码进行加密之后再存储
(2) 引入一个盐(salt),跟用户的密码组合在一起,增加密码的复杂度
22 | 哈希算法(下):哈希算法在分布式系统中有哪些应用?
1. 负载均衡
利用哈希算法替代映射表,可以实现一个会话粘滞的负载均衡策略。(同一个客户端上,在一次会话中的所有请求都路由到同一个服务器上)
2. 数据分片
通过哈希算法对处理的海量数据进行分片,多机分布式处理,可以突破单机资源的限制。
3. 分布式存储
利用一致性哈希算法,可以解决缓存等分布式系统的扩容、缩容导致数据大量搬移的难题。
具体说明查看 404,您访问的页面已经不存在!
https://www.cnblogs.com/moonandstar08/p/5405991.html
23 | 二叉树基础(上)
1. 概念
(1) 满二叉树: 除了叶子节点之外,每个节点都有左右两个子节点。
(2) 完全二叉树:叶子节点都在最底下两层,最后一层的叶子节点都靠左,并且除了最后一层,其他层的节点个数都要达到最大。
(3) 节点的高度:节点到叶子节点的最长路径(边的数目)
(4) 节点的深度:根节点到这个节点所经历的边的个数
(5) 节点的层数:节点的深度+1
(6) 树的高度:根节点的高度
2. 存储二叉树的方法,包括 链式存储法 和 顺序存储法。
(1) 链式存储法
节点有三个字段,一个存储数据,另外两个是指向左右子节点的指针。
大部分二叉树代码都是通过这种结构来实现的。
(2) 顺序存储法
根节点下标为1,左节点下标为2,右节点下标为3,以此类推。
节点 X 存储在数组中下标为 i 的位置
下标为 2 * i 就是左子节点
下标为 2 * i + 1 就是右子节点
下标为 i/2 的就是它的父节点
下标为 0 的存储位置不使用,i从1开始
3. 二叉树的遍历
(1) 前序遍历 : 中左右
(2) 中序遍历 : 左中右
(3) 后序遍历 : 左右中
24 | 二叉树基础(下)
1. 二叉查找树要求定义:
树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。
2. 查找:
从根节点开始,要查找的值比根节点小的话,继续查左节点;要查找的值比根节点大的话,继续查右节点。
3. 插入:
新插入的数据是在叶子节点上的,所以不用考虑太多,遍历下去插入就行。
4. 删除:
分三种情况来处理
(1) 要删除的节点没有子节点的话,只需将其父节点指向它的指针置为null
(2) 有一个子节点,将父节点指向它指针改为指向这个唯一子节点。
(3) 有两个子节点,将右子树中最小的节点,替换到要删除的节点上。
5. 重复数据的二叉查找树
有重复数据的话,可以两种方式处理:
(1) 链表的方式,把值相同的数据都存储在同一个节点上。
(2) 新插入的数据当作大于来处理.
6. 时间复杂度:
跟树的高度成正比,也就是 O(height)
7. 二叉查找树相比散列表的优势:
(1) 输出有序数据: 散列表的数据是无序的,二叉查找树,只需中序遍历就能输出有序数据。
(2) 扩容耗时: 散列表扩容耗时更大。
(3) 复杂程度: 散列表复杂一点,需要考虑散列函数,冲突情况更多。
附:
散列表:插入删除查找都是O(1), 是最常用的,但其缺点是不能顺序遍历以及扩容缩容的性能损耗。适用于那些不需要顺序遍历,数据更新不那么频繁的。
跳表:插入删除查找都是O(logn), 并且能顺序遍历。缺点是空间复杂度O(n)。适用于不那么在意内存空间的,其顺序遍历和区间查找非常方便。
红黑树:插入删除查找都是O(logn), 中序遍历即是顺序遍历,稳定。缺点是难以实现,去查找不方便。其实跳表更佳,但红黑树已经用于很多地方了。
25 | 红黑树(上)
1. 平衡二叉树的定义:
任意一个节点的左右子树的高度相差不能大于 1。
2. 平衡二叉树的价值:
不会出现左子树很高,右子树很矮的情况,插入、删除、查找的操作效率比较高和稳定。
3. 红黑树的定义:
不严格的近似平衡二叉查找树。包含两个意义:
(1) 不严格: 并不完全符合平衡二叉树的定义。
(2) 近似平衡: 性能不会退化得太严重。
4. 红黑树的要求:
(1) 根节点是黑色的
(2) 叶子节点都是黑色的空节点,不存储数据.
(3) 相邻两层的节点不能同时为红色,即:红色节点被黑色节点隔开
(4) 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点
26 | 红黑树(下)
暂时略过
27 | 递归树
1. 借助递归树来分析算法时间复杂度的原因:
(1) 递归树每一层操作消耗的时间总和是一样的
(2) 树的高度 h,乘以每一层的时间消耗 n,就可以得到总的时间复杂度O(n∗h)
2. 以下三个例子可以使用递归树的方式算时间复杂度:
(1) 快速排序
(2) 斐波那契数列
(3) 数据集的 全排列 操作
28 | 堆和堆排序
1. 堆的定义:
(1) 是一个完全二叉树
(2) 每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值
(3) 大于等于子节点的叫大顶堆,小于等于子节点的叫小顶堆。
2. 堆的两个操作: 插入元素 和 删除堆顶元素。 操作完后还要做调整保持堆的特性,叫做“堆化”
(1) 插入元素:
在最后位置插入元素,从下往上做比较和替换操作。
(2) 删除堆顶元素:
删除堆顶元素后,把最后一个元素放到堆顶位置。然后针对堆顶做堆化。
3. 堆排序的操作分两步: 建堆 和 排序
(1) 建堆:
直接把数组视为一个堆(完全二叉树的规则),从数组的后面往前,找第一个非叶子结点,向下做“堆化”。重复直至第一个结点,就完成了建堆。
(2) 排序:
完成建堆后,根节点就是最大的结点,直接和数组最后元素替换(正在做从小到大的排序),然后对剩下的n-1个结点做堆化(也就是最大结点脱离堆)。重复直至只剩下标为 1 的一个元素,排序工作就完成了。
4. 堆排序没有快速排序好的原因:
(1) 快速排序顺序访问数据,对CPU缓存友好。但堆排序不是。
(2) 堆排序数据交换次数更多。因为建堆的过程会打乱数据原有的相对先后顺序,导致原数据的有序度降低。
5. 堆排序比快速排序好的地方:
堆时间复杂度比较固定,O(N*log2N)
快速排序平均情况下是O(N*log2N) ,最坏情况下是O(N平方)
6. 优先级队列定义
队列具有先进先出的特性,而优先级队列是按照优先级来进行处理。要选出优先级最高的元素则可以借助堆来完成。
7. 利用优先队列(即大或小顶堆)自动调整顺序的步骤:
(1) 将n个数组的第一个元素构建优先队列(小顶堆)
(2) 重复下列步骤n*m次:
a. 每次从堆中取出最小元素(堆顶元素),并将其存入输出数组中
b. 用堆顶元素所在数组的下一元素将堆顶元素替换掉
c. 如果数组中元素被取光了,将堆顶元素替换为无穷大。每次替换堆顶元素后,重新调整堆
29 | 堆的应用
1. 优先级队列,具体例子:高性能定时器
把任务按照执行时间,存储在优先级队列中。最优先的先执行,把计算它的执行时间与当前时间的差值。然后就可以根据这个差值作为执行下个任务的等待时间,不需要每秒轮询任务表。
2. 求 Top K:
一直维护一个 K 大小的小顶堆,需要查询当前的前 K 大数据,可以立刻返回
3. 求中位数:
把数据队列用两个堆来维护,分成大顶堆和小顶堆。
逐个数据建堆的时候,持续调整和保证两个堆的数目相同或者相差1,并且保证一个是大根堆一个是小根堆。
大顶堆或小顶堆的头部就是中位数。
4. 求99% 响应时间
把数据根据响应时间,建成两个堆(大顶堆和小顶堆)。大根堆堆顶就是排99%的响应时间值。
插入数据时,值比大根堆顶小的,就放大根堆(这是时间小于第99%的)。否则放小根堆。
5. 取到热门榜 Top 10 的搜索关键词(10 亿个)
把10亿个词求hash值,放到散列表中。散列表就存储了不重复的关键词和出现次数。
再构建大小为10的大顶堆。 获得结果
30 | 图的表示:如何存储微博、微信等社交网络中的好友关系?
1. 图相关概念的定义:
无向图、有向图、带权无向图,邻接矩阵存储法,如下:
邻接表如下:
2. 邻接矩阵存储法优劣点:
优点:查询效率高,方便矩阵运算
缺点:比较浪费空间
3. 邻接表
优点:节省存储空间,
缺点:链表不方便查找,查询效率没有邻接矩阵存储方式高。但可以把链表改为二叉查找树、跳表、散列表来改进。