BitMap位圖與海量數據的理解與應用

1. Bit Map算法簡介

? ? ? ??來自于《編程珠璣》。所謂的Bit-map就是用一個bit位來標記某個元素對應的Value, 而Key即是該元素。由于采用了Bit為單位來存儲數據,因此在存儲空間方面,可以大大節省。

2、 Bit Map的基本思想

? ? ? ? 我們先來看一個具體的例子,假設我們要對0-7內的5個元素(4,7,2,5,3)排序(這里假設這些元素沒有重復)。那么我們就可以采用Bit-map的方法來達到排序的目的。要表示8個數,我們就只需要8個Bit(1Bytes),首先我們開辟1Byte的空間,將這些空間的所有Bit位都置為0,如下圖:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?


然后遍歷這5個元素,首先第一個元素是4,那么就把4對應的位置為1(可以這樣操作 p+(i/8)|(0x01<<(i%8)) 當然了這里的操作涉及到Big-ending和Little-ending的情況,這里默認為Big-ending),因為是從零開始的,所以要把第五位置為一(如下圖):
?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??


然后再處理第二個元素7,將第八位置為1,,接著再處理第三個元素,一直到最后處理完所有的元素,將相應的位置為1,這時候的內存的Bit位的狀態如下:?
?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??


然后我們現在遍歷一遍Bit區域,將該位是一的位的編號輸出(2,3,4,5,7),這樣就達到了排序的目的。

?

優點:

1.運算效率高,不許進行比較和移位;

2.占用內存少,比如N=10000000;只需占用內存為N/8=1250000Byte=1.25M。?
缺點:

? ? ? ?所有的數據不能重復。即不可對重復的數據進行排序和查找。 ? ?

?

算法思想比較簡單,但關鍵是如何確定十進制的數映射到二進制bit位的map圖。

3、 Map映射表

假設需要排序或者查找的總數N=10000000,那么我們需要申請內存空間的大小為int a[1 + N/32],其中:a[0]在內存中占32為可以對應十進制數0-31,依次類推:?
bitmap表為:?
a[0]--------->0-31?
a[1]--------->32-63?
a[2]--------->64-95?
a[3]--------->96-127?
..........?
那么十進制數如何轉換為對應的bit位,下面介紹用位移將十進制數轉換為對應的bit位。?

如題:

給你一個文件,里面包含40億個整數,寫一個算法找出該文件中不包含的一個整數, 假設你有1GB內存可用。

如果你只有10MB的內存呢?

一個位代表一個數據,那40一個數據大概要40*10^8*bit = 0.5GB,滿足內存要求。

首先我們用int來表示:int ?bmap[1+N/32]; //N是總數,N=40億,一個int32bit

然后我們插入一個整數val,要先計算val位于數組bmap中的索引:index = val/32;

比如整數33,index=33/32=1,第33位于數組中的index=1

比如整數67,index=67/32=2,位于數組中index=2

然后在計算在這個index中的位置,因為數組中的每個元素有32位

33,index=1,在1中的位置為33%32=1

67,index=2,在2中的位置為67%32=3

然后就是標識這個位置為1:

bmap[val/32] ?|= (1<<(val%32));

33: bmap[1] ? ?!= (1<<1);//xxxxxx1x,紅絲位置被置為1

67: bmap[2] ? != ?(1<<3);//xxxx1xxx

void setVal(int val)
{bmap[val/32] |= (1<<(val%32));//bmap[val>>5] != (val&0x1F);//這個更快?
}

?

怎樣檢測整數是否存在?

比如我們檢測33,同樣我們需要計算index,以及在index元素中的位置

33: index = 1, 在bmap[1]中的位置為 1,只需要檢測這個位置是否為1

bmp[1] &(1<<1),這樣是1返回true,否側返回false

67:bmp[2]&(1<<3)

127:bmp[3]&(1<<31)

bool testVal(int val)
{return bmap[val/32] & (1<<(val%32));//return bmap[val>>5] & (val&0x1F);
}

?

現在我們來看如果內存要求是10MB呢?

?

這當然不能用bitmap來直接計算。因為從40億數據找出一個不存在的數據,我們可以將這么多的數據分成許

多塊, 比如每一個塊的大小是1000,那么第一塊保存的就是0到999的數,第2塊保存的就是1000 到1999的數……

實際上我們并不保存這些數,而是給每一個塊設置一個計數器。 這樣每讀入一個數,我們就在它所在的塊對應的計數器加1。

處理結束之后,?我們找到一個塊,它的計數器值小于塊大小(1000), 說明了這一段里面一定有數字是文件中所不包含的。然后我們單獨處理
這個塊即可。接下來我們就可以用Bit Map算法了。我們再遍歷一遍數據, 把落在這個塊的數對應的位置1(我們要先把這個數
歸約到0到blocksize之間)。 最后我們找到這個塊中第一個為0的位,其對應的數就是一個沒有出現在該文件中的數。)

4、 Bit-Map的應用

? ? ??1)可進行數據的快速查找,判重,刪除,一般來說數據范圍是int的10倍以下。

?????? 2)去重數據而達到壓縮數據

5、 具體實現(JAVA)

【問題實例】

1)已知某個文件內包含一些電話號碼,每個號碼為8位數字,統計不同號碼的個數。

8位最多99 999 999,大概需要99m個bit,大概10幾m字節的內存即可。

位圖法需要的空間很少(依賴于數據分布,但是我們也可以通過一些放啊發對數據進行處理,使得數據變得密集),在數據比較密集的時候效率非常高。例如:8位整數可以表示的最大十進制數值為99999999,如果每個數組對應于一個bit位,那么把所有的八進制整數存儲起來只需要:99Mbit = 12.375MB.

實際上,Java?jdk1.0已經提供了bitmap的實現BitSet類,不過其中的某些方法是jdk1.4之后才有的。

分別使用自己實現的BitMap和jdk的BitSet類:

復制代碼
 1 //去除重復并排序2 import java.util.Arrays;3 import java.util.BitSet;4 import java.util.Random;5 6 /**7  * @author 8  * @date Time: 9  * @des:
10  */
11 public class BitMap {
12     int ARRNUM = 800;
13     int LEN_INT = 32;
14     int mmax = 9999;
15     int mmin = 1000;
16     int N = mmax - mmin + 1;
17 
18     public static void main(String args[]) {
19          new BitMap().findDuplicate();
20          new BitMap().findDup_jdk();
21     }
22 
23     public void findDup_jdk() {
24         System.out.println("*******調用JDK中的庫方法--開始********");
25         BitSet bitArray = new BitSet(N);
26         int[] array = getArray(ARRNUM);
27         for (int i = 0; i < ARRNUM; i++) {
28             bitArray.set(array[i] - mmin);
29         }
30         int count = 0;
31         for (int j = 0; j < bitArray.length(); j++) {
32             if (bitArray.get(j)) {
33                 System.out.print(j + mmin + " ");
34                 count++;
35             }
36         }
37         System.out.println();
38         System.out.println("排序后的數組大小為:" + count );
39         System.out.println("*******調用JDK中的庫方法--結束********");
40     }
41     //下面是自己實現的方法:
42     public void findDuplicate() {
43         int[] array = getArray(ARRNUM);
44         int[] bitArray = setBit(array);
45         printBitArray(bitArray);
46     }
47 
48     public void printBitArray(int[] bitArray) {
49         int count = 0;
50         for (int i = 0; i < N; i++) {
51             if (getBit(bitArray, i) != 0) {
52                 count++;
53                 System.out.print(i + mmin + "\t");
54             }
55         }
56         System.out.println();
57         System.out.println("去重排序后的數組大小為:" + count);
58     }
59 
60     public int getBit(int[] bitArray, int k) {// 1右移 k % 32位 與上 數組下標為 k/32 位置的值
61         return bitArray[k / LEN_INT] & (1 << (k % LEN_INT));
62     }
63 
64     public int[] setBit(int[] array) {// 首先取得數組位置下標 i/32, 然后 或上
65                                         // 在該位置int類型數值的bit位:i % 32
66         int m = array.length;
67         int bit_arr_len = N / LEN_INT + 1;
68         int[] bitArray = new int[bit_arr_len];
69         for (int i = 0; i < m; i++) {
70             int num = array[i] - mmin;
71             bitArray[num / LEN_INT] |= (1 << (num % LEN_INT));
72         }
73         return bitArray;
74     }
75 
76     public int[] getArray(int ARRNUM) {
77 
78         @SuppressWarnings("unused")
79         int array1[] = { 1000, 1002, 1032, 1033, 6543, 9999, 1033, 1000 };
80 
81         int array[] = new int[ARRNUM];
82         System.out.println("數組大小:" + ARRNUM);
83         Random r = new Random();
84         for (int i = 0; i < ARRNUM; i++) {
85             array[i] = r.nextInt(N) + mmin;
86         }
87 
88         System.out.println(Arrays.toString(array));
89         return array;
90     }
91 }
復制代碼

?

2)2.5億個整數中找出不重復的整數的個數,內存空間不足以容納這2.5億個整數。?
將bit-map擴展一下,用2bit表示一個數即可,0表示未出現,1表示出現一次,2表示出現2次及以上,在遍歷這些數的時候,如果對應位置的值是0,則將其置為1;如果是1,將其置為2;如果是2,則保持不變。或者我們不用2bit來進行表示,我們用兩個bit-map即可模擬實現這個2bit-map,都是一樣的道理。

給你一個文件,里面包含40億個整數,寫一個算法找出該文件中不包含的一個整數, 假設你有1GB內存可用。

如果你只有10MB的內存呢?原文地址:https://www.cnblogs.com/protected/p/6626447.html

?

轉載于:https://www.cnblogs.com/jstarseven/p/9444451.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/279662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/279662.shtml
英文地址,請注明出處:http://en.pswp.cn/news/279662.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

imdb文件_如何停止IMDB應用程序向您發送通知

imdb文件Recently, the IMDB app started sending out notifications for “Featured Trailers”. As near as I can guess, this is where the production company pays IMDB to push a link to the trailer to a load of people in an effort to promote it. If IMDB isn’t …

科普:BCH能夠買什么?如何使用BCH買東西?

2019獨角獸企業重金招聘Python工程師標準>>> 一提到BCH&#xff0c;你最想拿它做什么&#xff1f;可能對于投資者來說&#xff0c;它是暴富的神器&#xff0c;是投資的工具&#xff1b;對于開發者來說&#xff0c;是實現自身價值構建應用程序的網絡和平臺&#xff0…

驅動學習之驅動體驗

1&#xff1a;什么是linux驅動 從本質上講&#xff0c;驅動就是屬于內核層面的程序代碼&#xff0c;是直接和硬件打交道的。與裸機中直接操作寄存器去操作硬件的不同之處在于&#xff0c;裸機中操作的是物理內存&#xff0c;而我們在驅動中操作的是虛擬內存&#xff0c;驅動中還…

vim(三)golang代碼跳轉配

在golang的代碼里跳來跳去。。。。 godef 安裝 跳轉是通過godef實現&#xff0c;godef的安裝目錄一般是$GOBIN,只要讓godef命令在$PATH下即可 godef 命令安裝&#xff1a; go get -v github.com/rogpeppe/godef go install -v github.com/rogpeppe/godef vim插件安裝 ~/.vimrc配…

如何將iPhone或iPad更新到iOS 11

Apple released iOS 11 on September 19, 2017. You can upgrade by tapping “Install Now” when an update message appears, but you can also check for the update and install it immediately. 蘋果于2017年9月19日發布了iOS11 。您可以通過在出現更新消息時點按“立即安…

三、Python-列表

三、Python-列表 一、序列&#xff1a;是一塊用于存放多個值的連續內存空間&#xff0c;并且按一定順序排列&#xff0c;可以通過索引取值索引&#xff1a;從左到右的索引從0開始依次增加的正整數&#xff1b;從右到左的索引為-1開始的復數切片&#xff08;分片&#xff09;&am…

使用基本ACL規則限制用戶登錄

要求&#xff1a;配置ACL 2005規則&#xff0c;限制vty 0 4界面只允許IP地址為192.168.1.8的用戶和10.10.100.0/24網段的用戶登錄設備。 配置如下&#xff1a; system-view acl 2005 rule permit source 192.168.1.8 0 //允許IP地址為192.168.1.8的用戶登錄設備 rule permit s…

pandas 入門(2)

from pandas import Series, DataFrame, Index import numpy as np from numpy import nan as NAobj Series(range(3), index[a, b, c]) print(obj) index obj.index print(index) print(index[1:]) # index[1] d index對象時不可以被修改的 為了安全和共享index Index(n…

如何在Outlook 2013中管理附件

There comes a time, job-hunting, or sharing photos with older family members, where you may need to send stuff the old fashioned way – as an email attachment. If you email at work, it may be a part of your email repertoire. 有時需要找工作&#xff0c;與年長…

了解cron以及使用cron定時備份MySQL

cron是一個linux下的定時執行工具&#xff0c;可以在無需人工干預的情況下運行作業。由于Cron 是Linux的內置服務&#xff0c;但它不自動起來&#xff0c;可以用以下的方法啟動、關閉這個服務&#xff1a; /sbin/service crond start //啟動服務 /sbin/service crond stop //關…

ef 并發控制

ef 并發控制 ef 并發控制 什么是并發&#xff1f;并發分悲觀并發和樂觀并發。悲觀并發&#xff1a;比如有兩個用戶A,B&#xff0c;同時登錄系統修改一個文檔&#xff0c;如果A先進入修改&#xff0c;則系統會把該文檔鎖住&#xff0c;B就沒辦法打開了&#xff0c;只有等A修改完…

C#實現寫入文本文件內容功能

private void write_txt(string str1, string str2, string str3)02{03System.DateTime currentTime System.DateTime.Now;04string strYMD currentTime.ToString("d");05string FILE_NAME "MyFileSend" strYMD ".txt";//每天按照日期建立一…

如何在Windows上設置BitLocker加密

BitLocker is a tool built into Windows that lets you encrypt an entire hard drive for enhanced security. Here’s how to set it up. BitLocker是Windows內置的工具&#xff0c;可用于加密整個硬盤驅動器以增強安全性。 設置方法如下。 When TrueCrypt controversially …

Java字節碼方法表與屬性表深度剖析

方法表&#xff1a; 在上一次咱們已經分析到了字段信息了&#xff0c;如下&#xff1a; 緊接著就是方法相關的信息了&#xff1a; 而它展開之后的結構為&#xff1a; 所以往后數2個字節&#xff0c;看一下方法的總數&#xff1a; 3個方法&#xff0c;可咱們只定義了兩個方法呀&…

最大連續子數組和與JUnit測試

【題目】最大連續子數組和&#xff08;最大子段和&#xff09; 背景 問題&#xff1a; 給定n個整數&#xff08;可能為負數&#xff09;組成的序列a[1],a[2],a[3],…,a[n],求該序列如a[i]a[i1]…a[j]的子段和的最大值。當所給的整數均為負數時定義子段和為0&#xff0c;依此定義…

筆記本電源適配器為什么總壞_為什么某些交流適配器和電源會發出嘯叫聲?

筆記本電源適配器為什么總壞Most of the time our AC adapters and power supplies tend to be quiet, but what does it mean when one makes a whining noise? Should you be concerned? Today’s SuperUser Q&A post has the answers to a worried reader’s question…

4412 字符類設備的設備號

一、靜態申請字符類設備號 字符類設備函數在文件"include/linux/fs.h"中內核提供了三個函數來注冊一組字符設備編號&#xff0c;這三個函數分別是 register_chrdev_region()alloc_chrdev_region()register_chrdev()register_chrdev_region()是提前知道設備的主次設備…

monogdb操作system.*權限

mongodb roles system.roles集合刪不掉 當你自定義了特權(角色): db.createRole({role: "dropSystemViewsAnyDatabase",privileges: [{actions: [ "dropCollection" ],resource: { db: "", collection: "system.roles" }}],roles: []}…

如何發現假庫存照片(并將合適的人歸于屬性)

Spammers and other unscrupulous advertisers are always looking for new ways to get you click on their pages. One of the latest tactics is to steal popular and useful stock images—like the kind you sometimes see in news articles—and re-upload them elsewhe…

Mysql Hunter

一、簡介自動化實施的過程中&#xff0c;我們通常都面臨一個棘手的問題&#xff1a;數據的準備和恢復。即在成功執行一個自動化用例時&#xff0c;我們可能需要一定的數據前提&#xff0c;而為了使得整個前提不至于被其他的用例破壞&#xff0c;以至于我們有時不得不在自動化用…