資料結構:點陣圖法(bitmap||BMP)
一、定義
點陣圖法就是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.
二、資料結構
unsigned int bit[N];
在這個數組裡面,可以儲存 N * sizeof(int)個數據,但是最大的數只能是N * sizeof(int) - 1。假如,我們要儲存的資料範圍為0-15,則我們只需要使得N=1,這樣就可以把資料存進去。如下圖:
資料為【5,1,7,15,0,4,6,10】,則存入這個結構中的情況為
三、相關操作
1,寫入資料
定義一個數組: unsigned char bit[8 * 1024];這樣做,能存 8K*8=64K 個 unsigned short 資料。bit
存放的位元組位置和位位置(位元組 0~8191 ,位 0~7 )
比如寫 1234 ,位元組序: 1234/8 = 154; 位序: 1234 &0b111 = 2(等價於:1234%8=2.思考下,為什麼要這樣取餘?) ,那麼 1234 放在 bit 的下標 154 位元組處,把該位元組的 2 號位( 0~7)置為 1
位元組位置: int nBytePos =1234/8 = 154;
位位置: int nBitPos = 1234 & 7 = 2;
[cpp]
// 把陣列的 154 位元組的 2 位置為 1
unsigned short val = 1<<nBitPos;
bit[nBytePos] = bit[nBytePos] |val; // 寫入 1234 得到arrBit[154]=0b00000100
再比如寫入 1236 ,
位元組位置: int nBytePos =1236/8 = 154;
位位置: int nBitPos = 1236 & 7 = 4
[cpp]
// / 把陣列的 154 位元組的 4 位置為 1
val = 1<<nBitPos;
arrBit[nBytePos] = arrBit[nBytePos] |val; // 再寫入 1236 得到arrBit[154]=0b00010100函式實現:
[cpp]
#define SHIFT 5
#define MAXLINE 32
#define MASK 0x1F
void setbit(int *bitmap, int i){
bitmap[i >> SHIFT] |= (1 << (i & MASK));
}
2,讀指定位(判斷i是否在bitmap中)
[cpp]
bool getbit(int *bitmap1, int i){
return bitmap1[i >> SHIFT] & (1 << (i & MASK));
}
四、點陣圖法的缺點
可讀性差
點陣圖儲存的元素個數雖然比一般做法多,但是儲存的元素大小受限於儲存空間的大小。點陣圖儲存性質:儲存的元素個數等於元素的最大值。比如, 1K 位元組記憶體,能儲存 8K 個值大小上限為 8K 的元素。(元素值上限為 8K ,這個侷限性很大!)比如,要儲存值為 65535 的數,就必須要 65535/8=8K 位元組的記憶體。要就導致了點陣圖法根本不適合存 unsigned int 型別的數(大約需要 2^32/8=5 億位元組的記憶體)。
點陣圖對有符號型別資料的儲存,需要 2 位來表示一個有符號元素。這會讓點陣圖能儲存的元素個數,元素值大小上限減半。 比如 8K 位元組記憶體空間儲存 short 型別資料只能存 8K*4=32K 個,元素值大小範圍為 -32K~32K 。
五、點陣圖法的應用
1、給40億個不重複的unsigned int的整數,沒排過序的,然後再給一個數,如何快速判斷這個數是否在那40億個數當中
首先,將這40億個數字儲存到bitmap中,然後對於給出的數,判斷是否在bitmap中即可。
2、使用點陣圖法判斷整形陣列是否存在重複
遍歷陣列,一個一個放入bitmap,並且檢查其是否在bitmap中出現過,如果沒出現放入,否則即為重複的元素。
3、使用點陣圖法進行整形陣列排序
首先遍歷陣列,得到陣列的最大最小值,然後根據這個最大最小值來縮小bitmap的範圍。這裡需要注意對於int的負數,都要轉化為unsigned int來處理,而且取位的時候,數字要減去最小值。
4、在2.5億個整數中找出不重複的整數,注,記憶體不足以容納這2.5億個整數
參 考的一個方法是:採用2-Bitmap(每個數分配2bit,00表示不存在,01表示出現一次,10表示多次,11無意義)。其實,這裡可以使用兩個普 通的Bitmap,即第一個Bitmap儲存的是整數是否出現,如果再次出現,則在第二個Bitmap中設定即可。這樣的話,就可以使用簡單的1- Bitmap了。
[cpp]
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#define SHIFT 5
#define MAXLINE 32
#define MASK 0x1F
using namespace std;
// w397090770
// [email protected]
// 2012.11.29
void setbit(int *bitmap, int i){
bitmap[i >> SHIFT] |= (1 << (i & MASK));
}
bool getbit(int *bitmap1, int i){
return bitmap1[i >> SHIFT] & (1 << (i & MASK));
}
size_t getFileSize(ifstream &in, size_t &size){
in.seekg(0, ios::end);
size = in.tellg();
in.seekg(0, ios::beg);
return size;
}
char * fillBuf(const char *filename){
size_t size = 0;
ifstream in(filename);
if(in.fail()){
cerr<< "open " << filename << " failed!" << endl;
exit(1);
}
getFileSize(in, size);
char *buf = (char *)malloc(sizeof(char) * size + 1);
if(buf == NULL){
cerr << "malloc buf error!" << endl;
exit(1);
}
in.read(buf, size);
in.close();
buf[size] = '\0';
return buf;
}
void setBitMask(const char *filename, int *bit){
char *buf, *temp;
temp = buf = fillBuf(filename);
char *p = new char[11];
int len = 0;
while(*temp){
if(*temp == '\n'){
p[len] = '\0';
len = 0;
//cout<<p<<endl;
setbit(bit, atoi(p));
}else{
p[len++] = *temp;
}
temp++;
}
delete buf;
}
void compareBit(const char *filename, int *bit, vector<int> &result){
char *buf, *temp;
temp = buf = fillBuf(filename);
char *p = new char[11];
int len = 0;
while(*temp){
if(*temp == '\n'){
p[len] = '\0';
len = 0;
if(getbit(bit, atoi(p))){
result.push_back(atoi(p));
}
}else{
p[len++] = *temp;
}
temp++;
}
delete buf;
}
int main(){
vector<int> result;
unsigned int MAX = (unsigned int)(1 << 31);
unsigned int size = MAX >> 5;
int *bit1;
bit1 = (int *)malloc(sizeof(int) * (size + 1));
if(bit1 == NULL){
cerr<<"Malloc bit1 error!"<<endl;
exit(1);
}
memset(bit1, 0, size + 1);
setBitMask("file1", bit1);
compareBit("file2", bit1, result);
delete bit1;
cout<<result.size();
sort(result.begin(), result.end());
vector< int >::iterator it = unique(result.begin(), result.end());
ofstream of("result");
ostream_iterator<int> output(of, "\n");
copy(result.begin(), it, output);
return 0;
}
相關推薦
資料結構:點陣圖法(bitmap||BMP)
一、定義 點陣圖法就是bitmap的縮寫。所謂bitmap,就是用每一位來存放某種狀態,適用於大規模資料,但資料狀態又不是很多的情況。通常是用來判斷某個資料存不存在的。在STL中有一個bitset容器,引用bitset介紹: A bitset is a spe
Linux 核心資料結構:點陣圖(Bitmap)
https://github.com/0xAX/linux-insides/blob/master/DataStructures/bitmap.md Data Structures in the Linux Kernel Bit arrays and bit op
C++資料結構:二叉樹(一)——先序建立二叉樹
一、二叉樹 (Binary Tree) 定義: 二叉樹是n個節點的有限集合,該集合或者為空集( 稱為空二叉樹 ),或者由一個根節點和兩棵互不相交的的二叉樹組成,這兩棵二叉樹分別稱為根節點的左子樹和右
C++資料結構:二叉樹(二)——二叉樹的遍歷
一、序言 在上一篇文章中《二叉樹的先序建立》,我們介紹了二叉樹的基本結構以及先序建立二叉樹,在本篇文章中,我們要對二叉樹進行遍歷,包括: 層序遍歷 遞迴先序遍歷、遞迴中序遍歷、遞迴後序遍歷 非遞迴中序遍歷 二、二叉樹的遍歷 BiTree.h
資料結構之點陣圖(bitmap)詳解 (轉)
1. 概述 點陣圖(bitmap)是一種非常常用的結構,在索引,資料壓縮等方面有廣泛應用。本文介紹了點陣圖的實現方法及其應用場景。 2. 點陣圖實現 (1)自己實現 在點陣圖中,每個元素為“0”或“1”,表示其對應的元素不存在或者存在。 複製程式碼程式碼如
【資料結構】點陣圖與布隆處理器
文章目錄 1.點陣圖的實現 BitMap.h BitMap.c 2.布隆的實現 BloomFilter.h BloomFilter.c 1.點陣圖
資料結構:雜湊表(Hash Table)
雜湊表定義 雜湊表是一種根據關鍵碼去尋找值的資料對映結構,該結構通過把關鍵碼對映的位置去尋找存放值的地方。 本質是一個數組,陣列中每一個元素稱為一個箱子(bin),箱子中存放的是鍵值對。 雜湊表的儲存過程如下: 根據 key 計算出它的雜湊值 h。 假設箱子的個數
極客講堂之資料結構與演算法之美(一):複雜度分析(上)
(本文根據極客講堂——資料結構與演算法之美專欄的問答區整理修改而成,如有侵權還希望聯絡我鴨~) 一、什麼是複雜度分析? 1.資料結構和演算法解決是“如何讓計算機更快時間、更省空間的解決問題”。 2.因此需從執行時間和佔用空間兩個維度來評估資料結構和演算法的效能。 3.分別
資料結構與演算法之美(三):陣列
陣列看起來簡單基礎,但是很多人沒有理解這個資料結構的精髓。帶著為什麼陣列要從0開始編號,而不是從1開始的問題,進入主題。 一、 如何實現隨機訪問 1) 陣列是一種線性資料結構,用連續的儲存空間儲存相同型別資料: I) 線性表:陣列、連結串列、佇列、棧 ;非線性表
【資料結構】點陣圖BitMap與布隆過濾器BloomFilter
首先先看一下下面這個騰訊的面試題:給40億個不重複的無符號整數,沒排過序。給一個無符號整數,如何快速判斷一個數是否在這40億個數中。 【騰訊】思路一: 最容易想到的解法就是遍歷所有的40多億個整數,然後一個一個判斷。但是這個需要花費的記憶體是多大呢? 大家可以去算一下
【資料結構】點陣圖BitMap
給40億個不重複的無符號整數,沒拍過序。給定一個無符號整數,如何可以高效的判斷是否存在這些資料中。 直接的想法是,我們將這些的無符號整數儲存到記憶體中,然後用給定的數進行一一比較。 我們分析一下,一個
資料結構之程式效能檢測(一):三種排序演算法·對比
先上程式碼: #include<stdio.h> #include<time.h> # define MAX_SIZE 1001 void sort(int *a, int n); void sort2(int *a, int n)
集合的檢索:點陣圖法
點陣圖法 點陣圖(bit-map)法是一種邏輯上很巧妙的描述集合的方法。 如集合S={2,4,1,5,12},它用點陣圖描述就是 0110 11
資料結構:雜湊表(散列表)
轉自:http://blog.chinaunix.net/uid-26548237-id-3480645.html 一、散列表相關概念 雜湊技術是在記錄的儲存位置和它的關鍵字之間建立一個確定的對應關係f,使得每個關鍵字key對應一個儲存位置f(key)。
考研資料結構複習之線性表(二)
單鏈表的學習 #pragma once typedef char DataType; class SSeqListTest { public: SSeqListTest(); ~SSeqListTest(); }; typedef struct Node {
資料結構——線索二叉樹(程式碼)
線索二叉樹 C++ 環境codeblocks17 通過 /* 線索二叉樹 @CGQ 2018/10/29 */ #include <iostream> #include <stdio.h> #include <stdlib.h> using namesp
資料結構基礎之線性表(下)
轉自:http://www.cnblogs.com/edisonchou/p/4614934.html 線性表(下) 在上一篇中,我們瞭解了單鏈表與雙鏈表,本次將單鏈表中終端結點的指標端由空指標改為指向頭結點,就使整個單鏈表形成一個環,這種頭尾相接的單鏈表稱為單迴圈連結串列
資料結構與演算法——單鏈表(一)
單鏈表的頭插法,插入時就是逆序。 InsertList()還不完善。 #include<stdio.h> #include<stdlib.h> #define ERROR 0 #define OK 1 typedef int Status ; typedef int
資料結構與演算法——線性表(一)
#include <stdio.h> #include <stdlib.h> #define LIST_INIT_SIZE 200 #define LISTINCREASE 10 #define ERROR 0 #define OK 1 typedef int Elemt
【資料結構】希爾排序(ShellSort)
概念: 希爾排序法,又稱縮小增量法。希爾排序法的基本思想是:先選定一個整數, 把待排序檔案中所有資料分成幾個組,所有距離為gap的資料分在同一組內,並對每一組內的資料進行排序。 然後,去重複上述分組和排序的工作。當到達gap=1時,所有資料在一組內