1. 程式人生 > >Bitmap演算法及其應用——求素數

Bitmap演算法及其應用——求素數

        在學習hashtable的時候,發現用於標記懶惰刪除的資料結果是Bitmap,詳見資料結果習題解析(c++語言)(第三版) 鄧俊輝編著。理論上來說,可以用一個數組或者是std::vector來進行標記,但是Bitmap則具有更高的空間效率和時間效率。下面主要參考該書,對Bitmap進行了學習。

1. 什麼是Bitmap

1Byte = 8 bit,而Bitmap的每個bit位對應0或者1,代表真或假,bitmap則是一系列0與1構成的集合。如果用bool陣列來代表Hashtable的懶惰刪除標記,bool佔一個位元組,有8bit,其所佔空間為Bitmap的8倍。另外,bitmap不僅僅是空間效率高,還可以在O(1)時間內,對其進行賦值和讀取。

2. Bitmap的c++實現

/// @file bitmap.hpp
/// @brief declaration and implementation of bitmap class 
/// @author Shengfa Zhu, [email protected]
/// @version 1.0
/// @date 2018-03-06

#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>//header file of FILE, fopen, fread, fclose

class Bitmap {
private:
    char* M;//M[] is room for bitmap N * sizeof(char)*8 bit
    int N;

protected:
    void init(int n) {
        N = (n + 7) / 8;
        M = new char[N];
        memset(M, 0, N);
    }

public:
    
    /// @brief constructor
    Bitmap(int n = 8) {//creat bitmap with given size
        init(n);
    }

    /// @brief overide constructor 
    Bitmap(char* file, int n = 8) {//creat bitmap from file
        init(n);
        FILE* fp = fopen(file, "r");
        fread(M, sizeof(char), N, fp);
        fclose(fp);
    }

    /// @brief deconstructor
    ~Bitmap(){
        delete []M;
        M = NULL;
    }

    /// @brief set kth positon to 1
    void set(int k) {
        expand(k);
    //1 byte = 8 bit, 0x80=128, 0x07=7
    // a |= b :: a = a | b
        M[k >> 3] |= (0x80 >> (k & 0x07));//位操作
    }

    /// @brief clear kth positin of bitmap
    void clear(int k) {
        expand(k);
        M[k >> 3] &= ~(0x80 >> (k & 0x07));
    }

    /// @brief test ith is true or not
    bool test(int k) {
        expand(k);
        return M[k >> 3] & (0x80 >> (k & 0x07));
    }

    /// @brief expand room of M if k overflow
    void expand(int k) {
        if (k < 8 * N) return;
        int oldN = N;
        char* oldM = M;
        init(2 * k);//double size
        memcpy(M, oldM, oldN);//copy data to new M
        delete [] oldM;//release old room 
    }
    
    /// @brief convert n position to string
    char* bits2string(int n) {
        expand(n - 1);
        char* s = new char[n + 1];
        s[n] = '\0';
        for (int i = 0; i < n; i++) {
            s[i] = test(i) ? '1' : '0';
        }
        return s;
    }

    void dump(const char* file) {
        FILE* fp = fopen(file, "w");
        fwrite(M, sizeof(char), N, fp);
        fclose(fp);
    }
};

上述程式基本與資料結果習題解析(c++語言)(第三版) 鄧俊輝編著的P61-62相同。其中,以字元陣列來表示bitmap,在c++中char佔一個位元組,也就是8bit。在賦值的時候,由於無法對某個bit進行賦值操作,因此應用了位操作。

下面重點解釋下下面這行程式:

M[k >> 3] |= (0x80 >> (k & 0x07))

取k = 10 = 000001010(二進位制)為例,應當將第10個bit(0為起點)設為1,也就是第2個字元(以1為起點)中的第3個(以1為起點),而其他位保持不變。

k>>3 : 表示右移三位 k >>3 = 00000001=1, 取陣列的第2個字元進行操作;

k & 0x07 : 0x07(16進位制)= 7(10進位制)= 00000111 (2進位制),k & 0x07 = 000000010 = 2,

0x80 >>(k & 0x07) : 0x80(16進位制)= 128( 10進位制)= 10000000 (2進位制), 0x80 >>(k & 0x07) = 00100000

再經過一個與位操作之後,就可以將對應位置上的數設為1,而不影響其他位置。

從上面程式可以看出,set() clear() test()均是常數時間複雜度,並且使用了更為高效的位操作,有較高的效率。

3. Eratothenes篩法求素數

bitmap有很多的應用,例如可以用來不重複資料的排序,下面介紹如何基於bitmap求素數。先簡要介紹下一種求素數的演算法Eratothenes篩法。

自然數分為素數和合數,所有素數的整數倍均是合數,Eratothenes(希臘先哲)篩法就是基於上述的思想。從2開始對自然數進行遍歷,將2的整數倍的數去掉,然後遍歷到3, 將3的整數倍篩掉,在遍歷到5(4已經被去掉了), 將5的整數倍去掉,從此往後,剩下的數均是素數。

4. 基於Bitmap類 Eratothenes篩法的實現

可以基於Bitmap方便地實現Eratothenes演算法求得不超過n的所有素數,首先0和1不是素數。從2開始遍歷到n,將素數的整數倍所對應的bit位置設為1。遍歷完成之後,所有bit位是0的數就是不超過n的所有素數。

void Eratothenes(const int& n) {
    Bitmap B(n);
    B.set(0);//0 is not prime number
    B.set(1);//1 is not prime number
    for(int i = 2; i < n; i++) {
        if(!B.test(i)) 
            for(int j = i * i; j < n; j += i)
                B.set(j);
    }
    //print to monitor
    for(int i = 2; i < n; i++) {
        if(!B.test(i))
            std::cout << i << "\t";
    }
    std::cout << std::endl;
}

以上內容,大都參考鄧俊輝老師編寫的教材,將其記錄下來方便自己自學

相關推薦

Bitmap演算法及其應用——素數

        在學習hashtable的時候,發現用於標記懶惰刪除的資料結果是Bitmap,詳見資料結果習題解析(c++語言)(第三版) 鄧俊輝編著。理論上來說,可以用一個數組或者是std::vector來進行標記,但是Bitmap則具有更高的空間效率和時間效率。下面主要參

圖論初步-Tarjan演算法及其應用

暑假刷了一堆Tarjan題到頭來還是忘得差不多。 這篇部落格權當複習吧。 一些定義 無向圖 割頂與橋 (劃重點) 圖G是連通圖,刪除一個點表示刪除此點以及所有與其相連的邊。 若刪除某點u後G不再連通,那麼u是G的一個割頂(割點)。 若刪除某邊e後G不再連通,那麼e是G的一個橋。 雙連通 一個圖為雙

面試:解決重點問題,計算兩個時間段是否有交集的演算法及其應用例項

1、通過 if 判斷語句進行判斷,if(endTime1 > startTime2 && endTime2 > startTime1) 那麼這兩個時間段有交集,一個時間段的結束時間大於另一個時間段的開始時間,如果成立那麼兩個時間段有交集。

Java:演算法 - 整數區間素數

題目:判斷101-200之間有多少個素數,並輸出所有素數。 程式分析:判斷素數的方法:用一個數分別去除2到sqrt(這個數),如果能被整除,則表明此數不是素數,反之是素數。 吐槽:簡單的題,想仔細需要的引數,邏輯,邊界控制,爭取一次寫對。 程式碼: package com.oz.

解讀 2016 年十大機器學習演算法及其應用

毫無疑問,過去兩年中,機器學習和人工智慧的普及度得到了大幅提升。   如果你想學習機器演算法,要從何下手呢?以我為例,我是在哥本哈根留學期間,學習AI課程入門的。我們用的教科書是一本AI經典:《Peter Norvig’s Artificial Intelligence —

KNN演算法及其應用

一、KNN演算法介紹 1. 綜述 1.1 Cover和Hart在1968年提出了最初的鄰近演算法 1.2 分類(classification)演算法 1.3 輸入基於例項的學習(instance-based learnin

基於MATLAB的dijkstra演算法及其應用

clc; clear; close all; %% 載入設定資料 points = load('c:\\niu\\點的資料.txt'); lines = load('c:\\niu\\邊資料.txt'); A = ones(size(points, 1))*Inf; for i = 1 : size(A, 1

決策樹演算法及其應用案例

決策樹演算法主要分為三類: ID3、C4.5、CART演算法 以ID3演算法為例: 對上表某圖書銷量進行預測. 思考:建立測試模型,各個變數資料權重?資料的轉化? 重點在於:計算各個資訊熵(資料預處理),可參考百度百科內容 決策樹演算法模組: 關注點:對資料需要進行預處理,

遺傳演算法及其應用簡介

遺傳演算法(genetic algorithm,GA)是計算數學中用於解決最優化問題的搜尋演算法,是進化演算法的一種。進化演算法最初是借鑑了達爾文進化生物學中的一些現象而發展起來的,這些現象包括遺傳、突變、自然選擇以及雜交等。 預備知識:達爾文進化論,遺傳學三

manacher演算法及其應用

最近學習了牛客網的演算法初級班,學到了一些經典演算法 這裡整理一下manacher演算法,自己參考老師給的程式碼,轉成C++程式碼 #ifndef MANACHER_H #define MANACHER_H //Manacher演算法 :找出字串str中最長的迴文子串 #d

EM演算法及其應用

EM演算法簡介 首先上一段EM演算法的wiki定義: expectation–maximization (EM) algorithm is an iterative method to find maximum likelihood(MLE)

Flajolet-Martin演算法及其應用

來源:http://www.pluscn.net/?p=1192 對應的程式碼(maybe):https://github.com/graphlab-code/graphlab/blob/master/toolkits/graph_analytics/approxima

圖的點著色、區間著色問題及其應用(基於貪心思想的DFS回溯法點著色問題和區間著色演算法求解任務排程問題)

Graph Coloring Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 4503 Accepted: 2059 Special Judge Description You are

素數序列的生成及其應用(采用了新學的更高效的算法:布爾標記法 + 倍數淘汰法)

lin ++ lse 大於 所有 void ont null -a 問題: 不超過2000的素數有哪些? 她的QQ號是素數嗎? 解決: 已知: 1不是素數 2是素數 大於2的偶數不是素數 大於2的素數是奇數 當自然數k > 1時,素數的k被數不是素數 策略:

素數序列的生成及其應用 Advanced Version 1

one version 全部 text 硬盤 tar TP AD edr 算法依據: 若某大於1的整數N的算術平方根以內的所有素數都不能整除N,那麽N是素數。 數據容器: 小型數組BUFFER、二進制文件CACHE 程序特性: 理論上使用極少的內存(0.5MB左右)就能獲取

菜鷄日記——KMP演算法及其優化與應用

一、什麼是KMP演算法 KMP演算法,全稱Knuth-Morris-Pratt演算法,由三位科學家的名字組合命名,是一種效能高效的字串匹配演算法。假設有主串S與模式串T,KMP演算法可以線上性的時間內匹配出S中的T,甚至還能處理由多個模式串組成的字典的匹配問題。 二、KMP演算法原理及實現

《資料結構與演算法設計》實驗報告書之二叉樹的基本操作實現及其應用

《資料結構與演算法設計》實驗報告書之二叉樹的基本操作實現及其應用 實驗專案 二叉樹的基本操作實現及其應用 實驗目的 1.熟悉二叉樹結點的結構和對二叉樹的基本操作。 2.掌握對二叉樹每一種操作的具體實現。 3.學會利用遞迴方法編寫對二叉樹這種遞迴資料結構進行處理的演算法。 4.會用二叉

BitMap演算法應用詳解

  所謂的BitMap就是用一個bit位來標記某個元素所對應的value,而key即是該元素,由於BitMap使用了bit位來儲存資料,因此可以大大節省儲存空間。 基本思想:   這此我用一個簡單的例子來詳細介紹BitMap演算法的原理。假設我們要對0-7內的5個

演算法模板】尤拉篩法素數

#include<iostream> using namespace std; const int MAXN=1000000+10; int n,cnt,prime[MAXN]; bool vis[MAXN]; void findprime(int n)

經典的同態濾波演算法的優化及其應用引數配置。

% 同態濾波器 % ImageIn - 需要進行濾波的灰度影象 % High - 高頻增益,需要大於1 % Low - 低頻增益,取值在0和1之間 % C - 銳化係數 % Sigma - 截止頻率,越大影象越亮 % 輸出為進行