【数据结构(八)】哈希表

文章目录

  • 1. 基本概念
    • 1.1. 哈希表基本介绍
  • 2. 实例应用
    • 2.1. 思路分析
    • 2.2. 代码实现
      • 2.2.1. 实现添加、显示功能
      • 2.2.2. 实现查找功能


1. 基本概念

先看一个实际需求

google 公司的一个上机题:
    有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的 id 时,要求查找到该员工的 所有信息。要求:不使用数据库,尽量节省内存,速度越快越好-->哈希表(散列)

1.1. 哈希表基本介绍

    散列表(Hash table,也叫哈希表),是根据关键码-值(Key、value)而直接进行访问的数据结构。也就是说,它通过把关键码-值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

在这里插入图片描述

在这里插入图片描述

2. 实例应用

问题:
    有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,名字,住址…),当输入该员工的 id 时,要求查找到该员工的 所有信息。

要求:
    ①不使用数据库,速度越快越好–>哈希表(散列)
    ②添加时,保证按照 id 从低到高插入 (课后思考:如果 id 不是从低到高插入,但要求各条链表仍是从低到高,怎么解决?)
    ③使用链表来实现哈希表,该链表不带表头(即: 链表的第一个结点就存放雇员信息)

2.1. 思路分析

在这里插入图片描述

2.2. 代码实现

2.2.1. 实现添加、显示功能

package hashtable;

import java.util.Scanner;

public class HashTabDemo {
    public static void main(String[] args) {
        // 创建哈希表
        HashTab hashTab = new HashTab(7);

        // 写一个简单菜单
        String key = "";
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("add:添加雇员");
            System.out.println("list:显示雇员");
            System.out.println("exit:退出系统");

            key = scanner.next();
            switch (key) {
                case "add":
                    System.out.println("输入id");
                    int id = scanner.nextInt();
                    System.out.println("输入名字");
                    String name = scanner.next();
                    // 创建雇员
                    Emp emp = new Emp(id, name);
                    hashTab.add(emp);
                    break;
                case "list":
                    hashTab.list();
                    break;
                case "exit":
                    scanner.close();
                    System.exit(0);
                default:
                    break;
            }

        }
    }

}

// 创建 HashTable 管理多条链表
class HashTab {
    private EmpLinkedList[] empLinkedListArray;
    private int size;// 表示有多少条链表

    // 构造器
    public HashTab(int size) {

        this.size = size;
        // 初始化empLinkedListArray
        empLinkedListArray = new EmpLinkedList[size];
        // ?留一个坑:这时不要忘了分别初始化每个链表
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i] = new EmpLinkedList();
        }
    }

    // 添加雇员
    public void add(Emp emp) {
        // 根据员工的id,得到该员工应当添加到哪条链表
        int empLinkedListNo = hashFun(emp.id);
        // 将emp添加到对应的链表中
        empLinkedListArray[empLinkedListNo].add(emp);

    }

    // 遍历所有的链表
    public void list() {
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i].list(i);
        }
    }

    // 编写散列函数,使用一个简单取模法
    public int hashFun(int id) {
        return id % size;
    }
}

// 表示一个雇员
class Emp {

    public int id;
    public String name;
    public Emp next;// 默认为空

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

// 创建 EmpLinkedList, 表示链表
class EmpLinkedList {
    // 头指针,指向第一个Emp,因此我们这个链表的head是直接指向第一个Emp
    private Emp head;// 默认null

    // 添加雇员到链表
    // 说明
    // 1. 假定,当添加雇员是,id 是自增长的,即 id 的分配总是从小到大
    // 因此将该雇员直接加入到本链表的最后即可
    public void add(Emp emp) {

        // 如果是添加第一个雇员
        if (head == null) {
            head = emp;
            return;
        }

        // 如果不是第一个雇员,则使用一个辅助指针,帮助定位到最后
        Emp curEmp = head;
        while (true) {
            if (curEmp.next == null) {// 说明到链表的最后
                break;
            }
            curEmp = curEmp.next;// 后移
        }
        // 退出时,直接将 emp 加入链表
        curEmp.next = emp;
    }

    // 遍历链表的雇员信息
    public void list(int no) {
        if (head == null) {// 说明链表为空
            System.out.println("第 " + (no + 1) + " 链表为空");
            return;
        }
        System.out.print("第 " + (no + 1) + " 链表的信息为:");
        Emp curEmp = head;// 辅助指针
        while (true) {
            System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);
            if (curEmp.next == null) {// 说明curEmp已经是最后节点
                break;
            }
            curEmp = curEmp.next;// 后移,遍历
        }
        System.out.println();
    }
}

运行结果:

在这里插入图片描述

2.2.2. 实现查找功能

代码实现:

package hashtable;

import java.util.Scanner;

public class HashTabDemo {
    public static void main(String[] args) {
        // 创建哈希表
        HashTab hashTab = new HashTab(7);

        // 写一个简单菜单
        String key = "";
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println("add:添加雇员");
            System.out.println("list:显示雇员");
            System.out.println("find:查找雇员");
            System.out.println("exit:退出系统");

            key = scanner.next();
            switch (key) {
                case "add":
                    System.out.println("输入id");
                    int id = scanner.nextInt();
                    System.out.println("输入名字");
                    String name = scanner.next();
                    // 创建雇员
                    Emp emp = new Emp(id, name);
                    hashTab.add(emp);
                    break;
                case "list":
                    hashTab.list();
                    break;
                case "find":
                    System.out.println("请输入要查找的id");
                    id = scanner.nextInt();
                    hashTab.findEmpById(id);
                    break;
                case "exit":
                    scanner.close();
                    System.exit(0);
                default:
                    break;
            }

        }
    }

}

// 创建 HashTable 管理多条链表
class HashTab {
    private EmpLinkedList[] empLinkedListArray;
    private int size;// 表示有多少条链表

    // 构造器
    public HashTab(int size) {

        this.size = size;
        // 初始化empLinkedListArray
        empLinkedListArray = new EmpLinkedList[size];
        // ?留一个坑:这时不要忘了分别初始化每个链表
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i] = new EmpLinkedList();
        }
    }

    // 添加雇员
    public void add(Emp emp) {
        // 根据员工的id,得到该员工应当添加到哪条链表
        int empLinkedListNo = hashFun(emp.id);
        // 将emp添加到对应的链表中
        empLinkedListArray[empLinkedListNo].add(emp);

    }

    // 遍历所有的链表
    public void list() {
        for (int i = 0; i < size; i++) {
            empLinkedListArray[i].list(i);
        }
    }

    // 根据输入的id查找雇员
    public void findEmpById(int id) {
        int empLinkedListNo = hashFun(id);
        Emp emp = empLinkedListArray[empLinkedListNo].findEmpById(id);

        if (emp != null) {// 找到
            System.out.printf("在第 %d 条链表中找到 雇员id = %d\n", (empLinkedListNo + 1), id);

        } else {
            System.out.println("在哈希表中,没有找到该雇员");
        }
    }

    // 编写散列函数,使用一个简单取模法
    public int hashFun(int id) {
        return id % size;
    }
}

// 表示一个雇员
class Emp {

    public int id;
    public String name;
    public Emp next;// 默认为空

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

// 创建 EmpLinkedList, 表示链表
class EmpLinkedList {
    // 头指针,指向第一个Emp,因此我们这个链表的head是直接指向第一个Emp
    private Emp head;// 默认null

    // 添加雇员到链表
    // 说明
    // 1. 假定,当添加雇员是,id 是自增长的,即 id 的分配总是从小到大
    // 因此将该雇员直接加入到本链表的最后即可
    public void add(Emp emp) {

        // 如果是添加第一个雇员
        if (head == null) {
            head = emp;
            return;
        }

        // 如果不是第一个雇员,则使用一个辅助指针,帮助定位到最后
        Emp curEmp = head;
        while (true) {
            if (curEmp.next == null) {// 说明到链表的最后
                break;
            }
            curEmp = curEmp.next;// 后移
        }
        // 退出时,直接将 emp 加入链表
        curEmp.next = emp;
    }

    // 遍历链表的雇员信息
    public void list(int no) {
        if (head == null) {// 说明链表为空
            System.out.println("第 " + (no + 1) + " 链表为空");
            return;
        }
        System.out.print("第 " + (no + 1) + " 链表的信息为:");
        Emp curEmp = head;// 辅助指针
        while (true) {
            System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);
            if (curEmp.next == null) {// 说明curEmp已经是最后节点
                break;
            }
            curEmp = curEmp.next;// 后移,遍历
        }
        System.out.println();
    }

    // 根据 id 查找雇员
    public Emp findEmpById(int id) {
        // 判断链表是否为空
        if (head == null) {
            System.out.println("链表空");
            return null;
        }
        // 辅助指针
        Emp curEmp = head;
        while (true) {
            if (curEmp.id == id) {// 找到
                break;// 这时curEmp就指向要查找的雇员
            }
            // 退出
            if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员
                curEmp = null;
                break;
            }
            curEmp = curEmp.next;// 后移
        }

        return curEmp;
    }
}

运行结果:

在这里插入图片描述

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

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

相关文章

Swing程序设计详解(二)

一 文件标签组与图标 在Swing程序设计中&#xff0c;标签(JLabel)被用于显示文本、图标等内容。在Swing应用程序的用户系面中&#xff0c;用户能够通过标签上的文本、图标等内容获得相应的提示信息。 1.1 JLable标签 标签(JLabel)的父类是JComponent类。虽然标签不能被添加…

写实3D游戏模型纹理贴图设置

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 当谈到游戏角色的3D模型风格时&#xff0c;有几种不同的风格&#xf…

CSU计算机学院2023秋C语言期中题目思路分享(前三道题)

文章目录 写在前面A&#xff1a;个税计算——阅读理解与数据类型转换原题输入输出样例输入样例输出 题目分析题目理解代码实现与问题解决 我的代码 B&#xff1a;时制转换——问题是一点点解决的原题输入输出样例输入样例输出 题目分析我的代码 C&#xff1a;统计进位——人教版…

js基础之事件监听案例入门

事件绑定 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&…

力扣 Java 101.对称二叉树

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 提示&#xff1a; 树中节点数目在…

粒子群优化算法的实践

粒子群优化算法的实践 flyfish 粒子群优化算法&#xff08;Particle Swarm Optimization&#xff0c;PSO&#xff09;或者粒子群算法 红叉的地方是理想之地&#xff0c;这些粒子都想去&#xff0c;总结8个字是信息共享&#xff0c;个人决策。 上完图之后&#xff0c;上代码&a…

【Spring Boot 源码学习】ApplicationContextInitializer 详解

Spring Boot 源码学习系列 ApplicationContextInitializer 详解 引言往期内容主要内容1. 初识 ApplicationContextInitializer2. 加载 ApplicationContextInitializer3. ApplicationContextInitializer 的初始化 总结 引言 书接前文《初识 SpringApplication》&#xff0c;我们…

Python爬虫之重放攻击详解

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 重放攻击是一种网络攻击方式&#xff0c;攻击者通过截获合法用户的请求&#xff0c;并将其重新发送&#xff0c;以模拟合法用户的行为。在Python爬虫领域&#xff0c;了解重放攻击的原理和防范方法至关重要。本文…

DDSP-SVC-3.0完全指南:一步步教你用AI声音开启音乐之旅

本教程教你怎么使用工具训练数据集推理出你想要转换的声音音频&#xff0c;并且教你处理剪辑伴奏和训练后的音频合并一起&#xff0c;快来试试看把&#xff01; 1.使用的工具 要想训练ai声音&#xff0c;首先需要有各种工具&#xff0c;还需要我们提供你需要训练的声音&#…

简单桶排序

#include<stdio.h> int main() { int a[11], i, j, t; for (i 0;i < 10;i) a[i] 0;//初始化为零 for (int i 1;i < 5;i)//循环输入5个数&#xff1b; { scanf("%d", &t);//把每一数读取到变量t中 a[t];/…

淘宝api接口获取商品详情 评论数据

淘宝商品详情评论API接口是一种用于获取淘宝商品详情评论信息的接口。通过联讯数据该接口&#xff0c;开发者可以获取到商品详情页面的评论数据&#xff0c;包括评论内容、评论时间、评论者信息等。 使用淘宝商品详情评论API接口可以方便地获取淘宝平台上大量商品的评价数据&a…

64位Office API声明语句第113讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

1688跨境货源铺货API接口商品采集接口

在跨境电商运营中&#xff0c;不少卖家都会优先选择1688平台产品作为跨境店铺货源。 为帮助卖家提升运营效率&#xff0c;正式上线 1688一键跨境铺货及采购功能&#xff0c;帮助跨境卖家实现选品、铺货及采购一步到位&#xff01; 一键铺货&#xff0c;快速选品 公共参数 名称…

基于Java SSM框架实现汽车在线销售系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现汽车在线销售系统演示 摘要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&a…

Redis滚动分页的使用

Feed流 关注推送也叫Feed流。通过无限下拉刷新获取新的信息。 Feed流产品常见有两种模式&#xff1a; Timeline: 不做内容筛选&#xff0c;简单的按照内容发布时间排序&#xff0c;常用于好友或关注。例如朋友圈 优点&#xff1a;信息全面&#xff0c;不会有缺失。并且实现也…

Multidimensional Scaling(MDS多维缩放)算法及其应用

在这篇博客中&#xff0c;我将与大家分享在流形分析领域的一个非常重要的方法&#xff0c;即多维缩放MDS。整体来说&#xff0c;该方法提供了一种将内蕴距离映射到显性欧氏空间的计算&#xff0c;为非刚性形状分析提供了一种解决方案。当初就是因为读了Bronstein的相关工作【1】…

Java利用UDP实现简单群聊

一、创建新项目 首先新建一个新的项目&#xff0c;并按如下操作 二、实现代码 界面ChatFrame类 package 群聊; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.net.InetAddress; public abstract class ChatFrame extends JFrame { p…

决策树 (人工智能期末复习)

几个重要概念 信息熵&#xff1a;随机事件未按照某个属性的不同取值划分时的熵减去按照某个属性的不同取值划分时的平均 熵。即前后两次熵的差值。 表示事物的混乱程度&#xff0c;熵越大表示混乱程度越大&#xff0c;越小表示混乱程度越小。 对于随机事件&#xff0c;如果它的…

推荐一款Excel快速加载SQL的插件,方便又好用

如果告诉你只需要双击一下&#xff0c;SQL数据库中存放在表里面的数据&#xff0c;就能加载到你的Excel中&#xff0c;你想不想要&#xff1f; 今天给大家推荐一款好用的Excel插件&#xff0c;安装简单&#xff0c;使用方便&#xff0c;是经常使用SQL数据库的不二。 这款插件…

ANYTEXT: MULTILINGUAL VISUAL TEXT GENERATION AND EDITING

ANYTEXT: MULTILINGUAL VISUAL TEXT GENERATION AND EDITING Yuxiang Tuo, Institute for Intelligent Computing, Alibaba Group, ICLR2024 (6668), Code, Paper 1. 前言 基于扩散模型的文本到图像最近取得了令人印象深刻的成就。尽管当前用于合成图像的技术是高度先进的&am…