<<Java>> Hash(哈希表) 你会使用吗?知道底层原理吗?:三分钟一篇学会

简介: <<Java>> Hash(哈希表) 你会使用吗?知道底层原理吗?:三分钟一篇学会

什么是Hash(哈希表)?

① 先确定一个哈希函数:

hash (key) = key % capacity (通常会使用这种求余法,capacity是容量)


② 例子:

假如有一组数据集合:1,7,6,4,5,9 假设hash表容量为10

我们需要存入到哈希表中怎么存储?

0c57b983953e41d492814eba6f88efc3.png


我们将每个元素求到的hash数据存放到 hash表中得到


image.png


③ so?得出的结论


当我们查找元素的时候,只需要根据公式找到hashset的位置就可以直接找到元素的位置


,不必进行多次关键码的比较,搜索的速度比较快。


一般在查找一个元素时,要经过关键码的多次比较。


顺序查找的时间复杂度为 O(N)。平衡树查找的时间复杂度为树的高度,即O(logN)。


理想的搜索方法 : 不经过任何的比较,一次直接从表中得到搜索的元素。 很显然,顺序查找、平衡树查找都不是理性的,而哈希表是-------通过哈希函数是元素的存储位置与关键码之间能够建立起一一映射的关系,那么在查找的时通过该函数就可以直接找到该元素


哈希表插入/删除/查找的时间复杂度都是O(1)

冲突

① 概念(什么是冲突?)

不同的关键字通过 相同的哈希函数 计算出 相同的哈希地址,该现象称之为 哈希冲突 或 哈希碰撞。我们把 不同的关键码 而具有 相同哈希地址 的数据元素称为“ 同义词 ”。


② 冲突出现

  • 出现冲突的一个重要原因:哈希函数设计不够合理。
  • 常见哈希函数:(有很多很多,只列举俩)

        1.直接定制法  

(线性函数) Hash(key)= A*key + B

            使用 场 景 :需要事先知道关键字的分布情况,适合查找比较小且连续的情况

        2.除留余数法

   (上面的例子就是) Hash(key)= key%p (p接近地址数,但不大于地址数)


③ 冲突解决

  • 两种解决方法:闭散列开散列

闭散列(开放地址法)

  • 思想:如果哈希表没有被装满,则为把key存放到冲突位置中的下一个。


探测方法:

               1. 线性探测


                       直接插入到后面没有发生冲突的位置


                       缺陷:容易让产生冲突的元素堆积到一起


               2. 二次探测


                              第一次发生冲突,重新通过哈希函数计算H(i) = (H0+i*i)% m(m是地址数)


                               一直计算,直至计算得到的哈希地址不存在冲突。


开散列(哈希桶)

思想: 使用数组+链表+红黑树的方式,数组里面存放链表的头节点

图示:


image.png


开散列代码实现//重点


// key-value 模型
public class HashBucket {
    private static class Node {
        private int key;
        private int value;
        Node next;
        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }
    private Node[] array;
    private int size; // 当前的数据个数
    private static final double LOAD_FACTOR = 0.75;
    public int put(int key, int value) {
        int index = key % array.length;
// 在链表中查找 key 所在的结点
// 如果找到了,更新
// 所有结点都不是 key,插入一个新的结点
        for (Node cur = array[index]; cur != null; cur = cur.next) {
            if (key == cur.key) {
                int oldValue = cur.value;
                cur.value = value;
                return oldValue;
            }
        }
        Node node = new Node(key, value);
        node.next = array[index];
        array[index] = node;
        size++;
        if (loadFactor() >= LOAD_FACTOR) {    resize();    }
        return -1;
    }
    private void resize() {
        Node[] newArray = new Node[array.length * 2];
        for (int i = 0; i < array.length; i++) {
            Node next;
            for (Node cur = array[i]; cur != null; cur = next) {
                next = cur.next;
                int index = cur.key % newArray.length;
                cur.next = newArray[index];
                newArray[index] = cur;
            }
        }
        array = newArray;
    }
    private double loadFactor() {  return size * 1.0 / array.length;   }
    public HashBucket() {
        array = new Node[8];
        size = 0;
    }
    public int get(int key) {
        int index = key % array.length;
        Node head = array[index];
        for (Node cur = head; cur != null; cur = cur.next) {
            if (key == cur.key) {      return cur.value;    }
        }
        return -1;
    }
}


相关文章
|
4月前
|
监控 Java API
现代 Java IO 高性能实践从原理到落地的高效实现路径与实战指南
本文深入解析现代Java高性能IO实践,涵盖异步非阻塞IO、操作系统优化、大文件处理、响应式网络编程与数据库访问,结合Netty、Reactor等技术落地高并发应用,助力构建高效可扩展的IO系统。
134 0
|
4月前
|
存储 缓存 安全
深入讲解 Java 并发编程核心原理与应用案例
本教程全面讲解Java并发编程,涵盖并发基础、线程安全、同步机制、并发工具类、线程池及实际应用案例,助你掌握多线程开发核心技术,提升程序性能与响应能力。
192 0
|
4月前
|
存储 负载均衡 算法
我们来说一说 Java 的一致性 Hash 算法
我是小假 期待与你的下一次相遇 ~
152 1
|
4月前
|
人工智能 安全 Java
Go与Java泛型原理简介
本文介绍了Go与Java泛型的实现原理。Go通过单态化为不同类型生成函数副本,提升运行效率;而Java则采用类型擦除,将泛型转为Object类型处理,保持兼容性但牺牲部分类型安全。两种机制各有优劣,适用于不同场景。
140 24
|
5月前
|
存储 缓存 Java
我们来详细讲一讲 Java NIO 底层原理
我是小假 期待与你的下一次相遇 ~
190 2
|
5月前
|
XML JSON Java
Java 反射:从原理到实战的全面解析与应用指南
本文深度解析Java反射机制,从原理到实战应用全覆盖。首先讲解反射的概念与核心原理,包括类加载过程和`Class`对象的作用;接着详细分析反射的核心API用法,如`Class`、`Constructor`、`Method`和`Field`的操作方法;最后通过动态代理和注解驱动配置解析等实战场景,帮助读者掌握反射技术的实际应用。内容翔实,适合希望深入理解Java反射机制的开发者。
504 13
|
5月前
|
算法 Java 索引
说一说 Java 并发队列原理剖析
我是小假 期待与你的下一次相遇 ~
|
5月前
|
安全 Java 编译器
JD-GUI,java反编译工具及原理: JavaDecompiler一个Java反编译器
Java Decompiler (JD-GUI) 是一款由 Pavel Kouznetsov 开发的图形化 Java 反编译工具,支持 Windows、Linux 和 Mac Os。它能将 `.class` 文件反编译为 Java 源代码,支持多文件标签浏览、高亮显示,并兼容 Java 5 及以上版本。JD-GUI 支持对整个 Jar 文件进行反编译,可跳转源码,适用于多种 JDK 和编译器。其原理基于将字节码转换为抽象语法树 (AST),再通过反编译生成代码。尽管程序可能带来安全风险,但可通过代码混淆降低可读性。最新版修复了多项识别错误并优化了内存管理。
2740 1
|
5月前
|
存储 算法 安全
Java中的对称加密算法的原理与实现
本文详细解析了Java中三种常用对称加密算法(AES、DES、3DES)的实现原理及应用。对称加密使用相同密钥进行加解密,适合数据安全传输与存储。AES作为现代标准,支持128/192/256位密钥,安全性高;DES采用56位密钥,现已不够安全;3DES通过三重加密增强安全性,但性能较低。文章提供了各算法的具体Java代码示例,便于快速上手实现加密解密操作,帮助用户根据需求选择合适的加密方案保护数据安全。
397 58