BitSet—位图

news2024/11/8 13:52:48

BitSet

  • 🔎概念
  • 🔎位图的模拟实现
    • set()
    • get()
    • reSet()
    • getUsedSize()
    • 完整代码
  • 🔎利用位图进行排序
  • 🔎结尾

🔎概念


位图
用某一位表示存储的状态

位图的适用场景

  • 海量数据
  • 数据为自然数(≥ 0)
  • 数据不重复

举个栗子🌰

以 byte[] 数组为例
byte[] 数组中元素的大小是 1 Byte(字节), 8 bit(比特位)

在这里插入图片描述

存在数组 int[] arr = {1, 4, 12, 20}
满足数据为自然数(≥ 0), 数据不重复
存入 byte[] 数组

在这里插入图片描述

  • 对于 byte[] bytes

    • bytes[0] 用于存储 0 ~ 7 之间的数字
    • bytes[1] 用于存储 8 ~ 15 之间的数字
    • bytes[2] 用于存储 16 ~ 23 之间的数字
  • 用某一位表示存储的状态

    • 用 bytes[0] 的第 0 ~ 7 位(比特位)表示是否存储 0 ~ 7 之间的数字
    • 用 bytes[1] 的第 0 ~ 7 位(比特位)表示是否存储 8 ~ 15 之间的数字
    • 用 bytes[2] 的第 0 ~ 7 位(比特位)表示是否存储 16 ~ 23 之间的数字

🔎位图的模拟实现


此处利用 byte[] 数组模拟实现位图

定义两个变量
public byte[] bytes表示位图
public int usedSize表示位图中的元素个数

无参的构造方法🍭

public ExBitSet() {
    this.bytes = new byte[1];
}

带参的构造方法🍭

n 表示位数
8 表示byte[] 数组的大小为1 Byte(字节), 8 bit(比特位)
n / 8 +1
(0 ~ 7 之间的数字 / 8 = 0, 但所需的大小为 1 字节 → 存储 0 ~ 7 之间的数字)

public ExBitSet(int n) {
    this.bytes = new byte[n / 8 + 1];
}

set()


set(int val)
将某一位设置为 1
(将 val 存储至位图中)

  • val 表示传入的数字, 在 byte[] 数组中根据该数字的值修改其对应下标的位
  • arrayIndex 表示 bytes 数组的下标
  • bitIndex 表示对应的位
public void set(int val) {
    if(val < 0) {
        throw new ValException("val 值小于0");
    }
    int arrayIndex = val / 8;
    if(arrayIndex > bytes.length) {
        bytes = Arrays.copyOf(bytes, arrayIndex + 1);
    }
    int bitIndex = val % 8;
    bytes[arrayIndex] |= 1 << bitIndex;
    usedSize++;
}

举个栗子🌰

val = 12
arrayIndex = 12 / 8 = 1(对应 byte[] 数组的下标为1 → bytes[1])
bitIndex = 12 % 8 = 4(对应的位数为4 → 下标为1, 第 4 位表示 1 * 8 + 4 = 12)

bytes[arrayIndex] |= 1 << bitIndex
将 bytes[1] 的第 4 位设置为 1, 表示存储了数字 12

在这里插入图片描述
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

在这里插入图片描述

get()


get(int val)
判断当前位是否为 1
(判断 val 在位图中是否存在)

  • val 表示传入的数字, 在 byte[] 数组中根据该数字的值修改其对应下标的位
  • arrayIndex 表示 bytes 数字的下标
  • bitIndex 表示对应的位
public boolean get(int val) {
    if(val < 0) {
        throw new ValException("val 值小于0");
    }
    int arrayIndex = val / 8;
    if(arrayIndex > bytes.length) {
         bytes = Arrays.copyOf(bytes, arrayIndex + 1);
    }
    int bitIndex = val % 8;
    return (bytes[arrayIndex] & 1 << bitIndex) != 0;
}

举个栗子🌰

val = 12
arrayIndex = 12 / 8 = 1(对应 byte[] 数组的下标为1 → bytes[1])
bitIndex = 12 % 8 = 4(对应的位数为4 → 下标为1, 第 4 位表示 1 * 8 + 4 = 12)

bytes[arrayIndex] &= 1 << bitIndex
若存储了数字12, 则 bytes[1] 的第 4 位为 1

在这里插入图片描述

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

在这里插入图片描述

reSet()


reSet(int val)
将某一位设置为 0
(将 val 从位图中删除)

  • val 表示传入的数字, 在 byte[] 数组中根据该数字的值修改其对应下标的位
  • arrayIndex 表示 bytes 数字的下标
  • bitIndex 表示对应的位
public void reSet(int val) {
    if(val < 0) {
        throw new ValException("val 值小于0");
    }
    int arrayIndex = val / 8;
    if(arrayIndex > bytes.length) {
        bytes = Arrays.copyOf(bytes, arrayIndex + 1);
    }
    int bitIndex = val % 8;
    bytes[arrayIndex] &= ~(1 << bitIndex);
    usedSize--;
}

举个栗子🌰

val = 12
arrayIndex = 12 / 8 = 1(对应 byte[] 数组的下标为1 → bytes[1])
bitIndex = 12 % 8 = 4(对应的位数为4 → 下标为1, 第 4 位表示 1 * 8 + 4 = 12)

bytes[arrayIndex] &= ~(1 << bitIndex)
将 bytes[1] 的第 4 位设置为 0, 表示删除了数字 12

在这里插入图片描述

~0 = 1
~1 = 0

在这里插入图片描述

getUsedSize()


getUsedSize()
获取位图中的元素个数

public int getUsedSize() {
    return usedSize;
}

完整代码


这里的异常是自定义的
也可以根据自己的需要进行相关的修改

import java.util.Arrays;

public class ExBitSet {

    public byte[] bytes;
    // 记录当前位图中存在多少个有效数据
    public int usedSize;

    public ExBitSet() {
        this.bytes = new byte[1];
    }

    /**
     * n → 需要多少位
     */
    public ExBitSet(int n) {
        this.bytes = new byte[n / 8 + 1];
    }

    /**
     * 设置某一位为 1
     */

    public void set(int val) {
        if(val < 0) {
            throw new ValException("val 值小于0");
        }
        int arrayIndex = val / 8;
        if(arrayIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, arrayIndex + 1);
        }
        int bitIndex = val % 8;
        bytes[arrayIndex] |= 1 << bitIndex;
        usedSize++;
    }

    /**
     * 判断当前位是否为 1
     */

    public boolean get(int val) {
        if(val < 0) {
            throw new ValException("val 值小于0");
        }
        if(arrayIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, arrayIndex + 1);
        }
        int arrayIndex = val / 8;
        int bitIndex = val % 8;
        return (bytes[arrayIndex] & 1 << bitIndex) != 0;
    }

    /**
     * 将对应位置变为0
     */
    public void reSet(int val) {
        if(val < 0) {
            throw new ValException("val 值小于0");
        }
        if(arrayIndex > bytes.length) {
            bytes = Arrays.copyOf(bytes, arrayIndex + 1);
        }
        int arrayIndex = val / 8;
        int bitIndex = val % 8;
        bytes[arrayIndex] &= ~(1 << bitIndex);
        usedSize--;
    }

    // 当前位图中的元素个数
    public int getUsedSize() {
        return usedSize;
    }

}

🔎利用位图进行排序


根据 byte[] 数组的下标计算数据所在的范围区间
根据当前位是否为 1 判断是否存储了该数字

  • bytes[0] 表示 0 ~ 7 之间的数字(0 * 8 + 对应的位)
  • bytes[1] 表示 8 ~ 15 之间的数字(1 * 8 + 对应的位)
  • bytes[2] 表示 16 ~ 23 之间的数字(2 * 8 + 对应的位)
public static void main(String[] args) {

   ExBitSet bitSet = new ExBitSet();

   int n = bitSet.bytes.length;
   for(int i = 0; i < n; i++) {
       int x = bitSet.bytes[i];
       for(int j = 0; x != 0 && j < 8; j++) {
           if((x & 1 << j) != 0) {
               System.out.println(i * 8 + j);
           }
       }
   }
}

举个栗子🌰

假设当前位图中存储的元素为 1, 12, 4, 0, 23, 5

  • int n = 3
  • bytes[0] != 0, bytes[1] != 0, bytes[2] != 0
  • i 表示对应的下标, i * 8 表示对应的取值范围
  • j 表示对应的位数, i * 8 + j 表示具体的数值

在这里插入图片描述

🔎结尾

创作不易,如果对您有帮助,希望您能点个免费的赞👍
大家有什么不太理解的,可以私信或者评论区留言,一起加油

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

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

相关文章

内网隧道代理技术(二)之LCX端口转发

LCX端口转发 LCX介绍 LCX是一款端口转发工具&#xff0c;分为Windows版和Linux版&#xff0c;Linux版本为PortMap。LCX有端口映射和端口转发两大功能&#xff0c;例如当目标的3389端口只对内开放而不对外开放时&#xff0c;可以使用端口映射将3389端口映射到目标的其他端口使…

计算两个向量的外积numpy.outer()

【小白从小学Python、C、Java】 【等级考试500强双证书考研】 【Python-数据分析】 计算两个向量的外积 numpy.outer() 以下说法正确的是&#xff1a; import numpy as np a np.array([1,2]) print("【显示】a ",a) b np.array([3,4,5]) print("【显示】b &q…

SpringBoot进阶-SpringBoot如何实现配置文件脱敏

目录 参考一、概述二、实现1、引入pom2、在配置文件中添加密钥3、生成加密之后的数据4、将加密之后的数据添加到配置文件中 三、踩坑Encryption raised an exception. A possible cause is you are using strong encryption algorithms and you have not installed the Java Cr…

python系列27:jupyter转web app的工具Mercury

1. 简介 官网&#xff1a;https://runmercury.com/ Mercury可以将 Jupyter Notebook 呈现为 Web 应用程序。类似的package还有streamlit和voila 使用import mercury as mr进行安装。Mercury的页面分为左边的输入部分&#xff0c;和右边的输出部分&#xff0c;下面是极简例子&a…

C++函数重载学习

C 允许多个函数拥有相同的名字&#xff0c;只要它们的参数列表不同就可以&#xff0c;这就是函数的重载&#xff08;Function Overloading&#xff09;。 一个基本的例子&#xff1b; #include<iostream> using namespace std;void print(int i) {cout<<"a …

远程控制之原理和实践

按理来说&#xff0c;本人不该发表此类专业文章&#xff0c;鄙人零星碎片化的开发经历&#xff0c;让本人斗胆向诸位网友&#xff0c;在远控方面做一点演示说明&#xff0c;谈论一点自己的认识。 程序工程代码地址&#xff1a;点击此处下载。 程序分为两个部分&#xff0c;控…

OpenCV 项目开发实战--对图像中的斑点进行检测(Python、C++代码实现)

什么是斑点? Blob 是图像中一组连接的像素,它们共享一些共同的属性(例如,灰度值)。在上图中,暗连接区域是斑点,斑点检测旨在识别和标记这些区域。 文末附相关测试代码的下载链接 SimpleBlobDetector 示例 OpenCV 提供了一种基于不同特征检测和过滤斑点的便捷方法。让…

计算机组成原理笔记(王道考研)(持续更新)

文章目录 前言概论计算机的发展计算机系统计算机硬件组成各个硬件的工作原理计算机系统的层次结构计算机系统结构、组成、实现 计算机性能指标储存器CPU整体指标Amdahl定律与加速比 前言 本文是对王道计算机考研《计算机组成原理》课程的总结&#xff0c;主讲咸鱼学长讲的确实…

那些曾经考过的turtle绘图题(1~5)

【编程实现绘图 -1】 使用使用turtle库的函数,绘制三个彩色的圆,圆的颜色按顺序如图,圆的半径从里至外分别是20,50, 100,效果如图所示 # 样例代码 from turtle import * # 导入turtle库 list_r = [20, 50, 100] # 定义半径列表 list_color = ["red", "…

chatgpt赋能python:在画布中间画图的Python技巧

在画布中间画图的Python技巧 在Python中&#xff0c;绘图是数据可视化和图形表示的一种重要方式。然而&#xff0c;在绘制图表时&#xff0c;我们需要让图表的中心点位于画布的正中心&#xff0c;而不是依靠手动计算像素值来实现。这不仅让图表更易读&#xff0c;还提高了可视…

chatgpt赋能python:Python中如何处理多个输入

Python中如何处理多个输入 在编写Python程序时&#xff0c;我们经常需要从用户那里获取多个输入来执行某些操作。本文将介绍Python中的各种方法来处理多个输入。 从终端获取多个输入 Python中最简单的方式是从终端获取多个输入。下面是一个基本的例子&#xff1a; input_st…

chatgpt赋能python:Python中的函数

Python中的函数 Python是一种高级语言&#xff0c;可用于各种应用程序&#xff0c;从Web开发到科学计算。Python中的函数是重要的编程概念之一&#xff0c;它允许开发人员将一段代码重复使用&#xff0c;并可以按照需要调用它们。 函数是什么&#xff1f; 函数是一种拥有参数…

直动式插装减压阀DPR-100-N-S-24

参数规格 操作压力:流动情况: 内部泄漏: 弹性范围: 工作温度: 推荐过滤等级: 流体介质: 阀腔/阀腔工具:阅体材质: 3000 PSI (207 Bar)见[压降与流量关系图].5英寸/min(82cc/min)在最大压力3000PSI(207Bar)下50PSI至200PSI(3至14 Bar)预设值:150 PSI(10 Bar) 100 PSI 至…

打包jar包或war包

idea下springboot打包成jar包和war包&#xff0c;并且在外部tomcat下运行访问 jar包 这里设置pom.xml文件将工程打成jar包 使用maven的插件打包&#xff0c;打包后的jar包在项目的target目录下 此时打包出来是有默认的名称的jar包。然后在命令行下 运行起这个jar包。当然&…

chatgpt赋能python:Python中如何在输出一排后换行输出

Python中如何在输出一排后换行输出 在Python编程中&#xff0c;经常需要使用print语句输出信息。有时候需要在输出一排信息之后换行输出&#xff0c;比如在输出一个数据表格或者一个列表等等情况下&#xff0c;这就需要用到Python中如何在输出一排后换行输出的方法。 什么是换…

Python基础之类的继承与派生

一、继承 新创建一个类&#xff0c;这个类可以继承一个或多个父类&#xff0c;新创建的类及哦啊做子类或派生类&#xff0c;被继承的类叫做父类或基类。 例&#xff1a; class ParentClass_01: # 定义父类passclass ParentClass_02: # 定义父类passclass SonClass_01(Pa…

RTKLIB学习总结(九)RTK算法详解

文章目录 一、RTK算法数据类型1、rtk_t&#xff1a;rtk控制结构体2、sol_t&#xff1a;结果结构体3、SOLQ_XXX&#xff1a;解的类型状态4、ambc_t&#xff1a;模糊度固定控制结构体5、ssat_t&#xff1a;卫星状态控制结构体6、prcopt_t&#xff1a;算法处理选项结构体7、obs_t&…

【ChatGPT工具篇-1】ChatGPT + MindShow 分分钟搞定PPT制作

AI 能生万物吗&#xff1f; &#xfeff;&#xfeff;&#xfeff; 制作一份“通用性”的PPT需要几步&#xff1f; 三步 借助ChatGPT和MindShow&#xff0c;分分钟完成操作&#xff0c;就能制作出来完胜大部分人的PPT文件&#xff1b; 解锁更多AIGC&#xff08;ChatGPT、AI绘…

C#,码海拾贝(42)——病态线性方程组的“简单迭代解法”之C#源代码

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static partial class LEquations { /// <summary> /…

chatgpt赋能python:Python如何定义π

Python如何定义π 介绍 Python是一种高级编程语言&#xff0c;它被广泛用于数据分析、机器学习、科学计算和Web开发等领域。在这些领域中&#xff0c;算数计算是非常重要的&#xff0c;而数学领域中重要的一个数字就是π。 π是圆的周长与直径的比例。它是一个无限不循环的小…