首页 > 编程语言 >模拟散列表-java

模拟散列表-java

时间:2024-06-04 17:29:44浏览次数:16  
标签:java int 列表 return static 哈希 new public 模拟

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

前言

一、模拟散列表

二、算法思路

1.散列表

2.拉链法

3.开放寻址法

三、代码如下

1.拉链法代码如下:

 2.开放寻址法代码如下:

3.读入数据

3.代码运行结果

总结


前言

本文主要介绍模拟散列表,并用拉链法和开放寻址法来解决哈希冲突。


提示:以下是本篇文章正文内容,下面案例可供参考

一、模拟散列表

维护一个集合,支持如下几种操作:

  1. I x,插入一个整数 x;
  2. Q x,询问整数 x 是否在集合中出现过;

现在要进行 N 次操作,对于每个询问操作输出对应的结果。

输入格式

第一行包含整数 N,表示操作数量。

接下来 N 行,每行包含一个操作指令,操作指令为 I xQ x 中的一种。

输出格式

对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤N≤100000
−1000000000≤x≤1000000000

二、算法思路

1.散列表

散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。

计算索引的过程被称为 哈希(hash)

比如我们有一个从1到10^9个整数,然后我们有10^5个大小的空间,然后我们从1-10^9个数对10^5进行取余运算,然后得到的余数就是在空间中的位置,我们可以知道例如10^5+1在空间中的位置也是1,1在空间中的位置也是1,发生了冲突,这样就是哈希冲突。我们把对10^5进行取模运算叫做哈希函数

 注:我们对一个数和另一个书进行取模运算,模数尽量是质数且是大于当前数据规模大小的最小的一个质数,这样的冲突是最少的。

2.拉链法

图2.1拉链法示例 

拉链法是我们解决哈希冲突所使用的一种方法。比如我们用哈希函数hash(11) = 3就把11链接在3的位置,hash(23)=3也是放入3的位置,此时呢我们就把23链接在11的后面,故我们我们的每一个位置都是一条链表,故这种方法称为拉链法。

一般我们都是我们都是在散列表中进行增加和查找操作,很少进行删除操作;就算进行删除操作,我们也不是直接删除这个数,而是准备一个标志数组即可。

    //头插法
    public static void insert(int x){
        //因为负数对正数取余还是负数,所以我们加上一个N变成正数
        //k就是我们的哈希值
        int k = ( x % N + N ) % N;
        e[index] = x;
        ne[index] = h[k];
        h[k] = index;
        index++;

    }
    public static boolean query(int x){
        int k = (x % N + N ) % N;
        for(int i = h[k]; i != -1;i = ne[i]){
            if(e[i] == x){
                return true;
            }
        }
        return false;
    }

我们引入一维整型数组h,h[i]为第i个位置单链表的头结点,因为初始链表都为空,都初始化-1,然后我们采用头插法将结点插入链表。具体e数组、ne数组和尾插法、单链表的遍历的详细过程请看这篇博客。https://blog.csdn.net/m0_63267251/article/details/138202017

3.开放寻址法

 图3.1开放定址法示例图

开放寻址法解决冲突比如有10^5个数据,那么数组空间得开数据的2到3倍,这样才会减少冲突。

当h(x) = k的时候,然后第k个位置有元素,那么就往后移一位,如果后面一个位置还有元素,就接着往后移,知道有空白位置放即可。

我们查找也是从第k个位置开始,如果当前位置有人且是x那么我们就找到了x;如果当前位置有人但不是x,那我们就往后一位接着找;如果找到最后是一个空位且之前并没有找到x,就说明没有x。

删除操作我们不会直接把x删掉,而是在数组中打一个特殊的标记,标记一下x有没有删除(不常用)

    public static int find(int x){
        int k = (x % N + N) % N;
        while ( h[k] != x && h[k] != nu){
            k++;
            if(k == N){
                k = 0;
            }
        }
        return k;
    }

我们设置一个整型变量nu,当数组中的值等于nu的时候表示为空,当数组中的值不等于x且不为空时,往后移,当我们k移到最后一个位置,我们再让k从第一个位置开始查找空白位置,我们数组的空间是比较大的,够放置元素。找到了空白是说明没找到元素返回的空白处的数组下标,找到元素了返回的是找到位置的数组下标。

然后插入元素我们直接让 h[find(x)] = x即可。查询元素如果h[find(x)] == nu则说明没有该元素打印No,如果不等则说明找到该元素打印Yes。

 

三、代码如下

1.拉链法代码如下:

import java.io.*;
import java.util.*;
public class 模拟散列表 {
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static int N = 100003;
    //存储每个链表中第一个结点在e数组中的下标
    static int[] h = new int[N];
    //存储链表中的值
    static int[] e = new int[N];
    static int[] ne = new int[N];
    //记录链表中新创建的结点
    static int index = 0;

    public static void main(String[] args)throws Exception {
        int n = nextInt();
        //头结点下标全部初始化为-1
        Arrays.fill(h,-1);
        while (n-- > 0){
            String[] strs = nextLine().split(" ");
            String cmd = strs[0];
            int x = Integer.parseInt(strs[1]);
            if (cmd.equals("I")){
                insert(x);
            } else if (cmd.equals("Q")) {
                if (query(x)){
                    pw.println("Yes");
                }else {
                    pw.println("No");
                }
            }
        }
        pw.flush();
    }
    //头插法
    public static void insert(int x){
        //因为负数对正数取余还是负数,所以我们加上一个N变成正数
        //k就是我们的哈希值
        int k = ( x % N + N ) % N;
        e[index] = x;
        ne[index] = h[k];
        h[k] = index;
        index++;

    }
    public static boolean query(int x){
        int k = (x % N + N ) % N;
        for(int i = h[k]; i != -1;i = ne[i]){
            if(e[i] == x){
                return true;
            }
        }
        return false;
    }
    public static int nextInt()throws Exception{
        st.nextToken();
        return (int)st.nval;
    }
    public static String nextLine()throws Exception{
        return br.readLine();
    }
}

 2.开放寻址法代码如下:


import java.io.*;
import java.util.Arrays;

public class 开放定址法 {
    static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer st = new StreamTokenizer(br);
    static int N = 200003;
    static int[] h = new int[N];
    //如果数组中的数为m,则说明该位置为空
    static int nu = 0x3f3f3f3f;
    public static void main(String[] args) throws Exception{
        Arrays.fill(h,nu);
        int n = nextInt();
        while (n-- > 0){
            String[] strs = nextLine().split(" ");
            String cmd = strs[0];
            int x = Integer.parseInt(strs[1]);
            int k = find(x);
            if (cmd.equals("I")){
                h[k] = x;
            } else if (cmd.equals("Q")) {
                if(h[k] == nu){
                    pw.println("No");
                } else {
                    pw.println("Yes");
                }
            }
        }
        pw.flush();
    }
    public static int find(int x){
        int k = (x % N + N) % N;
        while ( h[k] != x && h[k] != nu){
            k++;
            if(k == N){
                k = 0;
            }
        }
        return k;
    }
    public static void insert(int x){
        int k = (x % N + N) % N;

    }
    public static int nextInt()throws Exception{
        st.nextToken();
        return (int)st.nval;
    }
    public static String nextLine()throws Exception{
        return br.readLine();
    }
}

3.读入数据

5
I 1
I 2
I 3
Q 2
Q 5

3.代码运行结果

Yes
No

总结

上述主要介绍了通过拉链发和开放寻址法来解决哈希冲突和模拟散列表的代码和思路。

标签:java,int,列表,return,static,哈希,new,public,模拟
From: https://blog.csdn.net/m0_63267251/article/details/139425829

相关文章

  • Java实现简易的计算器布局
    其实计算器本身的功能,每个编程语言本身就能实现,比如说我在python中敲击“3+2”的命令,返回值就是5。那么如果需要设计计算器,则关键的部分在于整个的算法页面布局,和功能的逻辑关系,以下我使用Java实现了计算器的布局即简易的功能。定义类Calculator的类,然后在中间添加容器界面,实......
  • 基于Java+Dijkstra算法的地铁线路换乘最短路径项目(免费提供全部源码)
    下载地址如下:基于Java+Dijkstra算法的地铁线路换乘最短路径项目(免费提供全部源码)资源-CSDN文库项目介绍背景随着城市化进程的不断推进,地铁已成为现代大城市公共交通系统的核心组成部分。地铁线路的日益复杂和站点的不断增加,使得乘客在出行时面临换乘路线选择的困扰。为了提......
  • 基于Java的汽车在线销售系统
    你好呀,我是计算机学长猫哥!如果有需求可以文末加我。开发语言:Java数据库:MySQL技术:Java技术工具:IDEA/Eclipse、Navicat、Maven系统展示首页用户信息管理车辆信息管理订单状态管理摘要本文介绍了汽车在线销售系统的设计与实现,该系统基于Java技术开发,采用B/S结......
  • 华为OD机试2024年最新题库(Python、JAVA、C、C++合集)C卷+D卷
    介绍博主介绍:CSDN领军人物top1的作者,全网粉丝30w+,文章累计被阅读3800w+,直接帮助200+,间接帮助800+同学进入od添加或私信博主免费获取本题解析以及代码24年5月份开始,考的都是OD统一考试(D卷),题库已经整理好了,命中率95%以上。5-10月份考的都是D卷真题,都是原题,圈内有多种......
  • JAVA面向对象练习题
    题目要求:        定义图书类(Book),要求有属性name(书名),price(价格),author(作者),对Book类进行封装。在测试类里的主方法中创建3本图书对象,并赋值。创建一个长度为3的Book类数组,在数组里,存放这3个图书对象。题目分析:  图书类Book:    属性:   ......
  • How to use JavaScript BigInt and Number.prototype.toString to handle the super l
    HowtouseJavaScriptBigIntandNumber.prototype.toStringtohandlethesuperlargeintegerproblemsAllInOne如何使用JavaScriptBigInt和Number.prototype.toStringg处理超大整数问题errorsfunctionplusOne(digits:number[]):number[]{letn=parseI......
  • 宝塔面板部署ruoyi-admin_jar(java项目)
    1.创建文件夹,上传jar文件:/www/wwwroot/域名/ruoyi-admin_jar2.点击网站-》添加Java项目3.选择已上传的jar文件-》添加对应域名-》配置后端路径:/prov-api,配置前端路径:/www/wwwroot/域名/dist(其他的默认)4.点击确认,等待一下,尝试访问(报错:404前端路径不对,502端口配置不对,401后端api......
  • JavaFX 常见图表组件
    图表组件简介JavaFX提供了一系列的图表组件,允许开发者在应用程序中轻松集成各种图表和图形。名称中文描述BarChart条形图用于显示条形图,条形图通过水平或垂直的条形来表示数据的大小PieChart饼图用于创建饼图,饼图通过不同扇区的角度来展示数据的比例关系Li......
  • JavaFX 常见事件类型及事件处理
    什么是事件驱动编程事件驱动编程是一种编程范式,其中程序的执行流程是由外部事件(如用户输入、传感器读数、消息接收等)触发的。在这种模式下,程序不是按照预定的顺序执行,而是响应事件来执行代码。这种编程方式在需要处理异步操作或与用户交互的应用程序中非常常见。事件驱动编程广......
  • java中的枚举
    目录定义使用枚举与switch所有枚举类都是Enum的子类枚举类的构造器枚举类可以有成员枚举类可以有抽象方法每个枚举类都有两个特殊的方法定义一个类有多个实例,但是实例的个数不是无穷的,是有限的。枚举类中的实例称为枚举项,一般来说,一个枚举类不应该有太多的枚举项。使用public......