【数据结构】哈希表(哈希函数+负载因子+解决冲突方法)

news2024/12/24 11:45:05

文章目录

    • 五、哈希表
      • 1.概念
      • 2.哈希函数
        • 1.设计哈希函数:
        • 2.常见的哈希函数
          • 1.直接定址法(常用):
          • 2.除留余数法(常用)
        • 3.负载因子
        • 4.解决冲突
          • 1.闭散列法(开放地址法)
            • 1.线性探测法:冲突的时候,放到下一个空的位置
            • 2.二次探测:
          • 2.开散列法(哈希桶)
        • 5.HashBunk(哈希桶的实现)


五、哈希表

1.概念

  • 查找的时间复杂度:二分查找为 o(N),搜索树为o(log2N) 哈希表为 o(1)
  • 通过关键字Key来快速找到对应的值,不比较,直接找到。
  • 通过一个函数将关键字和存储位置直接建立一一对应的关系,从而避免了不断的比较查找

这种映射的方法叫哈希(散列)方法,函数叫哈希函数,构造的结构叫哈希表(HashTable)

2.哈希函数

hash(key) = key % capacity

capacity是存储空间的大小

在这里插入图片描述

  • 哈希冲突:当两个不同的值,经过哈希函数,得到相同的地址时,发生哈希碰撞
  • 发生冲突的原因:1.存储的容量小于要存储的数量。2.哈希函数的设计不合理
  • 哈希冲突无法解决,只能尽量降低冲突率
1.设计哈希函数:

1.要足够简单

2.计算的地址在空间中均匀分布

3.有m个地址,值域为0到m-1

2.常见的哈希函数
1.直接定址法(常用):

HashKey= A*Key + B 关键字的线性函数

  • 优点:简单、均匀
  • 缺点:需要事先知道关键字的分布情况
  • 场景:查找比较小且连续的数
2.除留余数法(常用)

Hash(key) = key% p(p<=m)

3.负载因子

负载因子 a = 填进表中的元素个数 / 哈希表的长度
在这里插入图片描述

4.解决冲突
1.闭散列法(开放地址法)
1.线性探测法:冲突的时候,放到下一个空的位置
  • 缺点:将冲突的元素放在了一起

在这里插入图片描述

2.二次探测:

在这里插入图片描述

  • 缺点:空间利用率低
  • 解决了线性探测聚到一起的问题
  • 超过0.5要扩容
2.开散列法(哈希桶)
  • 也叫链地址法、开链法
  • 数组+链表 :数组的每个元素就是链表的头结点
  • 数组+链表+红黑树(当数组长度>=64 && 链表长度 >=8 以后,把链表变成红黑树,小于又变回去【树化、解树化】)

在这里插入图片描述

JDK7以前:用头插法存进数组中的链表

JDK8以后:采用尾插法

5.HashBunk(哈希桶的实现)

哈希桶的结构

public class HashBunk {
    static class Node {
        int key;
        int val;
        Node next;

        public Node(int key, int val) {
            this.key = key;
            this.val = val;
        }
    }

    public Node[] array;
    public int usedSize;
    public static final float DEFAULT_LOAD_FACTOR = 0.75f;//负载因子

    public HashBunk() {
        array = new Node[10];
    }
}

哈希桶的插入:采用尾插法实现

 /**
     * 哈希桶的插入
     *
     * @param key
     * @param val
     */
    public void put(int key, int val) {

        int index = key % array.length;
        //找到要插入的链表所在数组的下标标

        Node cur = array[index];
        //遍历index处的链表,看是否存在Key,
        // 存在,跟新val
        //不存在,进行尾插法
        while (cur != null) {
            if (cur.key == key) {
                cur.val = val;//key存在,更新val
                return;
            }
            cur = cur.next;
        }
        if (array[index]==null){
            Node node = new Node(key, val);
            array[index]=node;
            usedSize++;
        }else {
            cur = array[index];
            while (cur.next!=null){
                cur = cur.next;
            }
            //进行尾插法
            Node node = new Node(key, val);
            cur.next = node;
            node.next = null;
            usedSize++;

        }
        //计算当前负载因子
        if (doLoadFactor() > DEFAULT_LOAD_FACTOR) {
            //进行扩容,不光要改变数组的大小,还要重新确定链表的首地址
            //因为之前的首地址是按照之前的容量大小计算出来的。
            resize();
        }
    }

数组大小的扩容,同时要重新确定链表中每个结点的位置

    private void resize() {
        Node[] newArray = new Node[2 * array.length];
        for (int i = 0; i < array.length; i++) {
            //遍历原来的数组
            Node cur = array[i];
            //得到原来数组的首结点
            while (cur != null) {
                //遍历链表
                int newIndex = cur.key % newArray.length;
                Node tmp = cur.next;
                Node node = cur;
                node.next = null;
                if (newArray[newIndex] == null) {
                    newArray[newIndex] = node;
                } else {
                    Node lastNode = getLastNode(newArray[newIndex]);
                    lastNode.next = node;
                }
                cur = tmp;
            }
        }
        array = newArray;
    }

    private Node getLastNode(Node cur) {
        while (cur.next != null) {
            cur = cur.next;
        }
        return cur;
    }

    private float doLoadFactor() {
        return usedSize * 1.0f / array.length;

    }

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

点击移步博客主页,欢迎光临~

偷cyk的图

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker容器启动rabbitmq

docker容器启动rabbitmq 一、RabbitMQ部署1.1.在线拉取mq镜像1.2.运行mq容器1.3.访问mq 二、RabbitMQ的集群2.1.集群分类2.1.设置 /etc/hosts文件 endl 一、RabbitMQ部署 1.1.在线拉取mq镜像 # 在线拉取 docker pull rabbitmq:3-management1.2.运行mq容器 docker run \ -e R…

python爬虫 Appium+mitmdump 京东商品

爬虫系列&#xff1a;http://t.csdnimg.cn/WfCSx 前言 我们知道通过Charles进行抓包可以发现其参数相当复杂&#xff0c;Form 表单有很多加密参数。如果我们只用 Charles 探测到这个接口链接和参数&#xff0c;还是无法直接构造请求的参数&#xff0c;构造的过程涉及一些加密…

Kafka-生产者报错javax.management.InstanceAlreadyExistsException

生产者发送消息到 kafka 中,然后控制台报错 然后根据日志查看 kafka 的源码发现了问题原因 说的是MBean已经注册了,然后报异常了,这样就会导致生产者的kafka注册失败, 原因是项目上生产者没有配置clientId,默认都是空导致的, 多个生产者(项目)注册到kafka集群中的 id 都相同。 …

水泵房远程监控物联网系统

随着物联网技术的快速发展&#xff0c;越来越多的行业开始利用物联网技术实现设备的远程监控与管理。水泵房作为城市供水系统的重要组成部分&#xff0c;其运行状态的监控与管理至关重要。HiWoo Cloud作为专业的物联网云服务平台&#xff0c;为水泵房远程监控提供了高效、稳定、…

SpringCloud(22)之Sentinel实战应用

一、Sentinel核心库 sentinel主页&#xff1a;主页 alibaba/Sentinel Wiki GitHub 1.1 Sentinel介绍 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&…

有趣的前端知识(三)

推荐阅读 有趣的前端知识&#xff08;一&#xff09; 有趣的前端知识&#xff08;二&#xff09; 文章目录 推荐阅读JS内置对象JS外部对象BOM模型history对象screen对象navigator对象 DOM&#xff08;文档对象模型&#xff09;DOM的方法&#xff08;对于节点的操作&#xff09…

Rudolf and the Ball Game

传送门 题意 思路 暴力枚举每一个妆台的转换条件 code #include<iostream> #include<cstdio> #include<stack> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<cstring> #include<ma…

ChatGPT 插件Plugin集合

ChatGPT的插件功能推出一段时间了&#xff0c;陆陆续续的上架了得有200了。 但是其中大部分都不是很好用&#xff0c;并且找起来也复杂。 推荐一个不知名热心人做的导航页。 ChatGPT Plugins Overview 基本上集合了所有的插件&#xff0c;并且还在实时更新中。 需要升级4.0&a…

el-input设置max、min无效的解决方案

目录 一、方式1&#xff1a;type“number” 二、方式2&#xff1a;oninput&#xff08;推荐&#xff09; 三、计算属性 如下表所示&#xff0c;下面为官方关于max&#xff0c;min的介绍&#xff1a; el-input&#xff1a; max原生属性&#xff0c;设置最大值min原生属性&a…

<Senior High School Math>: inequality question

( 1 ) . o m i t (1). omit (1).omit ( 2 ) . ( a 2 − b 2 ) ( x 2 a 2 − y 2 b 2 ) ( x 2 y 2 ) − ( a 2 y 2 b 2 b 2 x 2 a 2 ) ≤ x 2 y 2 − 2 x y ( x − y ) 2 (2). (a^2-b^2)(\frac{x^2}{a^2} - \frac{y^2}{b^2})(x^2y^2)-(\frac{a^2y^2}{b^2}\frac{b^2x^2}{a^…

自然语言处理NLP:tf-idf原理、参数及实战

大家好&#xff0c;tf-idf作为文体特征提取的常用统计方法之一&#xff0c;适合用于文本分类任务&#xff0c;本文将从原理、参数详解和实际处理方面介绍tf-idf&#xff0c;助力tf-idf用于文本数据分类。 1.tf-idf原理 tf 表示词频&#xff0c;即某单词在某文本中的出现次数与…

【刷题】双指针进阶

请看入门篇 &#xff1a;双指针入门 送给我们一句话&#xff1a; 如今我努力奔跑&#xff0c;不过是为了追上那个曾经被寄予厚望的自己 —— 约翰。利文斯顿 双指针进阶 Leetcode 611 有效三角形的个数Leetcode LCR179.查找总价格为目标值的两个商品Leetcode 15.三数之和Thanks…

uniapp中人脸识别图片并圈起人脸

效果如上&#xff0c;我用的是阿里云的人脸识别。首先&#xff0c;我们先封装一个阿里云的请求js文件 faceRecognition.js import CryptoJS from crypto-js//SignatureNonce随机数字 function signNRandom() {const Rand Math.random()const mineId Math.round(Rand * 1000…

UE5 android打包

下载安装JDK https://repo.huaweicloud.com/java/jdk/https://repo.huaweicloud.com/java/jdk/ 选择对应的jdk版本 配置环境变量 编辑Path 验证是否成功 java -version 安装Android Studio https://developer.android.google.cn/studio?hlzh-cnhttps://developer.androi…

EMQX 4.0和EMQX 5.0集群架构实现1亿MQTT连接哪些改进

EMQX 5.0水平扩展能力得到了指数级提升&#xff0c;能够更可靠地承载更大规模的物联网设备连接量。 在EMQX5.0正式发布前的性能测试中&#xff0c;我们通过一个23节点的EMQX集群&#xff0c;全球首个达成了1亿MQTT连接每秒100万消息吞吐&#xff0c;这也使得EMQX 5.0成为目前为…

【C++ 设计模式】简单工厂模式

文章目录 前言一、简单工厂模式是什么&#xff1f;二、实现原理三、UML类图四、简单工厂模式具体代码总结 前言 在软件开发中&#xff0c;设计模式是解决特定问题的可复用解决方案。其中&#xff0c;简单工厂模式是一种创建型设计模式&#xff0c;旨在封装对象的创建过程&…

IDEA开启Run Dashboard

1、Run Dashboard是什么&#xff0c;为什么要使用 Run Dashboard 是 IntelliJ IDEA 中的一个工具窗口&#xff0c;用于管理和监视项目中正在运行的应用程序和配置。它提供了一种集中管理运行和调试过程的方式&#xff0c;可以让开发人员更方便地查看和控制正在运行的应用程序。…

2 Redis的安装与配置

这里是要将 Redis 安装到 Linux 系统中。 1.1 Redis 的安装 1.1.1 克隆并配置主机 修改主机名&#xff1a;/etc/hostname修改网络配置&#xff1a;/etc/sysconfig/network-scripts/ifcfg-ens33 1.1.2 安装前的准备工作 &#xff08;1 &#xff09;安装 gcc &#xff08;2…

如何从 Mac 电脑外部硬盘恢复删除的数据文件

本文向您介绍一些恢复 Mac 外置硬盘数据的快速简便的方法。 Mac 的内部存储空间通常不足以存储所有数据。因此&#xff0c;许多用户通过外部驱动器扩展存储或创建数据备份。然而&#xff0c;与几乎所有其他设备一样&#xff0c;从外部硬盘驱动器丢失有价值的数据并不罕见。由于…

数据库是什么?数据库连接、管理与分析工具推荐

一、数据库是什么&#xff1f; 数据库是一种结构化的数据存储系统&#xff0c;用于有效地组织、存储和管理大量的数据。它是一个集中化的数据存储库&#xff0c;通常由一个或多个数据表组成&#xff0c;每个数据表包含多个行和列&#xff0c;用于存储特定类型的数据。数据表中…