近期在看《编程珠玑》这本书。 第1章中引入了bitmap(位图)的数据结构。

曾经没有接触过, 抽出时间研究了一下,记录下来。

书中描写叙述的情景:

1. 最多1000万个7位数电话号码(号码不反复,实际大概800万个),保存在文本中

2. 每隔一段时间要对号码进行排序

3.程序模块最多可用1M Bytes的内存, 磁盘空间充足

分析:

通常方案:7位电话号码能够用uint32_t (4个字节)来存储,  4 * 8 * 10^6 Bytes约为32M Bytes。一次性排序显然内存不满足。

1M Bytes 内存能够存放 10^6/4 = 250万个号码, 1000万个约要分40趟进行读取排序写入文件,在归并到一起

此方案,须要40次读原始文本的代价,效率低下。

位图方案: 1个字节(8Bit)能够存放8个整数,  实际800万个号码,刚好1M Bytes的内存空间能够使用,符合要求。

一、原理

通常存储方案。 每一个整数(假如4个字节)。 占用内存多。 在内存不足或海量数据时。 导致处理方法复杂。

位图。 能够理解用位(Bit)来表示数据。 1个字节是8位, 能够存储8个连续的整数, 内存空间充分利用。 每一位 1表示有数据, 0 表示没有数据。

举例说明:

整数集合 {1 , 11,  9 , 7 , 10 }

5个整数,用通常存储方案,须要 5  * 4 = 20 字节

位图仅仅须要  12位, 不到2个字节(一般是用2个字节来存放,方便管理和字节对齐)

这5个整数用位图表演示样例如以下:

0 1 0 0 0 0 0 1 0 1 1 1 0 0 0 0
0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

第1个字节。表示的数据范围  0 ~ 7。 第2个字节, 表示的数据范围 : 8 ~ 15

二、 一个非负整数(如果为N)位图的表示方法

(负数表示的方法类似。 在此仅仅以非负数来分析)

1. 计算N属于哪个单元

1个字节(8Bit)能够存放8个连续的整数,一个位图能够划分为多个这种小单元。

整数N除以8 的值能够推断在哪个单元中。

如样例中: 整数 9,   9 / 8 =  1(从0 開始计算的),能够知道在第2个字节单元中。

2. 位图中N的插入

每个字节中,能够表示8个连续整数,  要确定N在单元中的确切位置

插入9之前:

0 0 0 0 0 0 0 0
8 9 10 11 12 13 14 15

插入9之后:

0 1 0 0 0 0 0 0
8 9 10 11 12 13 14 15

如果插入之前。单元数值为X,

插入9后能够表示为:  X  |  (0X80 >> 9 % 8)

公式能够表示为:   X  |  ( 0X80 >> N % 8)

推算过程: 0X80, 二进制表示 1000  0000 ,右移 9 % 8= 1位。 变为 0 100   0000。和 插入之前的数 “或”运算。就能够把9的位置设为1了。

3. 位图中N的查询

如果N 所在的划分单元的数值为 X,

公式能够表示为:  X   &  ( 0X80 >> N % 8)

推算过程:0X80 右移 N % 8 位, 与X 进行“交”运算, 假设结果为0, 则整数N不在位图中, 反之。在位图中。

4. 位图中N的删除

如果N所在的划分单元的数值为X,

公式能够表示为: X & ~(0X80 >> N % 8)

推算过程:0X80 右移 N % 8 位。求反会把相应的为置为0。其它位为1, 再与X 进行“交”运算, 仅仅把N所在单元的位置设为0

通过以上的分析。写代码就方便了。 我用c语言写了一个简单的測试代码:

_bitmap.h

#ifndef _BITMAP_H
#define _BITMAP_H
#include <stdint.h> static inline void bitmap_add(char* p, int64_t n)
{
p += n / 8;
*p |= (0x80 >> n % 8);
} static inline void bitmap_del(char* p, int64_t n)
{
p += n / 8;
*p &= ~(0x80 >> n % 8);
} // yes: > 0, no: 0
static inline int bitmap_lookup(char* p, int64_t n)
{
p += n / 8;
return *p & (0x80 >> n % 8);
} #endif /*_BITMAP_H*/

test.c

#include <stdio.h>
#include "_bitmap.h" int main(int argc, char* argv[])
{
uint32_t num[] = {7999, 6000, 0, 1, 13, 11, 12, 99, 88, 55, 77, 800, 5000}; #define SIZE 1000
char a[SIZE] = {0}; // Can store 0 ~ 7999 int i = 0;
for (i = 0; i < sizeof(num) / sizeof(uint32_t); i++)
{
bitmap_add(a, num[i]);
} //print bitmap
char* p = a;
for (i = 0; i < SIZE; i++)
{
int j = 0;
for (j = 0; j < 8; j++)
{
if ((*p & (0x80 >> j)))
printf("%d\t", i * 8 + j);
}
p++;
}
printf("\n"); // delete
bitmap_del(a, 99);
bitmap_del(a, 0); // print bitmap
p = a;
for (i = 0; i < SIZE; i++)
{
int j = 0;
for (j = 0; j < 8; j++)
{
if ((*p & (0x80 >> j)))
printf("%d\t", i * 8 + j);
}
p++;
}
printf("\n"); int x = 99;
if (bitmap_lookup(a, x))
{
printf("%d is in bitmap\n", x);
}
else
{
printf("%d is not in bitmap\n", x);
} x = 7999;
if (bitmap_lookup(a, x))
{
printf("%d is in bitmap\n", x);
}
else
{
printf("%d is not in bitmap\n", x);
} return 0;
}

输出结果:

数据结构——bitmap的更多相关文章

  1. Linux 内核数据结构bitmap

    #include <stdio.h> #include <stdlib.h> #define MAX_PRIO 10000 #define BITS_PER_LONG 32 # ...

  2. 转:从《The C Programming Language》中学到的那些编程风格和设计思想

    这儿有一篇写的很好的读后感:http://www.cnblogs.com/xkfz007/articles/2566424.html   读书不是目的,关键在于思考.   很早就在水木上看到有人推荐& ...

  3. MD中bitmap源代码分析--数据结构

    本篇分析bitmap的数据结构的设计,并基于此分析bitmap的工作机制. 为了后面更清楚的理解,先有个总体印象,给出整体的结构图: 在下面的描述中涉及到的内容可以对照到上图中相应部分,便于理解. 首 ...

  4. 【算法与数据结构专场】BitMap算法基本操作代码实现

    上篇我们讲了BitMap是如何对数据进行存储的,没看过的可以看一下[算法与数据结构专场]BitMap算法介绍 这篇我们来讲一下BitMap这个数据结构的代码实现. 回顾下数据的存储原理 一个二进制位对 ...

  5. Linux 内核里的数据结构:位图(bitmap)

    注: 本文由 LCTT 原创翻译,Linux中国 荣誉推出 Linux 内核中的位数组和位操作 除了不同的基于链式和树的数据结构以外,Linux 内核也为位数组(或称为位图(bitmap))提供了 A ...

  6. 高级数据结构及应用 —— 使用 bitmap 进行字符串去重

    bitmap 即为由单个元素为 boolean(0/1, 0 表示未出现,1 表示已经出现过)的数组. 如果C/C++ 没有原生的 boolean 类型,可以用 int 或 char 来作为 bitm ...

  7. 一种很有意思的数据结构:Bitmap

    昨晚遇到了一种很有意思的数据结构,Bitmap. Bitmap,准确来说是基于位的映射.其中每个元素均为布尔型(0 or 1),初始均为 false(0).位图可以动态地表示由一组无符号整数构成的集合 ...

  8. c/c++ 数据结构之位图(bitmap)具体解释

    1.  概述 位图(bitmap)是一种很经常使用的结构,在索引.数据压缩等方面有广泛应用. 本文介绍了位图的实现方法及其应用场景. 2. 位图实现 2014728101320" alt=& ...

  9. Lucene核心数据结构——FST存词典,跳表存倒排或者roarning bitmap 见另外一个文章

    Lucene实现倒排表没有使用bitmap,为了效率,lucene使用了一些策略,具体如下:1. 使用FST保存词典,FST可以实现快速的Seek,这种结构在当查询可以表达成自动机时(PrefixQu ...

随机推荐

  1. Ibatis2.3.4的一个bug

    java.lang.ClassCastException: com.chat.upgrade.domain.ClientFile cannot be cast to java.lang.String ...

  2. WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇)

    原文:WCF技术剖析之十四:泛型数据契约和集合数据契约(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话)]]在.NE ...

  3. Python 脚本帮你找出微信上删除了你的“好友“

  4. [置顶] android关机闹钟设计思路

    1: 首先需要硬件支持,支持alarm中断触发开机,目前高通平台几乎都支持: 2:关机前需要在rtc-xxx.c中做到enable_irq_wake,和不disable alarm功能(默认开机后al ...

  5. BSGS_Baby steps giant steps算法

    BSGS这个主要是用来解决这个题: A^x=B(mod C)(C是质数),都是整数,已知A.B.C求x. 在具体的题目中,C一般是所有可能事件的总数. 解: 设m = ceil(sqrt(C))(ce ...

  6. 基于visual Studio2013解决面试题之0302链表中找倒数k项节点

     题目

  7. Eclipse无提示的解决办法 和 内容辅助技巧

    Eclipse无提示的解决办法 和 内容辅助技巧 一.若发现内容辅助失效没有提示 下面是解决办法,现贴出来与大家共享:       1.菜单window->Preferences->Jav ...

  8. Problem E: Erratic Ants

    这个题没过……!题意:小蚂蚁向四周走,让你在他走过的路中寻找最短路,其中可以反向主要思路:建立想对应的图,寻找最短路径,其中错了好多次,到最后时间没过(1.没有考录反向2.没有考虑走过的路要标记……! ...

  9. 不使用webview,用手机浏览器的android app

    需求:wap站在手机上以App的形式打开,但不要嵌套WebView,只能以浏览器打开 package com.gzz.whyinzi; import android.net.Uri; import a ...

  10. C语言中 struct成员变量顺序对内存的占用

    在C语言的结构体中,是会按照其变量类型来进行分配内存大小的.但是对于不同的编译器,结果是不同的,在VC++6.0中是怎么个分配情况呢?用一下C中的关键字sizeof()来测试下,注意sizeof()不 ...