Python数据结构与算法-哈希map的实现及原理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python数据结构与算法-哈希map的实现及原理相关的知识,希望对你有一定的参考价值。

参考技术A

1-collections.MutableMapping

1.1 概念:这是什么?

大家可能想知道这一串英文是什么意思?其实只需要了解在collections库当中有一个非常重要的抽象基类MutableMappin

g,专门用于实现map的一个非常有价值的工具。后边我们会用到它。

2-我们的map基类


2.1 实现这个类

这个基类其实也就是确定了键值对的属性,并且存储了基本的比较方法。它的对象就是一个键值对咯。这个很好理解。有点类似object的感觉。

3-通过map基类实现的无序映射

给大家看一个上边的例子,这个例子来源于网络,自己改了改,能用,更加详细而已,凑合看.

4-Python哈希表的实现的基类

4.1 咱有话直说:上才(代)艺(码)

如果还不知道哈希表概念的同xio,请参考 python进阶之数据结构与算法–中级-哈希表(小白piao分享) 。废话不多说,咱们撸代码:

OK了,基本的哈希表就实现了,其实仔细想想很容易,但是自己要能实现还是要理解哈希表的本质哦,外加一定量的练习才可以熟练掌握,练习的目的就是为了熟练而已。

5-分离链表实现的具体哈希map类

说明:这玩意只是一种降低冲突的手段,上一节提过,降低冲突最好的地方是发生在元组进入桶的时候,所以想必大家猜到了,接下来的分离链表也就是为了self._bucket_xxxxxxx系列方法做准备。这里之所以在上边使用@abstractmethod就是为了继承实现,目的可以实现多种将冲突的哈希表。分离链表的概念上一节也有的。
“见码入面”(借鉴:见字如面这个电视节目,有兴趣可以看看,还不错的):

6-用线性探测处理冲突的哈希map类

这种方式的好处不需要再去借助其他额外的赋值结构来表示桶。结构更加简单。不会再像上一种方法还要让桶是一个UnsortedTableMap的对象。
代码如下:

浅析一致性哈希算法的原理及实现

1.分布式缓存问题


以上是单节点环境下,但随着流量的增大,可能就演变为了如下情形:

这个负载均衡算法该如何设计最为合理呢?
首先能想到的最简单的方法可能就是随机或者轮询,这样会产生两个问题:一是数据冗余;二是数据可能已经被缓存,但请求却命中了不存在该数据的节点上。

如何解决这个问题?只需要保证相同的key被发送给相同节点上即可。再一想这不就是hash算法嘛【index = hash(key) % n】(n为节点的数量)

public class SimpleHash 

    public int loadBalance(String key) 
        return hash(key) % 3;
    
    private int hash(String key) 
        int hash = Math.abs(key.hashCode());
        .....
        .....
        return hash;
    

这种算法它的容错性和扩展性不是很好;一旦某个节点宕机或者加入新的节点时,导致n发生了变化,需要重新hash计算,这样可能导致大量缓存不命中,一瞬间给磁盘数据库造成了很大的压力。

容错性是指当某个节点宕机时,整个系统是否可以继续高效运行;扩展性是指加入新节点时,整个系统是否可以高效运行。

所以这种简单的哈希算法并不适用于实际场景,而本文所讲的一致性哈希算法解决了大量哈希重定位的问题。

2.一致性哈希算法

一致性哈希引入了一个虚拟的圆环,这个圆环有2^32个节点组成(0~ 2^32);

📚它的原理如下:

(1)对每个缓存服务器的IP作为key进行哈希计算,得到的结果一定分布在环上。
(2)对每个数据作为key进行哈希计算,得到的结果也一定分布在环上


按照顺时针,第一台遇到的节点就是该数据定位到的服务器。

❓当节点宕机或者添加新的节点时,它会出现什么样的结果呢?

public class ConsistentHash 
    private static final String[] NODES = "123.23.34.1", "123.52.2.1", "43.122.54.1";
    //模拟环形哈希表
    private static final SortedMap<Integer, String> CIRCLE_Map = new TreeMap<>();
    static 
        for (String node : NODES) 
            int index = hash(node);
            System.out.println(node + "节点的哈希值为:" + index);
            CIRCLE_Map.put(index, node);
        
    
    public static String loadBalance(String key) 
        int index2 = hash(key);
        //返回一个大于或等于index2的map
        SortedMap<Integer, String> tailMap = CIRCLE_Map.tailMap(index2);
        //如果tailMap为空,则直接返回哈希表的第一个数据
        if (tailMap.isEmpty()) 
            return CIRCLE_Map.get(CIRCLE_Map.firstKey());
         else 
            //第一个Key就是顺时针过去离node最近的那个结点
            return CIRCLE_Map.get(tailMap.firstKey());
        
    
    private static int hash(String key) 
        ........
        ........
    

    public static void main(String[] args) 
        System.out.println("zsh被路由到的节点为:" + loadBalance("zsh"));
    

此时可以看到只有一小部分数据进行了重定位,所以它具有很好的容错性和扩展性,❓那么它就没一点问题吗?答案肯定不是的,在某种情况下,会出现节点倾斜的问题。


当节点2宕机之后,数据1和数据2都重定位到了节点3上,节点分布式不均匀会导致数据倾斜的问题

3.引入虚拟节点

解决数据倾斜问题,可以通过增加大量节点使其分布均匀;但是实际上不可行,太浪费钱。所以引入虚拟节点,并将虚拟机节点定位到某个物理节点上即可。

如下图引入v1~v6虚拟节点,并建立与物理节点的映射关系;如定位到v1和v2的数据均定位到节点1上。


带虚拟节点的哈希算法实现

public cl

以上是关于Python数据结构与算法-哈希map的实现及原理的主要内容,如果未能解决你的问题,请参考以下文章

浅析一致性哈希算法的原理及实现

浅析一致性哈希算法的原理及实现

浅析一致性哈希算法的原理及实现

python 学习笔记 -- 数据结构与算法 哈希表 Implementation of a Hash Table

Python算法哈希存储哈希表散列表原理

图片相似度识别:dHash算法