用位圖排序無重復(fù)數(shù)據(jù)集實(shí)例代碼(C++版)
《Programming Pearls》(編程珠璣下載)第一章講述了如何用位圖排序無重復(fù)的數(shù)據(jù)集,整個(gè)思想很簡(jiǎn)潔,今天實(shí)踐了下。
一、主要思想
位圖排序的思想就是在內(nèi)存中申請(qǐng)一塊連續(xù)的空間作為位圖,初始時(shí)將位圖的每一位都置為0,然后依次讀取待排序文件的整數(shù),將整數(shù)所在的位設(shè)置為1,最后掃描位圖,如果某一位為1,則說明這個(gè)數(shù)存在,輸出到已排序文件。比如待排序的數(shù)據(jù)S={3,0,4,1,7,2,5},max(S)=7,我們可以設(shè)置一個(gè)八位的位圖B,將位圖的每一位初始為0,即B=[0,0,0,0,0,0,0,0],對(duì)S中的每一個(gè)整數(shù)d,設(shè)置B[d]=1,即B=[1,1,1,1,1,1,0,1],最后掃描位圖,對(duì)位圖的每一位i,如果B[i]==1,則輸出i到已排序文件,排序后的S={0,1,2,3,4,5,7}。
整個(gè)過程只需要遍歷一遍待排序文件和位圖,時(shí)間復(fù)雜度O(n),需要的輔助空間為(max(S)/8)B。雖然這個(gè)排序算法只能在無重復(fù)的整數(shù)集上運(yùn)行,但對(duì)于有些需求,確實(shí)做到高效實(shí)現(xiàn),比如說給手機(jī)號(hào)碼排序,手機(jī)號(hào)碼11位,第一位始終為1,理論上可以有10^10個(gè)號(hào)碼,但一些號(hào)碼未發(fā)放,即有些號(hào)碼在系統(tǒng)中不存在,假設(shè)系統(tǒng)中有50%的合法號(hào)碼,每個(gè)號(hào)碼用long int表示,這么多號(hào)碼所需要的空間為50%*(10^10)*4B=20GB,不能放在內(nèi)存中進(jìn)行快速排序。一個(gè)可選的方案是分多趟進(jìn)行歸并排序,但需要較長(zhǎng)的時(shí)間。我們申請(qǐng)一個(gè)10^10位的位圖,需要的內(nèi)存是10^10/8B=1.25GB,完全可以在當(dāng)代的PC機(jī)上運(yùn)行,在掃描位圖時(shí),假設(shè)某一位i為1,輸出文件時(shí),在前面添加一個(gè)1,例如i=3885201314,輸出為13885201314。
二、算法實(shí)現(xiàn)
用c語言實(shí)現(xiàn)的話,需要自己封裝位圖操作,這里需要用到三個(gè)操作:設(shè)置位圖的所有位為0(setAllZero);設(shè)定指定的位為1(setOne);查看指定的位是否為1(find);代碼如下:
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#define MAX_NUM 16777216//最大的數(shù),也就是需要的位
#define BYTE_NUM (1+MAX_NUM/8)//字節(jié)數(shù)
#define MASK 0x07
void setAllZero(unsigned char *p,long size);
void setOne(unsigned char *p,long loc);
int find(unsigned char *p,long loc);
bool getSorted(unsigned char *bitmap,char *fileName);
bool setBitmap(unsigned char *bitmap,char *fileName);
int bitmapSort();
int main(){
return bitmapSort();
}
int bitmapSort(){
unsigned char *bitmap; //位圖指針
bitmap = (unsigned char *)malloc(BYTE_NUM*sizeof(unsigned char));
if(bitmap == NULL){
printf("Malloc failed\n");
return -1;
}
setAllZero(bitmap,BYTE_NUM);//將位圖所有位設(shè)置為0
setBitmap(bitmap,"phoneNumber.txt");//掃描待排文件,將位圖對(duì)應(yīng)位設(shè)置為1
getSorted(bitmap,"bitmapSort.txt"); //掃描位圖,將位圖為1的位號(hào)輸出到文件
free(bitmap);//釋放位圖
return 0;
}
/***********設(shè)置待排序數(shù)據(jù)的位圖**************/
bool setBitmap(unsigned char *bitmap,char *fileName){
FILE *readFp;
printf("Setting bitmap...\n");
readFp = fopen(fileName,"r");
if(readFp == NULL)
return false;
long phoneNum=0;
while(fscanf(readFp,"%ld\n",&phoneNum) != EOF){
setOne(bitmap,phoneNum);//將 phoneNum位設(shè)置為1
}
fclose(readFp);
return true;
}
/*****順序遍歷位圖輸出記錄,從而實(shí)現(xiàn)排序****************/
bool getSorted(unsigned char *bitmap,char *fileName){
printf("Search bitmap...\n");
FILE *writeFp;
writeFp = fopen(fileName,"w");
if(writeFp == NULL)
return false;
long phoneNum=0;
for(phoneNum = 0; phoneNum < MAX_NUM; phoneNum += 1){
if(find(bitmap,phoneNum)){
fprintf(writeFp,"%ld\n",phoneNum);
}
}
fclose(writeFp);
return true;
}
/******先將位圖清零********/
void setAllZero(unsigned char *bitmap,long size){
for(long i=0;i<size;i++)
*(bitmap+i) &= 0;
}
/*************************************************
將指定的位置為1
(loc>>3)相當(dāng)于整除2^3=8,即定位到字節(jié)數(shù),MASK=0x07,loc&MASK相當(dāng)于loc%8
***************************************************/
void setOne(unsigned char *bitmap,long loc){
*(bitmap+(loc>>3)) |= (1<<(loc&MASK));//
}
/******查找指定的位是否為1********/
int find(unsigned char *bitmap,long loc){
return ((*(bitmap+(loc>>3))) & (1<<(loc&MASK))) == (1<<(loc&MASK));
}
C++的STL中有一個(gè)數(shù)據(jù)結(jié)構(gòu)bitset,操作位圖很方便。
#include <bitset>
#define MAX_NUM 4000000//最多的數(shù),即需要的位數(shù)
using namespace std;
int main(){
FILE *readFp,*writeFp;
readFp = fopen("phoneNumber1.txt","r");
writeFp = fopen("bitsetSorted.txt","w");
bitset<MAX_NUM> bitmap;
for(long i=0;i<MAX_NUM;i++){//先將位圖初試化為0
bitmap.set(i,0);
}
printf("Begin set bitmap...\n");
long number = 0;
while(fscanf(readFp,"%ld\n",&number) != EOF){
bitmap.set(number,1);//將number所在位設(shè)置為1
}
printf("Begin search bitmap...\n");
for(long i=0;i<MAX_NUM;i++){
if(bitmap[i] == 1)//將位1的位輸出到已排序文件
fprintf(writeFp,"%ld\n",number);
}
fclose(writeFp);
fclose(readFp);
}
排序算法很快就寫好了,就開始生成測(cè)試數(shù)據(jù),想生成0—2^31的亂序數(shù)據(jù)集還真不容易,首先要保證不重復(fù),第二要丟掉40%的數(shù)(無效手機(jī)號(hào)碼),第三要盡可能的亂序,搗了很久,最終還是找到了實(shí)現(xiàn)辦法,生成了12GB的數(shù)據(jù)集,關(guān)于生成這個(gè)數(shù)據(jù)集的辦法,歡迎一起討論,我將會(huì)在下一篇中總結(jié)一下我的方法。
完整的代碼可以參考github。
欄 目:C語言
下一篇:C語言解3元1次方程組 用初中學(xué)的最基本的聯(lián)合消元法
本文標(biāo)題:用位圖排序無重復(fù)數(shù)據(jù)集實(shí)例代碼(C++版)
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3914.html
您可能感興趣的文章
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用函數(shù)刪除字符
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言用函數(shù)寫分段 用c語言表示分段函數(shù)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排序法函數(shù)
- 04-02c語言分段函數(shù)怎么求 用c語言求分段函數(shù)
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求階乘
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)-用棧實(shí)現(xiàn)表達(dá)式求值的方法詳解
- 01-10使用OpenGL實(shí)現(xiàn)3D立體顯示的程序代碼
- 01-10HDOJ 1443 約瑟夫環(huán)的最新應(yīng)用分析詳解
- 01-10用貪心法求解背包問題的解決方法


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法