理解数据结构 hashtable的简易理解思路

结构图

为了方便演示,下图中分区算法为下标取模

private int hashFun(int id) {
      //使用 hash并取模

      return id % size;
  }

在这里插入图片描述

Hashtable的结构如图所示:是一个数组(元素为各个链表的表头)+ 多个链表组成,也就是说 hashtable 结合了数组和链表的优点。

  • 数组的特点:寻址容易,插入和删除困难
  • 链表的特点:寻址困难,而插入和删除操作容易
  • 哈希表的特点:寻址插入和删除操作都容易

简单的代码实现

该代码实现的功能有分区存储与查找

  • 数据 Emp 的存储:存储时采用ID 取模算法确定数据的存储位置。
  • 数据 Emp的查找:根据 ID 查找数据
public class HashTableDemo {
    public static void main(String[] args) {
        HashTable hashTable = new HashTable(7);
        hashTable.add(new Emp(1, "jack"));
        hashTable.add(new Emp(2, "tom"));
        hashTable.add(new Emp(3, "smith"));
        hashTable.add(new Emp(4, "mary"));
        hashTable.add(new Emp(5, "king"));
        hashTable.add(new Emp(6, "scott"));
        hashTable.add(new Emp(7, "peter"));
        hashTable.add(new Emp(8, "jack1"));
        hashTable.add(new Emp(9, "jack2"));
        hashTable.add(new Emp(10, "jack3"));
        hashTable.add(new Emp(11, "jack4"));
        hashTable.add(new Emp(12, "jack5"));
        hashTable.add(new Emp(13, "jack6"));
        hashTable.add(new Emp(14, "jack7"));
        hashTable.add(new Emp(15, "jack8"));
        hashTable.list();
    }
}

class HashTable {
    /**
     * 数组
     */
    private EmpLinkedList[] empLinkedListArray;
    /**
     * 数组的大小
     */
    private int size;

    public HashTable(int size) {
        this.size = size;
        empLinkedListArray = new EmpLinkedList[size];
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i] = new EmpLinkedList();
        }
    }

    public void add(Emp emp) {
        // 使用散列函数确定放入哪个链表
        int empLinkedListNo = hashFun(emp.id);
        empLinkedListArray[empLinkedListNo].add(emp);
    }

    /**
     * 使用某种算法确定数据的存放位置
     * 这里简单的使用模运算,来确定数据应该落在那个数组元素指定的链表上,
     * 只是一种特例,因为所存的数据包含 ID,所以采用对 ID 取模运算。
     * 更具一般性的算法是使用 哈希函数,对数组大小取模,这里只是个例子。
     *
     * @param id 数组的索引
     * @return
     */
    private int hashFun(int id) {
        //使用 hash并取模

        return id % size;
    }

    public void list() {
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i].list(i);
        }
    }
}

class EmpLinkedList {
    private Emp head;

    public void add(Emp emp) {
        if (head == null) {
            head = emp;
            return;
        }
        Emp temp = head;//游标
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = emp;
    }

    public void list(int no) {
        if (head == null) {
            System.out.println("第" + no + "链表为空");
            return;
        }
        System.out.print("第" + no + "链表信息为:");
        Emp temp = head;
        while (temp != null) {
            System.out.print("id=" + temp.id + " name=" + temp.name + " ");
            temp = temp.next;
        }
        System.out.println();
    }

    public Emp findEmpById(int id) {
        if (head == null) {
            return null;
        }
        Emp temp = head;
        while (temp != null) {
            if (temp.id == id) {
                return temp;
            }
            temp = temp.next;
        }
        return temp;
    }
}

class Emp {
    public int id;
    public String name;
    public Emp next;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }
}

哈希表的理解

可以将每一条链表理解为一个区间,数据按照某种算法添加到与之相适应的区间,也称为分区算法, kafka中 分区的设计思路也是基于此。

这里的算法是对与数据相关的那个属性或者特征值(称为 key)进行某种运算,得到一个唯一的一个数据,该算法的结果决定的所谓的数据落盘。

哈希表的主要功能:

  • 分区存储:对具有相同的特征的数据进行跟组存储。
  • 分区查找:依据数据的特性值,在特定的分组中查找数据,提高了检索的效率。

哈希表名字的由来

为了保证数据查找的唯一性,采用哈希函数才作为分区算法,即是哈希表的由来。

为什么采用哈希函数?

基于哈希函数的性质,所以采用哈希函数作为分区算法。

哈希函数是一种将任意长度的数据映射为固定长度输出的算法。哈希函数广泛应用于计算机科学的多个领域,如数据索引、密码学、数据完整性校验等。以下是哈希函数的主要概念及其性质:

概念

  1. 输入与输出

    • 输入:可以是任意长度的数据(字符串、文件等)。
    • 输出:固定长度的哈希值(通常是固定长度的二进制串或十六进制字符串)。
  2. 用途

    • 数据索引:快速查找数据。
    • 数据完整性校验:检测数据是否被篡改。
    • 密码学:安全地存储密码。
    • 散列表:实现高效的数据结构。

性质

  1. 确定性

    • 对于相同的输入,哈希函数总是产生相同的输出。
    • 这一性质确保了哈希值的可预测性和一致性。
  2. 均匀分布

    • 哈希函数应尽量使不同的输入产生不同的哈希值,以减少冲突。
    • 均匀分布有助于提高哈希表的性能。
  3. 单向性

    • 从哈希值很难反推出原始输入数据。
    • 这一性质在密码学中尤为重要,确保了数据的安全性。
  4. 抗碰撞性

    • 弱抗碰撞性:给定一个输入数据,很难找到另一个不同的输入数据,使得两者的哈希值相同。
    • 强抗碰撞性:很难找到两个不同的输入数据,使得它们的哈希值相同。
    • 抗碰撞性是哈希函数在密码学应用中的关键属性。
  5. 计算效率

    • 哈希函数应具有较高的计算效率,以便在实际应用中能够快速生成哈希值。
  6. 敏感性

    • 即使输入数据有微小的变化,哈希值也会发生显著变化。
    • 这一性质有助于检测数据的微小修改。

常见的哈希函数

  • MD5:128位哈希值,已不再推荐用于安全性要求高的场景。
  • SHA-1:160位哈希值,同样不推荐用于安全性要求高的场景。
  • SHA-256:256位哈希值,广泛用于安全敏感的应用。
  • SHA-3:新一代哈希函数,提供更高的安全性和性能。

哈希表的实质

根据对哈希表的结构和算法分析可知,

  • 哈希表的结构:数组(这里体现了哈希)+链表(这里体现里表);
  • 哈希表的实现逻辑:就是由哈希算法(分区算法)、数组(存放分区首元素)和链表(可以理解为分区)来实现的。

Java 中的 hashtable

public class Hashtable<K,V>
    extends Dictionary<K,V>
    implements Map<K,V>, Cloneable, java.io.Serializable {

    /**
     * The hash table data.
     */
    private transient Entry<?,?>[] table;

    /**
     * The total number of entries in the hash table.
     */
    private transient int count;

    /**
     * The table is rehashed when its size exceeds this threshold.  (The
     * value of this field is (int)(capacity * loadFactor).)
     *
     * @serial
     */
    private int threshold;

    /**
     * The load factor for the hashtable.
     *
     * @serial
     */
    private float loadFactor;

    /**
     * The number of times this Hashtable has been structurally modified
     * Structural modifications are those that change the number of entries in
     * the Hashtable or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the Hashtable fail-fast.  (See ConcurrentModificationException).
     */
    private transient int modCount = 0;

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    @java.io.Serial
    private static final long serialVersionUID = 1421746759512286392L;

    /**
     * Constructs a new, empty hashtable with the specified initial
     * capacity and the specified load factor.
     *
     * @param      initialCapacity   the initial capacity of the hashtable.
     * @param      loadFactor        the load factor of the hashtable.
     * @throws     IllegalArgumentException  if the initial capacity is less
     *             than zero, or if the load factor is nonpositive.
     */
    public Hashtable(int initialCapacity, float loadFactor) {
    }

    /**
     * Constructs a new, empty hashtable with the specified initial capacity
     * and default load factor (0.75).
     *
     * @param     initialCapacity   the initial capacity of the hashtable.
     * @throws    IllegalArgumentException if the initial capacity is less
     *              than zero.
     */
    public Hashtable(int initialCapacity) {
        this(initialCapacity, 0.75f);
    }

    /**
     * Constructs a new, empty hashtable with a default initial capacity (11)
     * and load factor (0.75).
     */
    public Hashtable() {
        this(11, 0.75f);
    }
    /**
     * Constructs a new hashtable with the same mappings as the given
     * Map.  The hashtable is created with an initial capacity sufficient to
     * hold the mappings in the given Map and a default load factor (0.75).
     *
     * @param t the map whose mappings are to be placed in this map.
     * @throws NullPointerException if the specified map is null.
     * @since   1.2
     */
    public Hashtable(Map<? extends K, ? extends V> t) {
        this(Math.max(2*t.size(), 11), 0.75f);
        putAll(t);
    }

}

从源码中可以看出来hashtable 一共提供了 4 个构造方法

  • public Hashtable(int initialCapacity, float loadFactor): 用指定初始容量和指定加载因子构造一个新的空哈希表
  • public Hashtable(int initialCapacity) :用指定初始容量和默认的加载因子 (0.75) 构造一个新的空哈希表
  • public Hashtable():默认构造函数,容量为 11,加载因子为 0.75
  • public Hashtable(Map<? extends K, ? extends V> t):构造一个与给定的Map具有相同映射关系的新哈希表

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/938492.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【YashanDB知识库】kettle同步PG至崖山提示no encryption pg_hba.conf记录

【问题分类】数据导入导出 【关键字】数据同步&#xff0c;kettle&#xff0c;数据迁移&#xff0c;pg_hba.conf 【问题描述】使用kettle同步postgresql至崖山数据库时提示以下报错信息&#xff1a; 【问题原因分析】pg_hba.conf 文件中没有正确配置允许从 IP 地址 连接到数…

记录2024-leetcode-字符串DP

10. 正则表达式匹配 - 力扣&#xff08;LeetCode&#xff09;

UE5制作伤害浮动数字

效果演示&#xff1a; 首先创建一个控件UI 添加画布和文本 文本设置样式 添加伤害浮动动画&#xff0c;根据自己喜好调整&#xff0c;我设置了缩放和不透明度 添加绑定 转到事件图表&#xff0c;事件构造设置动画 创建actor蓝图类 添加widget 获取位置 设置位移 创建一个被击中…

【USB-HID】“自动化键盘“

这里写目录标题 【USB-HID】"自动化键盘"1. 前言2. 框架3. 实现3.1 模拟键盘按键输入 【USB-HID】“自动化键盘” 1. 前言 最近从朋友那了解了一种"自动化键盘"&#xff0c;能够通过上位机录制按键脚本&#xff0c;然后执行脚本&#xff0c;实现物理键盘…

STM32F407ZGT6-UCOSIII笔记4:时间片轮转调度

本文学习与程序编写基于 正点原子的 STM32F1 UCOS开发手册 编写熟悉一下 UCOSIII系统的 时间片轮转调度 文章提供测试代码讲解、完整工程下载、测试效果图 目录 解决上文的卡系统问题&#xff1a; 使能时间片轮转调度&#xff1a; 任务初始化定义更改&#xff1a; 文件结构…

【Flask+OpenAI】利用Flask+OpenAI Key实现GPT4-智能AI对话接口demo - 从0到1手把手全教程(附源码)

文章目录 前言环境准备安装必要的库 生成OpenAI API代码实现详解导入必要的模块创建Flask应用实例配置OpenAI API完整代码如下&#xff08;demo源码&#xff09;代码解析 利用Postman调用接口 了解更多AI内容结尾 前言 Flask作为一个轻量级的Python Web框架&#xff0c;凭借其…

搭建springmvc项目

什么是springmvc MVC它是一种设计理念。把程序按照指定的结构来划分: Model模型 View视图 Controller控制层 springmvc框架是spring框架的一个分支。它是按照mvc架构思想设计的一款框架。 springmvc的主要作用: 接收浏览器的请求数据&#xff0c;对数据进行处理&#xff0c;…

Three.js相机Camera控件知识梳理

原文&#xff1a;https://juejin.cn/post/7231089453695238204?searchId20241217193043D32C9115C2057FE3AD64 1. 相机类型 Three.js 主要提供了两种类型的相机&#xff1a;正交相机&#xff08;OrthographicCamera&#xff09;和透视相机&#xff08;PerspectiveCamera&…

为“行车大脑”降温:Simdroid-EC助力汽车ECU设计研发

ECU&#xff08;Electronic Control Unit&#xff0c;电子控制单元&#xff09;被誉为汽车的行车大脑&#xff0c;在工作时会产生大量的热量&#xff0c;而其散热存在以下难题&#xff1a;一是工作环境恶劣&#xff0c;ECU常处于高温环境中&#xff1b;二是ECU所处的空间较为狭…

改进系列(6):基于DenseNet网络添加TripletAttention注意力层实现的番茄病害图像分类

目录 1. DenseNet 介绍 2. TripletAttention 3. DenseNet TripletAttention 4. 番茄场景病害病虫识别 4.1 数据集情况 4.2 训练 4.3 训练结果 4.4 推理 1. DenseNet 介绍 DenseNet是一种深度学习架构&#xff0c;卷积神经网络&#xff08;CNN&#xff09;的一种变体&…

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库

Ubuntu 20.04LTS 系统离线安装5.7.44mysql数据库 环境下载 MySQL 5.7.44 包安装标题检查服务是否启动成功遇到的问题登陆&修改密码&远程访问 环境 操作系统&#xff1a;Ubuntu 20.04.4 LTS 数据库&#xff1a;MySQL 5.7.34 内核版本&#xff1a;x86_64&#xff08;amd…

0基础学前端-----CSS DAY6

0基础学前端-----CSS DAY6 视频参考&#xff1a;B站Pink老师 今天是CSS学习的第六天&#xff0c;今天开始的笔记对应Pink老师课程中的CSS第三天的内容。 本节重点&#xff1a;CSS的三大特性以及CSS的盒子模型。 1.CSS的三大特性 CSS有三个重要特性&#xff1a;层叠性、继承性…

手写Redis分布式锁+RedisUtil二次封装

文章目录 1.手写Redis分布式锁1.RedisShareLockUtil2.使用方式 2.RedisUtil二次封装1.RedisUtil2.使用案例 1.手写Redis分布式锁 1.RedisShareLockUtil package com.sunxiansheng.redis.util;import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springfra…

Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 预览

文章目录 一、简介二、下载 QtPdfium三、加载 QtPdfium 动态库四、Demo 使用 关于QT Widget 其它文章请点击这里: QT Widget 国际站点 GitHub: https://github.com/chenchuhan 国内站点 Gitee : https://gitee.com/chuck_chee 姊妹篇: Qt WORD/PDF&#x…

IO的入门

目录 1.IO概述1.1流的分类 2.字符流2.1 案例 1.IO概述 IO&#xff08;Input/Output&#xff09;:输入和输出&#xff0c;指的是某个设备或环境进行数据的输入或者输出。例如&#xff1a;键盘的输入&#xff0c;再比如显示器就是输出设备&#xff0c;输出图像。 对于java来说输…

el-table表格嵌套子表格:展开所有内容;对当前展开行内容修改,当前行默认展开;

原文1 原文2 原文3 一、如果全部展开 default-expand-all"true" 二、设置有数据的行打开下拉 1、父table需要绑定两个属性expand-row-key和row-key <el-table:data"tableData":expand-row-keys"expends" //expends是数组&#xff0c;设置…

canal详解及demo

提示&#xff1a;如何保证Redis中的数据与数据库中的数据一致性&#xff1f;数据同步canal的介绍和demo、大型企业如何实现mysql到redis的同步&#xff1f;使用binlog实时更新redis缓存、canal的接入教程、win下canal的服务器端、canal客户端的创建、连接、测试教程、数据同步方…

平方根无迹卡尔曼滤波(SR-UKF)的MATLAB例程,使用三维非线性的系统

本MATLAB 代码实现了平方根无迹卡尔曼滤波&#xff08;SR-UKF&#xff09;算法&#xff0c;用于处理三维非线性状态估计问题 文章目录 运行结果代码概述代码 运行结果 三轴状态曲线对比&#xff1a; 三轴误差曲线对比&#xff1a; 误差统计特性输出&#xff08;命令行截图&…

汇编DOSBox 如何使文件可以运行

1.在vscode编写&#xff08;其他也可以&#xff09;如何在vscode中编写汇编语言并在终端进行调试(保姆级别&#xff09;_如何在vscode编译asm-CSDN博客 2.点击ML615中的DOS 2.1在命令行中输入命令 ml 文件名.asm ml 文件名.obj 2.2 将生成的exe文件移动到Assembly里面 这个文件…

QT多线程(三):基于条件等待的线程同步

在多线程的程序中&#xff0c;多个线程之间的同步问题实际上就是多个线程之间的协调问题。例如在以下例子中只有等 ThreadDAQ 写满一个缓冲区之后&#xff0c;ThreadShow 和ThreadSaveFile 才能读取缓冲区的数据。 int buffer[100]; QReadWriteLock Lock; //定义读写锁变量 v…