【数据结构】哈希表详解以及代码实现

news2025/9/15 3:10:37

目录

1.来源:

2.哈希函数

1.哈希函数的设计规则

 2.哈希函数的设计思路

3.哈希碰撞

4.解决哈希碰撞的方案

5.负载因子 

3.基于开散列方案的HashMap实现

 1.HashMap类中的属性

2.哈希函数

3.判断当前哈希表中是否含有指定的key值

4.判断当前哈希表中是否包含指定的value值

5.在哈希表中新增,修改元素

6.哈希表扩容

7.删除哈希表中指定的key节点


1.来源:

哈希表来源于数组的随机访问特性

当我们需要查找某个指定元素时,

用链表存储:从链表头遍历到链表尾部,时间复杂度为O(n)

用平衡搜索树存储:时间复杂度为O(logn)

用数组存储,如果知道了元素的索引,那么查找元素的时间复杂度就是O(1)

利用数组的随机访问特性来查找元素,这个思想就是哈希表产生的背景

2.哈希函数

1.哈希函数的设计规则

 2.哈希函数的设计思路

3.哈希碰撞

哈希碰撞是指两个不同的值经过哈希函数计算之后得到相同的值,不论是多优秀的哈希函数,哈希碰撞都不可避免,我们只能尽量降低哈希碰撞出现的概率

取一个素数作为负载因子可以有效降低哈希碰撞的几率

4.解决哈希碰撞的方案

1.闭散列(线性探测):发生冲突时,找冲突旁边的空闲位置放入冲突元素

虽然好想好放,但是因此带来的更大问题,难找更难删,所以一般不采用

2.开散列(链地址法):出现冲突,让冲突的位置变成一个链表

就这样做解决了一部分问题,但随着数据的不断增加,哈希冲突的概率不断增大,在当前数组中,某些链表的长度会很长,查找效率依然下降

解决方案:

1.整个数组扩容,对数组内元素进行搬移,原先冲突的元素大概率不会在冲突

2.将长度过于长的链表转为BST

5.负载因子 

3.基于开散列方案的HashMap实现

 1.HashMap类中的属性

   private static class Node{
        int key;
        int value;
        Node next;

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

    private int size;

    private int M;

    private Node[] data;

    //负载因子
    private static final double LOAD_FACTOR = 0.75;

    public MyHashMap(int capacity) {
        this.data = new Node[capacity];
        this.M = capacity;
    }

    public MyHashMap() {
        this(16);
    }

2.哈希函数

    //哈希函数
    private int hash(int key) {
        return key % this.M;
    }

3.判断当前哈希表中是否含有指定的key值

    //判断当前哈希表中是否含有指定的key值
    public boolean containsKey(int key){
        int index = hash(key);
        for (Node i = data[index]; i != null ; i = i.next) {
            if(i.key == key) {
                return true;
            }
        }
        return false;
    }

4.判断当前哈希表中是否包含指定的value值


    //判断当前哈希表中是否包含指定的value值
    public boolean containsValue(int value) {
        for(int i = 0; i < data.length; i++) {
            for(Node x = data[i]; x != null; x = x.next) {
                if(x.value == value) {
                    return true;
                }
            }
        }
        return false;
    }

5.在哈希表中新增,修改元素

    //在哈希表中新增,修改元素
    public int put(int key, int value) {
        int index = hash(key);
        //判断是否存在
        for(Node x = data[index]; x != null; x = x.next) {
            if(x.key == key) {
                int oldValue = x.value;
                x.value = value;
                return oldValue;
            }
        }
        //此时一定不存在
        Node node = new Node(key,value);
        node.next = data[index];
        data[index] = node;
        size++;
        //判断是否需要扩容
        if(size >= data.length * LOAD_FACTOR) {
            resize();
        }
        return -1;
    }

6.哈希表扩容

    private void resize() {
        this.M = data.length << 1;
        Node [] newData = new Node[M];
        for (int i = 0; i < data.length; i++) {
            for (Node x = data[i]; x != null;) {
                Node next = x.next;
                int newIndex = hash(x.key);
                x.next = newData[newIndex];
                newData[newIndex] = x;
                x = next;
            }
        }
        data = newData;
    }

7.删除哈希表中指定的key节点


    //删除哈希表中指定的key节点
    public boolean removeKey(int key) {
        int index = hash(key);
        //判空
        if(data[index] == null) {
            return false;
        }
        //判断是否为头节点
        if(data[index].key == key) {
            data[index] = data[index].next;
            size--;
            return true;
        }
        Node prev = data[index];
        while (prev.next != null) {
            if(prev.next.key == key) {
                prev.next = prev.next.next;
                size--;
                return true;
            }
        }
        return false;
    }

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

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

相关文章

【尊享版】聊聊我最近比较重要的一些认知升级

超友们&#xff0c;早上好&#xff5e; 今天我为你带来的分享是《聊聊我最近比较重要的一些认知升级》&#xff0c;主要分为三个部分&#xff1a; 一、【10 点战略认知升级】 二、【10 点学习认知升级】 三、【5 点提效认知升级】 &#x1f388;一、【10 点战略认知升级】 …

基于Java+SpringBoot+vue的在线动漫信息平台设计与实现【源码(完整源码请私聊)+论文+演示视频+包运行成功】

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战 &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案例&#xff08;300套&#xff09; 目录 一、效果演示 二、…

一文吃透泛型

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址 如果访问不了Github&#xff0c…

CVE-2017-10271 WebLogic XMLDecoder反序列化漏洞

靶场环境&#xff1a;vulnstack靶机-委派靶场 漏洞描述 CVE-2017-10271漏洞产生的原因大致是Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其中使用了XMLDecoder来解析用户传入的XML数据&#xff0c;在解析的过程中出现反序列化漏洞&#xff0c;导致可执行任…

【RabbitMQ】Spring整合RabbitMQ、Spring实现RabbitMQ五大工作模式(万字长文)

目录 一、准备 1、创建maven项目​编辑 2、引入依赖 3、创建配置文件 1.RabbitMQ配置文件 2.生产者项目配置文件 3.消费者项目配置文件 二、生产者xml中文件创建队列 三、生产者xml文件中创建交换机以及绑定队列 1、创建交换机 2、绑定队列 四、消费者xml文件中创建…

第五十八章 线段树(一)

第五十八章 线段树&#xff08;一&#xff09;一、树状数组的缺陷二、线段树的作用三、线段树的基本构成1、节点定义2、线段树的结构四、线段树的重要函数1、构造线段树——bulid函数2、查询区间——query函数3、单点修改——modify函数五、例题一、树状数组的缺陷 在前面两个…

flink 的 State

目录 一、前言 二、什么是State 2.1&#xff1a;什么时候需要历史数据 2.2&#xff1a;为什么要容错&#xff0c;以及checkpoint如何进行容错 2.3&#xff1a;state basckend 又是什么 三、有哪些常见的是 State 四、 State的使用 五、State backend 5.1 MemoryState…

进程,线程,调度和调度算法基本知识

进程 我们编写的代码只是一个存储在硬盘的静态文件&#xff0c;通过编译后就会生成二进制可执行文件&#xff0c;当我们运行这个可执行文件后&#xff0c;它会被装载到内存中&#xff0c;接着 CPU 会执行程序中的每一条指令&#xff0c;那么这个运行中的程序&#xff0c;就被称…

【C++】内联函数理解

内联函数 内联函数的使用是对于C语言中宏函数的一种改进&#xff0c;他继承了宏的优点并避免了宏的缺点。 宏的优点&#xff1a;a. 代码复用性高 b. 宏函数减少栈帧建立&#xff0c;提高效率 宏的缺点&#xff1a;a. 可读性差 b. 没有类型安全检查 c. 不方便调试 C基本不再建议…

银行数字化转型导师坚鹏:金融数据治理、数据安全政策解读

金融数据治理、数据安全政策解读及大数据应用课程背景&#xff1a; 很多银行存在以下问题&#xff1a; 不知道如何准确理解金融数据治理及数据安全相关政策 不清楚金融数据治理及数据安全相关政策对银行有什么影响&#xff1f; 不清楚如何有效应用金融数据治理及数据安全相关…

软考软件设计师 下午试题二笔记

E-R图基本图形元素 实体 一个实体的存在要以另一个实体存在为前提&#xff0c;这个就是弱实体&#xff0c;比如家属和职工&#xff0c;家属的存在就是依赖于职工 属性 属性带下划线的是主键 联系 三个实体之间的联系 试题二问题一例题 问题二 将er图转成关系模式就是问题二答…

Cell Discovery:人类特异基因促进大脑皮层折叠新机制

在人类进化过程中&#xff0c;新皮层的扩张与智力的提高和认知功能的改善密切相关。这种扩张的一个关键方面是大脑皮层沟回的形成&#xff0c;它使扩张的皮质表面积能够适应有限的颅骨空间。这些进化特征主要依赖于多种神经干细胞和祖细胞亚型及其神经源性分裂产生的更多数量的…

《计算机网络-自顶向下》05. 网络层-控制平面

文章目录路由控制方式每路由控制逻辑集中式控制路由选择算法LS —— 链路状态路由选择算法DV —— 距离向量路由选择算法LS 和 DV 算法的比较自治系统内部路由协议RIPOSPF自治系统外部路由协议&#xff1a;BGP通告 BGP 路由信息选择最好的路由相关术语热土豆选择路由选择算法&a…

Swagger教程

Swagger 目标 Swagger简介【了解】 Springboot整合swagger【掌握】 Swagger 常用注解【掌握】 一、Swagger简介 ​ Swagger 是一系列 RESTful API 的工具&#xff0c;通过 Swagger 可以获得项目的⼀种交互式文档&#xff0c;客户端 SDK 的自 动生成等功能。 ​ Swagger …

TryHackMe-Year of the Owl(Windows渗透测试)

Year of the Owl 当迷宫在你面前&#xff0c;你迷失了方向时&#xff0c;有时跳墙思考是前进的方向。 端口扫描 循例 nmap SMB枚举 smbmap enum4linux也什么都没有 Web枚举 80端口 gobuster扫到一堆403&#xff0c;并没有什么有用的信息 443端口与80端口一致 47001端口依…

【SQL】公网远程访问局域网SQL Server数据库【无公网IP内网穿透】

目录 1.前言 2.本地安装和设置SQL Server 2.1 SQL Server下载 2.2 SQL Server本地连接测试 2.3 Cpolar内网穿透的下载和安装 2.3 Cpolar内网穿透的注册 3.1 Cpolar云端设置 3.2 Cpolar本地设置 4.公网访问测试 5.结语 转发自CSDN远程穿透的文章&#xff1a;[无需公网IP&am…

详解以太坊

以太坊原理 以太坊通过建立终极的抽象的基础层-内置有图灵完备编程语言的区块链-使得任何人都能够创建合约和去中心化应用&#xff0c;并在其中设立他们自由定义的所有权规则、交易方式和状态转换函数。 图灵完备&#xff1a;能够运行非常复杂的运算&#xff0c;最简单的理解…

基于共享储能电站的工业用户日前优化经济调度

目录 1 主要内容 共享电站示意图 目标函数 2 部分程序 3 程序结果 4 程序链接 1 主要内容 该程序方法复现《基于共享储能电站的工业用户日前优化经济调度》算例2和算例3&#xff0c;根据共享储能电站的商业运营模式&#xff0c;将共享储能电站应用到工业用户经济优化调度…

〖Python网络爬虫实战⑨〗- 正则表达式基本原理

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

【Linux】用户命令(创建,修改,切换,删除,密码)

目录 1.创建 查看用户信息 查看id 2.修改 修改用户名 修改用户uid 操作前&#xff1a; 操作后 修改组名 操作前&#xff1a; 操作后: 修改组id 操作前&#xff1a; 操作后&#xff1a; 操作前&#xff1a; 操作后: 3.切换用户 4.删除 操作前&#xff1a; 操作…