一、定义     --概念部分参考http://www.iteblog.com/archives/148

位图法就是bitmap的缩写。所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,但数据状态又不是很多的情况。通常是用来判断某个数据存不存在的。在STL中有一个bitset容器,其实就是位图法。

引用bitset介绍:A bitset is a special container class that is designed to store bits (elements with only two possible values: 0 or 1,true or false, ...).The class is very similar to a regular array, but optimizing for space allocation: each element occupies only one bit (which is eight times less than the smallest elemental type in C++: char).Each element (each bit) can be accessed individually: for example, for a given bitset named mybitset, the expression mybitset[3] accesses its fourth bit, just like a regular array accesses its elements.

二、数据结构

内部维护数组   char M [N];

在这个数组里面,可以存储 N * 8个数据,但是最大的数只能是N * 8 - 1。假如,我们要存储的数据范围为0-15,则我们只需要使得N=1,这样就可以把数据存进去。如下图:

数据为【5,1,7,15,0,4,6,10】,则存入这个结构中的情况为

三、相关操作

对于内部数组 char M [8 * 1024]; 这样做,能存 8K*8=64K 个 bit。存放的字节位置和位位置(字节 0~8191 ,位 0~7 )。

内部实现均采用位操作,比如将第1234个位置1 ,字节序:1234 >> 3 = 154; 位序:0x80 >> (1234 & 0x07) = 2 ,那么 1234 放在 M 的下标 154 字节处,把该字节的 2 号位( 0~7)置为 1。

1. 置位(设操作第k个位)

M[k >> 3] |= (0x80 >> (k & 0x07));

解释:M[第k个标志位所在的字节(k/8 取整)] |= (第k个标志位在所在字节中的位数(取余))

2. 复位(设操作第k个位)

M[k >> 3] &= ~(0x80 >> (k & 0x07));

解释:M[第k个标志位所在的字节(k/8 取整)] &= ~(第k个标志位在所在字节中的位数(取余))

3. 访问(设操作第k个位)

return M[k >> 3] & (0x80 >> (k & 0x07));

解释:M[第k个标志位所在的字节(k/8 取整)] &(第k个标志位在所在字节中的位的值)

4. 扩容

若被访问的M[k]已出界,则需扩容,与vector扩容原理类似,重新分配内存,容量加倍,并将原数据转移至新的空间。

四、位图的应用举例 (大规模数据,整数)

(1) 给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中。

40亿是个巨大的数量,如果将40亿个int变量完全存储到内存中可不得了,所以最好采用40亿个位(476M空间)来存放这40亿个数据的状态比较好。

首先,遍历这40亿个数字,分别在对应的位图中进行置位。然后对于给出的数,进行按秩查找,判断是否在bitmap中即可。

(2) 使用位图法判断整形数组是否存在重复

遍历数组,以数组元素为秩,分别将bitmap中对应的位置1,并且检查其是否已经为1,若为1,即为重复的元素。

(3) 使用位图法进行整形数组排序

首先遍历数组,得到数组的最大最小值,然后根据这个最大最小值来缩小bitmap的范围。这里需要注意对于int的负数,都要转化为unsigned int来处理,而且取位的时候,数字要减去最小值。

(4) 在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数

参考的一个方法是:采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)。其实,这里可以使用两个普通的Bitmap,即第一个Bitmap存储的是整数是否出现,如果再次出现,则在第二个Bitmap中设置即可。这样的话,就可以使用简单的1-Bitmap了。

五、位图实现

实现位图并封装在bitmap类中。

bitmap接口列表
操作 功能 对象
bitmap(int n = 8) 构造函数,默认容量为8位 位图
bitmap(char* file, int n = 8) 构造函数,从指定文件中读取比特图 位图
~bitmap() 析构函数,释放位图空间 位图
init(int n) 初始化位图空间 位图
set(int k) 置位第k个标志位 位图
clear(int k) 复位第k个标志位 位图
test(int k) 取出指定字节中的指定位 位图
dump(char* file) 将位图整体导出至指定的文件 位图
bits2string(int n) 将前n位转换为字符串 位图
expand(int k) 扩容 位图
print(int n) 逐位打印以检验位图内容 位图
isPrime(int n) 判断某个数是否为素数 自然数

(1) bitmap.h

#pragma once#pragma warning(disable : 4996 4800)
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "math.h"
class bitmap { //位图bitmap类
private:char* M; int N; //比特图所存放的空间M[],容量为N*sizeof(char)*8比特
protected:void init(int n)   //初始化位图空间{M = new char[N = (n + 7) / 8];   //申请内存memset(M, 0, N);    //初始化内存块}public:bitmap(int n = 8) { init(n); } //按指定或默认规模创建比特图(为测试暂时选用较小的默认值)bitmap(char* file, int n = 8) //按指定或默认规模,从指定文件中读取比特图{init(n); FILE* fp = fopen(file, "r"); fread(M, sizeof(char), N, fp); fclose(fp);}~bitmap() { delete[] M; M = NULL; } //析构时释放比特图空间void set(int k)   //置位第k个标志位{ expand(k);   //拓容        M[k >> 3] |= (0x80 >> (k & 0x07));  //M[第k个标志位所在的字节(k/8 取整)] |= (第k个标志位在所在字节中的位数(取余)) }void clear(int k) {expand(k);    //拓容 M[k >> 3] &= ~(0x80 >> (k & 0x07)); //M[第k个标志位所在的字节(k/8 取整)] &= ~(第k个标志位在所在字节中的位数(取余))}bool test(int k) {//取出指定字节中的指定位expand(k);    //拓容 return M[k >> 3] & (0x80 >> (k & 0x07));  //M[第k个标志位所在的字节(k/8 取整)] &(第k个标志位在所在字节中的位的值)}   void dump(char* file) //将位图整体导出至指定的文件,以便对此后的新位图批量初始化{FILE* fp = fopen(file, "w"); fwrite(M, sizeof(char), N, fp); fclose(fp);}char* bits2string(int n) { //将前n位转换为字符串——expand(n - 1); //此时可能被访问的最高位为bitmap[n - 1]char* s = new char[n + 1]; s[n] = '\0'; //字符串所占空间,由上层调用者负责释放for (int i = 0; i < n; i++) s[i] = test(i) ? '1' : '0';return s; //返回字符串位置}void expand(int k) { //若被访问的bitmap[k]已出界,则需扩容if (k < 8 * N) return; //仍在界内,无需扩容int oldN = N; char* oldM = M;init(2 * k); //与向量类似,加倍策略memcpy_s(M, N, oldM, oldN); delete[] oldM; //原数据转移至新空间}void print(int n) //逐位打印以检验位图内容,非必需接口{expand(n); for (int i = 0; i < n; i++) printf(test(i) ? "1" : "0");}static bool isPrime(int n) {  //判断某个数是否为素数if (n <= 3) {return n > 1;}// 不在6的倍数两侧的一定不是质数if (n % 6 != 1 && n % 6 != 5) {return false;}int s = (int) sqrt(n);for (int i = 5; i <= s; i += 6) {if (n % i == 0 || n % (i + 2) == 0) {return false;}}return true;
}
};

十二、【数据结构】位图(bitmap)的详解与实现相关推荐

  1. 【正点原子Linux连载】第三十二章 U-Boot启动流程详解 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  2. 十二种常见设计模式代码详解

    零:设计模式分类 设计模式有创建型模式.结构型模式与行为型模式 创建型:单例模式.工厂模式(简单工厂,工厂方法,抽象工厂) 结构型:适配器模式.门面模式.装饰器模式.注册树模式.代理模式.管道模式 行 ...

  3. Vue进阶(八十二):updated 应用详解

    文章目录 一.前言 二.注意事项 三.拓展阅读 一.前言 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用updated钩子函数. 无论是组件本身的数据变更,还是从父组件接收到的 pr ...

  4. Opencv学习----位图(bitmap)原理详解三---位图解析度

    2.3 解析度 分辨率是位图的一个属性,在视觉上查看或打印位图时是必需的,因为像素本身没有明确的尺寸.分辨率通常以每英寸像素数指定,但可以是任何其他测量单位.由于历史原因,大多数打印过程保留每英寸像素 ...

  5. Opencv学习----位图(bitmap)原理详解五---位图存储

    2.5 位图存储 存储位图的最简单方法是简单地逐字节地列出位图信息.此方法存储的文件通常称为RAW文件.考虑到位图尺寸(N x M)和位深(B)中的颜色深度,任何位图所需的磁盘存储量都很容易计算.文件 ...

  6. 第十二课:Sizzle引擎详解

    这篇博客难度太大,跟前端开发其实没什么关系,如果你想成为大牛,那就去了解下吧.如果你还不想,那可以忽略,毕竟面试官也不会问到这里来,因为他也不太懂.呵呵. Sizzle引擎是jQuery的选择器,它大 ...

  7. 前端一HTML:十二:元素查找过程的详解

    后代选择器查找原理 <!doctype html> <html lang="en"> <head><meta charset=" ...

  8. 深度学习之图像分类(二十八)-- Sparse-MLP(MoE)网络详解

    深度学习之图像分类(二十八)Sparse-MLP(MoE)网络详解 目录 深度学习之图像分类(二十八)Sparse-MLP(MoE)网络详解 1. 前言 2. Mixture of Experts 2 ...

  9. ELK详解(二十五)——elastalert配置参数详解

    今天继续给大家介绍Linux运维相关知识,本文主要内容是elastalert的配置参数详解. 一.配置文件参数详解 首先,我们来讲解一下elastalert的配置文件中的常用参数: 1.ES集群相关参 ...

最新文章

  1. 「学习笔记-Linux」学习Shell Script
  2. 白话Elasticsearch40-深入聚合数据分析之案例实战_Global Aggregation:单个品牌与所有品牌平均价格对比
  3. 【原创】iframe与父页面之间,变量、方法互相调用
  4. linux imq原理图,编译IMQ模块
  5. mysql删除有关联的数据库表_【数据库】mysql如何删除关联表
  6. Java设计模式之行为型:状态模式
  7. python IDLE中反斜杠显示为人民币符号¥的解决办法
  8. mysql桥梁表_以JDBC为桥梁入门MySQL数据库基础
  9. Virtualbox 无缝整合linux和windows双系统
  10. 移动端分享到微信和QQ
  11. python 爬虫 微博 github_GitHub - peanut-shi/weiboSpider: 新浪微博爬虫,用python爬取新浪微博数据...
  12. CentOS 6.5 安装 Redis 执行 make #error Newer version of jemalloc required
  13. 阶段3 3.SpringMVC·_07.SSM整合案例_03ssm整合之编写Spring框架
  14. 选手及评委素材信息规范处理说明
  15. 【设计模式】-工厂模式->工厂方法模式(源码与类图解析)
  16. UG(NX)二次开发 BlockUI 集列表使用方法
  17. cygwin 编译android,再次在 cygwin 下编译 Android toolchain
  18. Affinity Photo2022比PS更好用的图像编辑软件
  19. 国美易卡设计构架的思维模式(国美易卡)
  20. Java SpringMVC毕业项目实战-学生信息管理系统

热门文章

  1. 记一个打包出现错误Multiple chunks emit assets to the same filename js/chunk-0.js(chunks chunk-0 and chunk-0)
  2. java自动化分页_Python+Selenium自动化实现分页(pagination)处理
  3. jQuery筛选--hasClass(class)和eq(index|-index)
  4. MathJax的使用
  5. sicily 2013
  6. java实现带界面的生产者消费者_Java实现生产者消费者问题与读者写者问题
  7. YOLOv5训练报错:result type Float can‘t be cast to the desired output type __int64
  8. 跨境电商领域的ChatGPT使用攻略
  9. CMMB收费、直播星免费都是战略失误
  10. HDU 3498 whosyourdaddy (可重复覆盖舞蹈链)