哈希桶(详解&创建)

简介: 哈希桶(详解&创建)

一、什么是哈希桶?


       开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址(index = x % array.length()-1),具有相同地址的关键码归于同一子集合,每一个子集合称为一个哈希桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

image.png

编辑

如图,哈希是数组+链表结构,按照传入的元素放在通过散列函数计算出的散列地址处,如果再加入新的相同散列地址则向后通过链表将其链接在一起。

二、创建哈希桶


2.1创建节点以及哈希表。


key:关键码通过散列函数计算出的散列地址

val:节点对应的值

next:向后链接相同散列地址的节点地址

image.png

节点的创建:

static class Node {
    public int key;
    int val;
    Node next;
    public Node(int key,int val) {
        this.key =key;
        this.val = val;
    }
}
public Node[] array;

散列表的创建:

public Node[] array;
public int usedsize;

这里需要了解一个概念:

负载因子:x = 填入表中元素的个数 / 散列表的长度。

负载因子过高会提高哈希冲突率,所以我们想要增加元素并且降低冲突率就得增加散列表的长度

image.png

我们从源码中可以看到,DEFAULT_LOAD_FACTOR是源码默认的负载因子最大值为0.75f,所以我们在模拟创建中也以这个指标去扩展数组的长度 。

image.png

2.2、添加节点


这里代码如下:grow代码在下一个

public void put(int key,int val) {
    int index = key%array.length-1;
    Node cur = array[index];
    while (cur!= null) {
        if (cur.key == key) {
            cur.val = val;
            return;
        }
    }
    Node node = new Node(key,val);
    node.next = array[index];
    array[index] = node;
    usedsize++;
    if (loadFactor() >= DEFAULT_LOAD_FACTOR) {
        grow();
    }
}


2.3、扩容(降低哈希冲突)


这里需要先提前标记下cur的下一个节点,不可以使用cur = cur.next ;因为遍历的cur.next会先把新位置链表的头节点接在cur的后面。

我们默认数组扩容为2倍扩容,并且遍历旧哈希表每一个节点放在新对应的散列地址处,因为数组扩容到了2倍会造成 index = x % array.length()-1 的散列地址改变。

private void grow() {
    Node[] newArray = new Node[array.length*2];
    for (int i = 0; i < array.length; i++) {
        Node cur =array[i];
        while (cur != null) {
            int index = cur.key% newArray.length-1;
            Node next = cur.next;
            cur.next = newArray[index];
            newArray[index] = cur;
            cur = cur.next;
        }
    }
    this.array = newArray;
}


2.4、获取key


通过遍历哈希表来找到对应的节点,如果不存在节点返回-1。

public int get(int key) {
    int index = key % array.length-1;
    Node cur = array[index];
    while (cur != null) {
        if (cur.key == key) {
            return cur.val;
        }
    }
    return -1;
}


2.5、负载因子判断


public float loadFactor() {
    return usedsize*1.0f / array.length;
}

完整代码放在Gitee: [HashBuck · 6442b0c · 404NOt/Repository-1 - Gitee.com]

相关文章
|
存储 缓存 负载均衡
图解一致性哈希算法,看这一篇就够了!
近段时间一直在总结分布式系统架构常见的算法。前面我们介绍过布隆过滤器算法。接下来介绍一个非常重要、也非常实用的算法:一致性哈希算法。通过介绍一致性哈希算法的原理并给出了一种实现和实际运用的案例,带大家真正理解一致性哈希算法。
30367 66
图解一致性哈希算法,看这一篇就够了!
|
机器学习/深度学习 自然语言处理 分布式计算
大规模语言模型与生成模型:技术原理、架构与应用
本文深入探讨了大规模语言模型(LLMs)和生成模型的技术原理、经典架构及应用。介绍了LLMs的关键特点,如海量数据训练、深层架构和自监督学习,以及常见模型如GPT、BERT和T5。同时,文章详细解析了生成模型的工作原理,包括自回归模型、自编码器和GANs,并讨论了这些模型在自然语言生成、机器翻译、对话系统和数据增强等领域的应用。最后,文章展望了未来的发展趋势,如模型压缩、跨模态生成和多语言多任务学习。
2408 3
|
运维 监控 KVM
什么是带内管理 带外管理?(转)
什么叫带外管理?常见的设备管理方式有SNMP、RMON、Web、TELNET以及通过CONSOLE、AUX接口管理,有些高端设备还具备100BASE-TX的带外管理端口。我在网上查到大概SNMP、RMON、Web、TELNET这些管理方式属于带内管理,通过CONSOLE、AUX接口管理和通过某些高端设备具有的100BASE-TX的带外管理端口进行管理的方式属于带外管理。
3392 0
|
监控 Linux
Linux的epoll用法与数据结构data、event
Linux的epoll用法与数据结构data、event
390 0
|
SQL 存储 自然语言处理
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
|
存储 固态存储 内存技术
Long Story of Block - DISCARD
## Concept ### introduction to DISCARD DISCARD 的概念其实来自 SSD 设备。我们知道由于 flash 存储介质的特性,SSD 设备中的一个 block 只支持 write、erase 操作,而不支持 overwrite 操作。对于一个已经被 write 过的 block,如果需要向这个 block 写入新的数据,就必须先对该 block
2350 1
|
编译器 API C++
Visual Studio 2019 处理中文编码字符集
使用 Visual Studio 2019 处理中文编码字符集,统一编码,避免运行时,打印输出,以及编译问题等。
2135 0
Visual Studio 2019 处理中文编码字符集
|
Docker 容器
【registry】docker 私有仓库实现https 访问
【registry】docker 私有仓库实现https 访问
2246 2
【registry】docker 私有仓库实现https 访问
|
存储 前端开发 Java
如何使用 Spring 上传文件:全面指南
如何使用 Spring 上传文件:全面指南
1652 1
|
存储 SQL Oracle
MySQL数据库快速入门到精通(超详细保姆级,建议收藏)这可能是目前最适合你的教程,从基础语法到实例演示。
此文章旨在为需要掌握快速开发和复习MySQL的同学所准备,您完全可以把此文章当作参考文档来使用,本文将尽量精简,使您快速的理解和掌握语法。
1382 0
MySQL数据库快速入门到精通(超详细保姆级,建议收藏)这可能是目前最适合你的教程,从基础语法到实例演示。