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

数据结构与算法-Hash算法-2

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函数非常经典,建议大家收藏,以后都可以用。

    java 复制代码
    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的工作原理。

构造方法:

java 复制代码
HashMap<Integer, String> map = new HashMap<>(); // 创建一个空的HashMap
HashMap<Integer, String> mapWithCapacity = new HashMap<>(16); // 创建一个预设容量的HashMap

put方法:

java 复制代码
map.put(1, "Apple"); // 添加键值对

get方法:

Java 复制代码
String value = map.get(1); // 获取键对应的值

equals方法:

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

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

java 复制代码
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被认为是相等的。

  1. remove方法:

    java 复制代码
    String removedValue = map.remove(1); // 移除键值对并返回值
  2. size方法:

    java 复制代码
    int size = map.size(); // 获取HashMap的大小
  3. isEmpty方法:

    java 复制代码
    boolean isEmpty = map.isEmpty(); // 检查HashMap是否为空

containsKey方法:

java 复制代码
boolean contains = map.containsKey(1); // 判断HashMap是否包含键1
  1. containsValue方法:

    java 复制代码
    boolean containsValue = map.containsValue("Apple"); // 检查HashMap中是否包含指定值
  2. keySet方法:

    java 复制代码
    Set<Integer> keySet = map.keySet(); // 获取HashMap中所有键的Set视图
### values方法:

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

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

    java 复制代码
    map.clear(); // 清空HashMap中的所有键值对
  2. hashCode方法:

    java 复制代码
    Collection<String> values = map.values(); // 获取HashMap中所有值的Collection视图
  3. clone方法:

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

```java
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;
    }
}
```

**注意** :以上代码示例假设`Integer`和`String`是键和值的类型,实际使用时可以替换为任何实现了`equals()`和`hashCode()`方法的对象。
相关推荐
PPPPPaPeR.31 分钟前
TopK问题与堆排序
c语言·开发语言·c++·算法
卡戎-caryon2 小时前
【数据结构】06.栈&&队列
c语言·数据结构·算法·链表
山脚ice2 小时前
【CT】LeetCode手撕—704. 二分查找
算法·leetcode
贱贱的剑2 小时前
【算法】选择排序
算法·rust·排序算法
瑜陀2 小时前
2024.06.30 刷题日记
数据结构·算法·leetcode
Star Patrick2 小时前
*算法训练(leetcode)第二十天 | 39. 组合总和、40. 组合总和 II、131. 分割回文串
c++·算法·leetcode
光久li2 小时前
【算法刷题 | 动态规划14】6.28(最大子数组和、判断子序列、不同的子序列)
算法·动态规划
飘然渡沧海2 小时前
gbk,ucs-2转中文
java·开发语言·算法
raykingl2 小时前
154. 寻找旋转排序数组中的最小值 II(困难)
java·python·算法·二分查找
raykingl2 小时前
69. x 的平方根(简单)
java·python·算法·二分查找