斐波那契散列和hashMap实践

news2025/1/24 2:26:08

斐波那契散列和hashMap实践

适合的场景:抽奖(游戏、轮盘、活动促销等等)

如果有不对的地方,欢迎指正!

HashMap实现数据散列:

配置项目,引入pom.xml:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.58</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.5</version>
</dependency>

前置条件:

  1. 存放数组:128位
  2. 100个数据进行散列
  3. 若有hash冲突,使用拉链法

首先,初始化100个随机数,这里采用雪花算法snowFlake,采用灵活注解引用,声明为Component,

简单了解下SnowFlake工具类实现方式:

import com.example.containstest.containsTestDemo.mapper.FileNameAndType;
import com.example.containstest.containsTestDemo.mapper.FileNameInsertMapper;
import com.example.containstest.containsTestDemo.pojo.DatagenertionDao;
import com.example.containstest.containsTestDemo.pojo.FileNameType;
import com.example.containstest.containsTestDemo.utils.SnowFlake;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@Component
public class SnowFlake implements IIdGenerator {

    private Snowflake snowflake;

    @PostConstruct
    public void init(){
        // 0 ~ 31 位,可以采用配置的方式使用
        long workerId;
        try {
            workerId = NetUtil.ipv4ToLong(NetUtil.getLocalhostStr());
        }catch (Exception e){
            workerId = NetUtil.getLocalhostStr().hashCode();
        }
        workerId = workerId >> 16 & 31;
        long dataCenterId = 1L;
        snowflake = IdUtil.createSnowflake(workerId,dataCenterId);
    }


    @Override
    public long nextId() {
        return snowflake.nextId();
    }
}

循环100,取其随机数保存列表中:

List<String> list = new ArrayList<>();
//保存idx和重复的值
Map<Integer, String> map = new HashMap<>();
for(int i = 0; i < 101; i++){
    list.add(String.valueOf(snowFlake.nextId()));
}

创建数据散列到的数组大小,这里取128

//定义要存放的数组 模拟初始化为128
String[] res = new String[128];

遍历保存的数组,计算出当前数值的hash值,然后到数组对应的下标处对应;

  1. 为空。当前key赋值到该数组下标值
  2. 不为空,表示hash冲突,这里采用字符串拼接模拟碰撞后使用的拉链法
  3. map存储对应idxkey
  4. 对重复的散列的值进行排序输出
for(String key : list){
    //计算hash值,未使用扰动函数
    int idx = key.hashCode() & (res.length - 1);
    log.info("key的值{},idx的值{}",key,idx);
    if(null == res[idx]){
        res[idx] = key;
        continue;
    }
    res[idx] = res[idx] +"->" + key;
    map.put(idx,res[idx]);
}
//排序
mapSort(map);

map排序:

private void mapSort(Map<Integer, String> map) {
    // 按照Map的键进行排序
    Map<Integer, String> sortedMap = map.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .collect(
                    Collectors.toMap(
                            Map.Entry::getKey,
                            Map.Entry::getValue,
                            (oldVal, newVal) -> oldVal,
                            LinkedHashMap::new
                    )
            );
    log.info("====>HashMap散列算法碰撞数据:{}",JSON.toJSONString(sortedMap));
}

未使用扰动函数HashMap散列输出结果展示:

{
    28: "1596415617815183397->1596415617815183430",
    29: "1596415617815183398->1596415617815183431",
    30: "1596415617815183399->1596415617815183432",
    59: "1596415617815183363->1596415617815183440",
    60: "1596415617815183364->1596415617815183441",
    61: "1596415617815183365->1596415617815183442",
    62: "1596415617815183366->1596415617815183443",
    63: "1596415617815183367->1596415617815183400->1596415617815183444",
    64: "1596415617815183368->1596415617815183401->1596415617815183445",
    65: "1596415617815183369->1596415617815183402->1596415617815183446",
    66: "1596415617815183403->1596415617815183447",
    67: "1596415617815183404->1596415617815183448",
    68: "1596415617815183405->1596415617815183449",
    90: "1596415617815183373->1596415617815183450",
    91: "1596415617815183374->1596415617815183451",
    92: "1596415617815183375->1596415617815183452",
    93: "1596415617815183376->1596415617815183453",
    94: "1596415617815183377->1596415617815183410->1596415617815183454",
    95: "1596415617815183378->1596415617815183411->1596415617815183455",
    96: "1596415617815183379->1596415617815183412->1596415617815183456",
    97: "1596415617815183413->1596415617815183457",
    98: "1596415617815183414->1596415617815183458",
    99: "1596415617815183415->1596415617815183459",
    121: "1596415617815183383->1596415617815183460",
    125: "1596415617815183387->1596415617815183420",
    126: "1596415617815183388->1596415617815183421",
    127: "1596415617815183389->1596415617815183422"
}

针对上述代码,修改int idx = key.hashCode() & (res.length - 1);为下面:

int idx =  (res.length - 1) & (key.hashCode() ^ (key.hashCode() >>> 16));

使用扰动函数HashMap散列输出结果展示:

{
    44: "1596518378456121344->1596518378456121388",
    67: "1596518378460315650->1596518378460315694",
    72: "1596518378456121351->1596518378456121395",
    73: "1596518378456121350->1596518378456121394",
    83: "1596518378456121345->1596518378456121389",
    92: "1596518378460315651->1596518378460315695",
    93: "1596518378460315652->1596518378460315696"
}

从对比结果可以看到,加入扰动函数后hash碰撞减少了很多。

斐波那契散列算法

前置条件:

  1. 生成模拟数据:随机且不重复的100个数
  2. 声明散列数组:大小128
  3. 若有hash冲突,保存map,方便数据查看

静态变量声明:

//黄金分割点
private static final int HASH_INCREMENT = 0x61c88647;
private static int range = 100;

按照惯例,初始化数组,模拟数据;

List<Integer> listThreadLocal = new ArrayList<>();

Map<Integer, String> map = new HashMap<>();
//定义要存放的数组 模拟初始化为128
Integer[] result = new Integer[128];
result = getNumber(range);
//......

//-----方法
/**
 * 随机生成100以内不重复的数
 * @param total
 * @return
 */
public static Integer[] getNumber(int total){
    Integer[] NumberBox = new Integer[total];			//容器A
    Integer[] rtnNumber = new Integer[total];			//容器B

    for (int i = 0; i < total; i++){
        NumberBox[i] = i;		//先把N个数放入容器A中
    }
    Integer end = total - 1;

    for (int j = 0; j < total; j++){
        int num = new Random().nextInt(end + 1);	//取随机数
        rtnNumber[j] = NumberBox[num];			//把随机数放入容器B
        NumberBox[num] = NumberBox[end];			//把容器A中最后一个数覆盖所取的随机数
        end--;									//缩小随机数所取范围
    }
    return rtnNumber;							//返回int型数组
}

遍历模拟的数据,通过源码阅读,可以找到new ThreadLocal<String>().set("xbhog");

注意点,threadLocal实现主要是在ThreadLoacalMap中

img

//2
private final int threadLocalHashCode = nextHashCode();
//4  默认值0
private static AtomicInteger nextHashCode = new AtomicInteger();
//3步骤使用
private static final int HASH_INCREMENT = 0x61c88647;

//3
private static int nextHashCode() {
    return nextHashCode.getAndAdd(HASH_INCREMENT);
}

//key和len是外部传入  1
int i = key.threadLocalHashCode & (len-1);

可以看到每次计算哈希值的时候,都会加一次HASH_INCREMENT黄金分割点,来更好的散列数据,然后模拟该操作:代码如下

for(int i = 0; i < listThreadLocal.size(); i++){
    hashCode = listThreadLocal.get(i) * HASH_INCREMENT + HASH_INCREMENT;
    Integer idx = (hashCode & 127);
    log.info("key的值{},idx的值{}",listThreadLocal.get(i),idx);
    if(null == result[idx]){
        result[idx] = listThreadLocal.get(i);
        continue;
    }
    String idxInRes = map.get(idx);
    String idxInRess = idxInRes + "->" + listThreadLocal.get(i);
    map.put(idx,idxInRess);
}

进行冲突后重复值排序

//map排序
if(CollectionUtil.isEmpty(map)){
    log.info("斐波那契额散列数据集:{}",JSON.toJSONString(result));
    System.out.println("===》无重复数据,不需要排序");
    return;
}
mapSort(map);

使用斐波那契散列算法输出结果展示:

斐波那契额散列数据集:38,15,29,22,55,86,70,64,47,32,67,7,60,85,97,95,58,46,14,83,12,72,18,96,36,20,76,59,6,33,50,30,23,42,81,31,66,71,82,61,53,84,41,45,74,63,89,77,90,16,8,37,1,62,65,99,51,78,91,39,5,57,27,56,44,13,92,25,0,24,80,3,94,26,40,34,73,35,88,2,87,11,93,54,69,68,10,17,43,48,19,9,79,21,98,52,4,28,75,49]
===》无重复数据,不需要排序

由上我们可以看到,没有重复的数据,全部比较完美的散列到不同的地方。

参考文章:

https://blog.csdn.net/qq_26327971/article/details/104757316

https://juejin.cn/post/6844903985808146439

https://juejin.cn/user/3913917126415166

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

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

相关文章

排序算法-冒泡排序

基本思路 遍历给定的数组&#xff0c;从左往右&#xff0c;两两比较&#xff0c;小的放在左边&#xff0c;大的放在右边&#xff0c;遍历完成&#xff0c;数组有序。 先来看一个冒泡排序的过程&#xff1a; 给定数组&#xff1a;[5,3,2,1,4] 排序结果&#xff1a;[1,2,3,4,5…

Sha1,Sha256 哈希(摘要)处理

具体参考&#xff1a;Sha1,Sha256哈希&#xff08;摘要&#xff09;在线处理工具

显示今天的年、月、日日期、时间的数据处理timetuple()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 显示今天的年、月、日 日期、时间的数据处理 timetuple() [太阳]选择题 对下面描述错误的选项为&#xff1f; import datetime dtdatetime.date.today() print("【显示】dt",dt) p…

Redis最全详解(三)——SpringBoot整合2种方式

SpringBoot整合Redis 常用 api 介绍 有两个 redis 模板&#xff1a;RedisTemplate 和 StringRedisTemplate。我们不使用 RedisTemplate&#xff0c;RedisTemplate 提供给我们操作对象&#xff0c;操作对象的时候&#xff0c;我们通常是以 json 格式存储&#xff0c;但在存储的…

[附源码]java毕业设计作业自动评阅系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【window下配置Maxim SDK环境】

【window下配置Maxim SDK环境】1. 前言2. Maxim SDK下载3. Maxim SDK安装3.1 安装详解3.2 安装完成4. 测试环境4.1 新建Hello word demo4.2 编译调试下载4.2.1 clean4.2.2 build4.2.3 Openocd5. 实验效果6.小结1. 前言 MAX78000FTHR为快速开发平台&#xff0c;帮助工程师利用M…

第149篇 笔记-web3

定义&#xff1a;Web3是基于去中心化原则的互联网新革命。Web3将当今丰富的交互式数字体验与为用户提供所有权和加密保证的基础设施相结合。 最近在传统技术部门和区块链生态系统的行业领导者中&#xff0c;Web3已成为主流意识&#xff0c;其对互联网的过去和未来有着广泛的影…

蜂鸟E203学习笔记(三)——流水线结构

握手和反压 首先介绍握手协议 valid-ready握手协议 valid先发起请求 ready先发出请求 同时发出请求 仔细观察上述3幅时序图&#xff0c;我们了解valid-ready握手机制需要注意三件事&#xff1a; valid与ready不可过度依赖&#xff0c;比如valid不可以等待ready到达再拉高&…

设计模式之工厂模式

文章目录1.前言工厂模式的三种实现方式应用场景2.简单工厂模式核心组成实现UML类图优点与缺点3.工厂方法模式核心组成实现UML类图优点与缺点4.抽象工厂模式核心组成实现UML类图优点与缺点1.前言 在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;…

React - Ant Design4.x版本安装使用,并按需引入和自定义主题

React - Ant Design4.x版本安装使用&#xff0c;并按需引入和自定义主题一. 安装使用 antd二&#xff0e;antd 高级配置安装 craco&#xff0c;对 create-react-app 的默认配置进行自定义自定义主题安装 babel-plugin-import &#xff0c;按需加载组件代码和样式Ant Design官网…

备赛笔记:RCNN网络基础

1 目标检测&#xff1a; 目标检测指的是对目标进行分类与定位&#xff0c;输入图片&#xff0c;输出物体类别以及其坐标 目标检测模型分为one stage 和two stage类型。one stage及端到端&#xff0c;速度较快&#xff0c;但是准确性较差&#xff0c;two stage网络速度较慢&…

CDH5.12.0-HiveServer2-java.net.SocketTimeoutException: Read timed out

问题描述 环境&#xff1a; 开发调度平台&#xff1a;数栖平台4.18&#xff08;16000任务&#xff0c;7000工作流&#xff09;大数据平台&#xff1a;CDH 5.12.0&#xff0c;大数据组件默认版本BI工具&#xff1a;FineBI实时数仓&#xff1a;Dolphinscheduler StarRocks 问…

从核酸检测平台崩盘看性能工程的范围

近几年疫情肆虐&#xff0c;健康码系统和核酸检测系统成了民生的保障。在疫情张狂的时候&#xff0c;这类系统的稳定性、可用性是关键的技术支撑能力。 每个地方的健康码平台都或多或少地出现过问题&#xff0c;影响每个人的生活。 从我工作十几年的性能工作经验&#xff0c;来…

225. 用队列实现栈-C语言

题目来源&#xff1a;力扣 题目描述&#xff1a; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压…

Python爬取数据分析

一.python爬虫使用的模块 1.import requests 2.from bs4 import BeautifulSoup 3.pandas 数据分析高级接口模块 二. 爬取数据在第一个请求中时, 使用BeautifulSoup   import requests # 引用requests库 from bs4 import BeautifulSoup # 引用BeautifulSoup库 res_movies re…

pycharm Process finished with exit code: -1073741571

问题现象 在pycharm使用debug模式调试代码时&#xff0c;异常退出&#xff0c;且错误码为-1073741571。除了错误码外&#xff0c;并没有看到其它报错。 分析 查阅资料&#xff1a; Process finished with exit code -1073741571 (0xC00000FD) when trying to implement ab…

ZPM介绍(3)

建立私服(Porxy-Registry) 这张图解释了您的私服是怎么工作的&#xff0c; 整篇文章在这里&#xff1a; Proxy-Registry 搭建私服 您需要有一台自己的的服务器&#xff0c; 在上面安装IRIS, zpm, 然后用zpm去下载另一个软件包“zpm-registry"。象这样 zpm:DEMO>search …

如何设置子域名?

什么叫子域名 域名可以划分为各个子域&#xff0c;子域还可以继续划分为子域的子域&#xff0c;这样就形成了顶级域、主域名、子域名等。 举例&#xff1a; “.com”是顶级域名&#xff08;一级域名&#xff09;&#xff1b; “aliyun.com”是主域名&#xff08;二级域名&…

AtCoder Beginner Contest 264 G.String Fair(最短路/暴力dp 补写法)

题目 n(n<18278)个串&#xff0c;第i个串Ti(Ti为纯小写字母串且长度不超过3)&#xff0c; 得分Pi(-1e9<Pi<1e9)&#xff0c;表示只要子串中出现一次Ti&#xff0c;就会获得Pi的得分 对于你可以构造的无限长的串S来说&#xff0c;S的最终得分&#xff0c;为其中每一…

我参加第七届NVIDIA Sky Hackathon——训练CV模型

如何从0开始训练自己的CV模型 第一步 配置基本环境(在上一篇已经配置了我参加第七届NVIDIA Sky Hackathon——训练ASR模型 ) 第二步 利用labelimg制作图像数据集 第三步 开始训练resnet18模型 文章目录如何从0开始训练自己的CV模型前言一、利用labelimg制作图像数据集1.安装la…