編程珠璣:位圖法排序


問題描述

輸入:一個最多包含n個正整數的文件,每個數都小於n,其中n=107。如果在輸入文件中有任何正數重復出現就是致命錯誤。沒有其他數據與該正數相關聯。

輸出:按升序排列的輸入正數的列表。

約束:最多有1MB的內存空間可用,有充足的磁盤存儲空間可用。運行時間最多幾分鍾,運行時間為10秒就不需要進一步優化。

程序設計與實現概要:

應用位圖或位向量表示集合。可用一個10位長的字符串來表示一個所有元素都小於10的簡單的非負整數集合,例如,可以用如下字符串表示集合{1,2,4,5,8}:

0  1  1  1  0  1  0  0  1  0  0

代表集合中數值的位都置為1,其他左所有的位置為0.編程珠璣當中建議是一年個一個具有1000萬個位的字符串來表示這個文件,那么這個文件的所占容量為10000000 bit=107bit,不到1MB的大小,其中,當且精當整數i在文件中存在,第i為1,這個表示利用了該問題的三個在排序問題中不常見的屬性:輸入數據限制在相對較小的范圍內;數據沒有重復;而且對於每條記錄而言,除了單一個整數外沒有其他關聯數據。

如給定表示文件中整數集合的位圖數據結構,則可以分三個階段來編寫程序

第一階段:將所有的位都置為0,從而將集合初始化為空。

第二階段:通過讀入文件中的每個整數來建立集合,將每個對應的位置都置為1。

第三階段:檢驗每一位,如果該為為1,就輸出對應的整數,有此產生有序的輸出文件。

 

 

 

下面的C語言的實現和C++的實現代碼

C語言:

所申請的int數組如下所示:

字節位置=數據/32;(采用位運算即右移5位)

位位置=數據%32;(采用位運算即跟0X1F進行與操作)。

 

#include <stdio.h>
#define MAX 10000000
#define SHIFT 5           
#define MASK 0x1F
#define DIGITS 32


int a[1+MAX/DIGITS];

void set(int n)                                //將邏輯位置為n的二進制位置為1 
{
    a[n>>SHIFT] |=(1<<(n&MASK));               //n>>SHIFT右移5位相當於除以32求算字節位置,n&MASK相當於對32取余即求位位置,
}                                                

void clear(int n)
{
    a[n>>SHIFT] &=(~(1<<(n&MASK)));           //將邏輯位置為n的二進制位置為0
}

int test(int n)
{
    return a[n>>SHIFT] & (1<<(n&MASK));        //測試邏輯位置為n的二進制位是否為1 
}

int main(int argc, char *argv[])
{
    int i,n;
    for(i=1;i<=MAX;i++)
    {
        clear(i);
    }    
    while(scanf("%d",&n)!=EOF)
    {
        set(n);
    }
    for(i=1;i<=MAX;i++)
    {
        if(test(i))
            printf("%d ",i);
    }
    return 0;
}

 

C++(使用bitset)

#include <iostream>
#include<bitset> 

using namespace std;


int main(int argc, char *argv[])
{
    const int max = 10000000;
    
    int n,i;
    bitset<max+1> bit;                     //初始默認所有二進制位為0 
    
    while(scanf("%d",&n)!=EOF)
    {
        bit.set(n,1);                   //將第n位置1               
    }    
    for(i=0;i<=max+1;i++)
    {
        if(bit[i]==1)
            printf("%d ",i);
    }
    return 0;
}


---------------------------------------------------

 擴展:
 
給40億個不重復的unsigned int的整數,沒有排過序,然后再給一個數,如果快速判斷這個數是否在那40億個數當中。(騰訊面試題)
 
用位圖法:40億unsigned int,則用位圖表示的話需要大小為40億個bit=4*10 9 bit=0.5*10 9 bytes 因此申請的內存只需要大小約為512MB左右,這樣在內存每個bit代表一個unsigned int整數,並將每個bit初始化為0,然后將40億個unsigned int的整數讀入,每個unsigned int的整數對應bit設置為1,讀入后,最后看所給定的數對應的bit是否為1,是1存在,否則不存在。
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM