首页 > 编程知识 正文

人工智能经典算法,五大经典算法

时间:2023-05-03 22:49:14 阅读:205864 作者:2605

一致性哈希算法 背景应用

在分布式应用中因为数据量激增是的数据CURD压力变大,所以在数量增长到一定程度后会选择对数据进行分库分表,但是在数据拆分后数据的操作会变的更加麻烦因为数据存储在不同的服务节点上,这样虽然减小数据处理压力但是增加了数据查找的难度。在分布式数据存储中可以应用哈希算法的原理根据每个唯一值的key进行hash然后取模可以得到数据存储服务的的位置,但是这样在每次对哈希表进行扩容时都会重新计算所有节点的hash值并重新放(少数不用移动,因为新旧hash值相同)。所以在基础的hash算法基础上优化出了一致性hash算法,目的是为了大幅度减少hash算法再扩容时带来的额外计算。

原理

初始化一个223-1大小的圆环哈希桶,将第一次所有的服务节点按照唯一值进行hash取模逐一映射到哈希桶中, 这样完成服务节点的初始化。


在存储数据时根据数据的唯一值进行hash取模逐一寻找服务节点进行存储,此处会出现两种情况:
(1)一次hash就映射到服务节点位置直接进行存储;
(2)第一次hash没有映射到服务节点,则按照圆环顺时针进行寻找最近服务节点进行存储。

而在扩容或者宕机时不会再重新计算所有数据,在插入新的服务节点(扩容)时,根据取模思路映射到圆环中,只用重新计算当前新节点的下一个服务节点内部分数据的hash从而大幅度减小rehash带来的性能损耗。而若是有某一服务节点宕机只需要将该节点数据迁移至下一服务节点即可完成修复,而且影响数据很小。

数据倾斜问题

虽然使用哈希算法初始化服务节点但是这样每个服务节点分布不均匀再扩容的时候还是会导致每次迁移的数据量不均匀。所以一致性Hash算法又引入了虚拟节点机制,在初始化和增加服务节点时不再只进行一次hash运算取模才映射到哈希桶内,而是重复多次,在hash桶内存入该节点多个虚拟副本,这样这些节点都是属于该节点,那这样在每个数据节点存储数据是可以做到相对平均。Dubbo的负载均衡就是利用这一思想。

实现 解决方案一:排序+List

第一种思路是:算出所有待加入数据结构的节点名称的Hash值放入一个数组中,然后使用某种排序算法将其从小到大进行排序,最后将排序后的数据放入List中,采用List而不是数组是为了结点的扩展考虑。

之后,待路由的结点,只需要在List中找到第一个Hash值比它大的服务器节点就可以了,比如服务器节点的Hash值是[0,2,4,6,8,10],带路由的结点是7,只需要找到第一个比7大的整数,也就是8,就是我们最终需要路由过去的服务器节点。

如果暂时不考虑前面的排序,那么这种解决方案的时间复杂度:

(1)最好的情况是第一次就找到,时间复杂度为O(1)

(2)最坏的情况是最后一次才找到,时间复杂度为O(N)

平均下来时间复杂度为O(0.5N+0.5),忽略首项系数和常数,时间复杂度为O(N)。

但是如果考虑到之前的排序,我在网上找了张图,提供了各种排序算法的时间复杂度:

解决方案二:遍历+List

解决方案使用List不变,不过可以采用遍历的方式:

(1)服务器节点不排序,其Hash值全部直接放入一个List中

(2)带路由的节点,算出其Hash值,由于指明了"顺时针",因此遍历List,比待路由的节点Hash值大的算出差值并记录,比待路由节点Hash值小的忽略

(3)算出所有的差值之后,最小的那个,就是最终需要路由过去的节点

在这个算法中,看一下时间复杂度:

1、最好情况是只有一个服务器节点的Hash值大于带路由结点的Hash值,其时间复杂度是O(N)+O(1)=O(N+1),忽略常数项,即O(N)

2、最坏情况是所有服务器节点的Hash值都大于带路由结点的Hash值,其时间复杂度是O(N)+O(N)=O(2N),忽略首项系数,即O(N)

所以,总的时间复杂度就是O(N)。其实算法还能更改进一些:给一个位置变量X,如果新的差值比原差值小,X替换为新的位置,否则X不变。这样遍历就减少了一轮,不过经过改进后的算法时间复杂度仍为O(N)。

总而言之,这个解决方案和解决方案一相比,总体来看,似乎更好了一些。

解决方案三:二叉查找树

抛开List这种数据结构,另一种数据结构则是使用二叉查找树。对于树不是很清楚的朋友可以简单看一下这篇文章树形结构。

当然我们不能简单地使用二叉查找树,因为可能出现不平衡的情况。平衡二叉查找树有AVL树、红黑树等,这里使用红黑树,选用红黑树的原因有两点:

1、红黑树主要的作用是用于存储有序的数据,这其实和第一种解决方案的思路又不谋而合了,但是它的效率非常高

2、JDK里面提供了红黑树的代码实现TreeMap和TreeSet

另外,以TreeMap为例,TreeMap本身提供了一个tailMap(K fromKey)方法,支持从红黑树中查找比fromKey大的值的集合,但并不需要遍历整个数据结构。

使用红黑树,可以使得查找的时间复杂度降低为O(logN),比上面两种解决方案,效率大大提升。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。