数据结构与算法-【算法专项】Hash算法-2(HashMap+设计Hash+Hash应用+Hashmap常用方法)

5 HashMap(又双叒叕提到红黑树动态扩容)

由于链表这种结构确实存在一些缺点,所以在我们的JDK中对之进行了优化,引入了更高效的数据结构:红黑树

  1. 初始大小:HashMap默认的初始大小是16,这个默认值是可以设置的,如果事先知道大概的数据量有多大,可以通过修改默认初始大小,减少动态扩容的次数,这样会大大提高HashMap的性能。

  2. 动态扩容:最大装载因子默认是0.75,当HashMap中元素个数超过0.75*capacity(capacity表示散列表的容量)的时候,就会启动扩容,每次扩容都会扩容为原来的两倍大小。

  3. Hash冲突解决办法:JDK1.7底层采用链表法。

    在JDK1.8版本中,为了对HashMap做进一步优化,我们引入了红黑树。而当链表长度太长(默认超过8)时,链表就转换为红黑树。我们可以利用红黑树快速增删改查的特点,提高HashMap的性能。当红黑树结点个数少于8个的时候,又会将红黑树转化为链表。因为在数据量较小的情况下,红黑树要维护平衡,比起链表来,性能上的优势并不明显。

  4. Hash函数:JDK的hash函数非常经典,建议大家收藏,以后都可以用。

    int hash(Object key) {
     int h = key.hashCode()return (h ^ (h >>> 16)) & (capitity -1); //capicity表示散列表的大小,最好使用2的整数倍
    }
    

6 如何设计Hash

假如你在面试中碰到了要你如何设计一个高效的企业级Hash表。你该如何处理?

这里大家可以借鉴HashMap 的设计思路:

  1. 必须要高效:即插入,删除 查找必须要快
  2. 内存:不能占用太多的内存,考虑用其他的结构,比如B+Tree,HashMap 10亿,存硬盘的算法:mysql B+tree
  3. Hash函数:这个要根据实际情况考虑.%
  4. 扩容:就是预估数据的大小,HashMap 默认的空间是16? 我知道我要存10000个数,2^n > 10000 or 2^n-1
  5. Hash冲突后怎么解决:链表 数组。

7 Hash的应用

  1. 加密:MD5 哈希算法。还是存在密码冲突 128位的二进制串,可以表示2^128次,md5(md5(),”1231”),b不可逆,建了一个hash库,存起来了。 Md5(88888888),穷举

  2. 怎么判断视频是否是重复的?Md5();128位

  3. 相似性检测:论文检测,指纹算法。会把每个论文计算出一个指纹,汉明距离。

  4. 负载均衡:nginx,2台服务器;可以根据ip计算hash,再做一个取模2运算。

  5. 分布系统:数据分库问题。我不是讲过一个10亿的数据的搜索词,一台机器存不下。要分成10个文件。Hash(key)%10 = > 就可以知道某个key在哪一个文件?扩大成数据库的 分表(10张表) id%10 =()。

  6. 分布式存储的时候:问题来了 如果我加了一张表。原来是10张,现在是11张了 怎么办?要重新计算,分配的时候查询怎么办?数据量很大,迁移的不是太多了吗?

  7. 查找算法:hashMap 查找如何设计出自己的一个hash查找算法呢?快,hash冲突要少,数据大小。初始大小,扩容

  8. 一致性Hash:哈希环

    假设我们有k个表,数据的hash值范围:[0,Integer.max].我们把整个数据范围划分成n个区间(n个区间要远远大于我们的k),每一个表就是分配到n/k的区间。当有新的表要来了,我们只需要将某几个小的区间数据迁移就可以了。这是一个环形结构,其根本思想就是分段了。

重点部分:数组 链表 二叉树 红黑树 HashMap源码

8 HashMap源码(又双叒叕)

HashMap是Java集合框架中的一个重要类,用于存储键值对。

HashMap的一些核心常用方法的简要说明和示例代码,具体细节可能涉及到哈希碰撞、加载因子、扩容等实现细节,这些通常不需要开发者手动实现,但了解这些细节有助于更好地理解HashMap的工作原理。

  1. 构造方法:

    HashMap<Integer, String> map = new HashMap<>(); // 创建一个空的HashMap
    HashMap<Integer, String> mapWithCapacity = new HashMap<>(16); // 创建一个预设容量的HashMap
    
  2. put方法:

    map.put(1, "Apple"); // 添加键值对
    
  3. get方法:

    String value = map.get(1); // 获取键对应的值
    
  4. equals方法:

    在Java中,HashMapequals方法用于比较两个HashMap对象是否相等。equals方法首先会检查两个对象的hashCode是否相等,如果hashCode不等,那么两个对象不可能相等,如果hashCode相等,那么HashMap会进一步比较其中的元素。

    以下是HashMapequals方法的核心代码:

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Map))
            return false;
        Map<?,?> m = (Map<?,?>) o;
        if (m.size() != size())
            return false;
        try {
            Iterator<Entry<K,V>> i = entrySet().iterator();
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key)==null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }
        return true;
    }
    

    这段代码首先检查o是否等于this,如果是,则直接返回true。然后检查o是否是一个Map实例。如果不是,则直接返回false。如果是,HashMap会比较其大小,如果两个Map的大小不等,则直接返回false。接下来,HashMap会迭代其所有的Entry,并逐一检查o中是否包含相同的键值对。如果有任何一个键值对不匹配,则返回false。如果所有的键值对都匹配,则返回true

    这个方法是HashMap对象相等性的核心实现,它确保了两个具有相同键值对的HashMap被认为是相等的。

  5. remove方法:

    String removedValue = map.remove(1); // 移除键值对并返回值
    
  6. size方法:

    int size = map.size(); // 获取HashMap的大小
    
  7. isEmpty方法:

    boolean isEmpty = map.isEmpty(); // 检查HashMap是否为空
    
  8. containsKey方法:

    boolean contains = map.containsKey(1); // 判断HashMap是否包含键1
    
  9. containsValue方法:

    boolean containsValue = map.containsValue("Apple"); // 检查HashMap中是否包含指定值
    
  10. keySet方法:

    Set<Integer> keySet = map.keySet(); // 获取HashMap中所有键的Set视图
    
  11. values方法:

    Collection<String> values = map.values(); // 获取HashMap中所有值的Collection视图
    
  12. entrySet方法:

    Set<Map.Entry<Integer, String>> entrySet = map.entrySet(); // 获取HashMap中所有键值对的Set视图
    
  13. clear方法:

    map.clear(); // 清空HashMap中的所有键值对
    
  14. hashCode方法:

    Collection<String> values = map.values(); // 获取HashMap中所有值的Collection视图
    
  15. clone方法:

  16. hash方法(用于自定义对象作为键时):

    public class MyKey {
        int value;
        // 必须重写hashCode方法
        @Override
        public int hashCode() {
            return Objects.hash(value);
        }
        // 必须重写equals方法
        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;
            MyKey myKey = (MyKey) obj;
            return value == myKey.value;
        }
    }
    

    注意:以上代码示例假设IntegerString是键和值的类型,实际使用时可以替换为任何实现了equals()hashCode()方法的对象。

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yinying293

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值