1. 程式人生 > >[整理]資料結構----點陣圖法

[整理]資料結構----點陣圖法

一、定義

       點陣圖法就是bitmap的縮寫。所謂bitmap,就是用每一位來存放某種狀態,適用於大規模資料,但資料狀態又不是很多的情況。通常是用來判斷某個資料存不存在的。在STL中有一個bitset容器,其實就是點陣圖法。

二、資料結構

unsigned int bit[N];

在這個數組裡面,可以儲存 N * sizeof(int) * 8個數據,但是最大的數只能是N * sizeof(int)  * 8 - 1。假如,我們要儲存的資料範圍為0-31,則我們只需要使得N=1,這樣就可以把資料存進去。

三、相關操作

1.寫指定位

定義一個數組: unsigned char bit[8 * 1024];這樣做,能存
8K*8=64K unsigned short 資料。bit 存放的位元組位置和位位置(位元組 0~8191 ,位 0~7

比如寫 1234 ,位元組序: 1234/8 = 154; 位序: 1234 & 0b111 = 2 ,那麼 1234 放在 bit 的下標 154 位元組處,把該位元組的 2 號位( 0~7)置為 1

// 把陣列的 154 位元組的 2 位置為 1
int nBytePos =1234/8 = 154; //位元組位置: 
int nBitPos = 1234 & 7 = 2; //位位置:   
unsigned short val = 1 << nBitPos;
bit[nBytePos] = bit[nBytePos] |val;  // 寫入 1234 得到arrBit[154]=0b00000100
#define SHIFT 5 &nbsp;
#define MAXLINE 32 &nbsp;
#define MASK 0x1F &nbsp;
void setbit(int *bitmap, int i){  
    bitmap[i >> SHIFT] |= (1 << (i & MASK));  
}

2.讀指定位

bool getbit(int *bitmap1, int i){  
    return bitmap1[i >> SHIFT] & (1 << (i & MASK));  
} 

四、點陣圖法的缺點

1.可讀性差

2.點陣圖儲存的元素個數雖然比一般做法多,但是儲存的元素大小受限於儲存空間的大小。點陣圖儲存性質:儲存的元素個數等於元素的最大值。比如, 1K 位元組記憶體,能儲存 8K 個值大小上限為 8K 的元素。(元素值上限為 8K ,這個侷限性很大!)比如,要儲存值為 65535 的數,就必須要 65535/8=8K 位元組的記憶體。要就導致了點陣圖法根本不適合存 unsigned int 型別的數(大約需要 2^32/8=5 億位元組的記憶體)。

3.點陣圖對有符號型別資料的儲存,需要 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(每個數分配2bit00表示不存在,01表示出現一次,10表示多次,11無意義)。其實,這裡可以使用兩個普 通的Bitmap,即第一個Bitmap儲存的是整數是否出現,如果再次出現,則在第二個Bitmap中設定即可。這樣的話,就可以使用簡單的1- Bitmap了。

六、實現

#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的縮寫。所謂bitmap,就是用每一位來存放某種狀態,適用於大規模資料,但資料狀態又不是很多的情況。通常是用來判斷某個資料存不存在的。在STL中有一個bitset容器,其實就是點陣圖法。 二、資料結構 unsigned int

Redis資料結構:點陣

原文:https://scalegrid.io/blog/introduction-to-redis-data-structure-bitmaps/ 點陣圖(也稱為位陣列,位向量等)是緊湊儲存位的陣列資料結構。它可以用來實現一個簡單的集資料結構。位陣列可以有效地利用硬體中的位級並行性來快速執行操

海量資料處理——點陣bitmap

定義一個數組: unsigned char bit[8 * 1024];這樣做,能存 8K*8=64K 個 unsigned short 資料。bit 存放的位元組位置和位位置(位元組 0~8191 ,位 0~7 ) 比如寫 1234 ,位元組序: 1234/8 = 154; 位序: 1234 &a

資料結構點陣(bitmap||BMP)

一、定義        點陣圖法就是bitmap的縮寫。所謂bitmap,就是用每一位來存放某種狀態,適用於大規模資料,但資料狀態又不是很多的情況。通常是用來判斷某個資料存不存在的。在STL中有一個bitset容器,引用bitset介紹: A bitset is a spe

輕鬆理解資料結構與算系列(Radix樹)

前言 推出一個新系列,《看圖輕鬆理解資料結構和演算法》,主要使用圖片來描述常見的資料結構和演算法,輕鬆閱讀並理解掌握。本系列包括各種堆、各種佇列、各種列表、各種樹、各種圖、各種排序等等幾十篇的樣子。 Radix樹 Radix樹,即基數樹,也稱壓縮字首樹,是一種提供key-value儲存查詢的資料結構。與

02-看理解資料結構與算系列(單向連結串列)

單向連結串列 單向連結串列屬於連結串列的一種,也叫單鏈表,單向即是說它的連結方向是單向的,它由若干個節點組成,每個節點都包含下一個節點的指標。 單鏈表特點 建立單鏈表時無需指定連結串列的長度,這個比起陣列結構更加有優勢,而陣列縱使實現成動態陣列也是需要指定一個更大的陣

01-看理解資料結構與算系列(陣列)

  陣列 陣列是最熟悉也是最基礎的一種結構了,有限個相同資料型別的元素按順序排列的集合為陣列。陣列的資料是連續的,有上界下界,在其中的元素都有屬於自己的索引值,即下標,通過這些下標就能定位到陣列值。 根據維度的不同可以將陣列分為一維陣列、二維陣列、三維陣列等等,以此類推。 一維陣列

07-看理解資料結構與算系列(選擇排序)

選擇排序 選擇排序是一種很簡單直觀的排序演算法,主要思想就是每次從待排序的元素中選擇出最大或最小的那個元素,然後將其放至已排序序列的末尾,直到全部待排序序列都排序完畢。 排序要點 初始狀態時,待排序序列為a1,a2,...an,已排序序列為空。 第一趟排序,從

06-看理解資料結構與算系列(AVL樹)

AVL樹 AVL樹,也稱平衡二叉搜尋樹,AVL是其發明者姓名簡寫。AVL樹屬於樹的一種,而且它也是一棵二叉搜尋樹,不同的是他通過一定機制能保證二叉搜尋樹的平衡,平衡的二叉搜尋樹的查詢效率更高。 AVL樹特點 AVL樹是一棵二叉搜尋樹。 AVL樹的左右子節點也是

05-看理解資料結構與算系列(基於陣列的棧)

棧 棧是一種線性儲存結構且運算受限的線性表,它的插入和刪除運算操作被限制在表的一端,該端稱為棧頂,而另外一端則稱為棧底。 棧中的資料以後進先出(Last In First Out 即LIFO)方式進出棧。 棧的實現 棧的實現方式有多種方式,主要是使用不同的結構來儲存棧元素,比如使用陣列、

12-看理解資料結構與算系列(氣泡排序)

氣泡排序 氣泡排序是一種很簡單的排序演算法,主要思想就是不斷走訪待排序序列,每次只比較兩個相鄰元素,如果這倆元素順序不符合要求則對換它們,不斷重複知道沒有相鄰元素需要對換。在不斷走訪比較過程中,越大的元素經過交換會慢慢走到數列頂端,所以看起來它就像氣泡一樣不斷往上冒,於是就叫冒泡。

11-看理解資料結構與算系列(B樹的刪除)

刪除操作 刪除操作比較複雜,主要是因為刪除的項可能在葉子節點上也可能在非葉子節點上,而且刪除後可能導致不符合B樹的規定,這裡暫且稱之為導致B樹不平衡,於是要進行一些合併、左旋、右旋等操作,使之符合B樹的規定(即讓B樹平衡)。另外,如果是刪除非葉子節點項需要先找到中序前驅來替換。 情況

10-看理解資料結構與算系列(B+樹)

B+樹 B+樹是B樹的一種變體,也屬於平衡多路查詢樹,大體結構與B樹相同,包含根節點、內部節點和葉子節點。多用於資料庫和作業系統的檔案系統中,由於B+樹內部節點不儲存資料,所以能在記憶體中存放更多索引,增加快取命中率。另外因為葉子節點相連遍歷操作很方便,而且資料也具有順序性,便於區間查詢。

17-看理解資料結構與算系列(NoSQL儲存-LSM樹)

關於LSM樹 LSM樹,即日誌結構合併樹(Log-Structured Merge-Tree)。其實它並不屬於一個具體的資料結構,它更多是一種資料結構的設計思想。大多NoSQL資料庫核心思想都是基於LSM來做的,只是具體的實現不同。所以本來不打算列入該系列,但是有朋友留言了好幾次讓我講LS

16-看理解資料結構與算系列(快速排序)

快速排序 快速排序由C.A.R.Hoare在1962年提出,是氣泡排序的一種改進。其基本思想為:通過一趟排序將待排序資料分割成獨立的兩部分,其中一部分的所有值都比另一部分的所有值都小,然後再對分割的兩部分分別進行快速排序,整個過程可以遞迴進行,最終所有資料變為有序序列。 排序要點

資料結構與算系列》合集整理

《資料結構與算法系列》合集整理 整理來自部落格園skywang12345,以下摘自作者介紹: “最近抽空整理了"資料結構和演算法"的相關文章。在整理過程中,對於每種資料結構和演算法分別給出"C"、"C++"和"Java"這三種語言的實現;實現語言雖不同,但原理如出一轍。因此,讀者在瞭解和學

輕鬆理解資料結構與算系列(希爾排序)

前言 推出一個新系列,《看圖輕鬆理解資料結構和演算法》,主要使用圖片來描述常見的資料結構和演算法,輕鬆閱讀並理解掌握。本系列包括各種堆、各種佇列、各種列表、各種樹、各種圖、各種排序等等幾十篇的樣子。 希爾排序 希爾排序是希爾(Donald Shell)提出的一種

【演算法-點陣】在海量資料中查詢重複元素

什麼是點陣圖法? 舉個簡單例子,在java中一個int型別的數有32位,而這32只表示一個數太過浪費,於是就考慮讓這32位可以表示32個數,每一位表示該數是否存在,例如: 這裡用16位的二進位制就能表示十六個數字,1表示存在,0表示不存在,上圖就表示存在(16,12,

資料結構的構建(鄰接表

#include<iostream> #include<string> #include<queue> using namespace std; #define ERROR 1 #define MAX_VERTEX_NUM 100 typedef struct ArcNod

資料結構的陣列表示

        圖( Graph )是 由頂點的有窮非空集合和頂點之間邊的集合組成,通常表示示為: G (V, E ) ,其中, G表示一個圖, V 是圖 G 中頂點的集合, E 是 圖 G 中邊的集合 。        圖狀結構是一種比樹形結構更復雜的非線性結構。在樹