• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 經典算法- BitMap

    標簽: 算法  數據結構

    原文鏈接https://www.jianshu.com/p/6082a2f7df8e

    一、問題引入

    舉一個例子,有一個無序有界int數組{1,2,5,7},初步估計占用內存4X4=16字節,這倒是沒什么奇怪的,但是假如有10億個這樣的數呢,如果這樣的一個大的數據做查找和排序,那估計內存也崩潰了,有人說,這些數據可以不用一次性加載,那就是要存盤了,存盤必然消耗IO。我們提倡的是高性能,這個方案直接不考慮。

    二、問題分析

    bitmap: 基于位的映射

    一個byte是占8個bit,如果每一個bit的值就是有或者沒有,也就是二進制的0或者1,如果用bit的位置代表數組值有還是沒有,那么0代表該數值沒有出現過,1代表該數組值出現過。不也能描述數據了嗎?具體如下圖:

    在這里插入圖片描述
    這樣,一個占用32bit的數據現在只占用了1bit,節省了不少的空間,排序就更不用說了,一切顯得那么順利。這樣的數據之間沒有關聯性,要是讀取的,你可以用多線程的方式去讀取。時間復雜度方面也是O(Max/n),其中Max為byte[]數組的大小,n為線程大小。
    處。

    三、應用與代碼

    基于bit運算實現

    再看代碼之前,我們先搞清楚一個問題,一個數怎么快速定位它的索引號,也就是說搞清楚byte[index]的index是多少,position是哪一位。舉個例子吧,例如add(14)。14已經超出byte[0]的映射范圍,在byte[1]范圍之類。那么怎么快速定位它的索引呢。如果找到它的索引號,又怎么定位它的位置呢。Index(N)代表N的索引號,Position(N)代表N的所在的位置號。

    Index(N) = N/8 = N >> 3;

    Position(N) = N%8 = N & 0x07;

    1. add(int num)

    你要向bitmap里add數據該怎么辦呢,不用擔心,很簡單,也很神奇。
    上面已經分析了,add的目的是為了將所在的位置從0變成1.其他位置不變.
    下圖應是作或運算 )
    在這里插入圖片描述
    實例代碼

    public void add(int num){
            // num/8得到byte[]的index
            int arrayIndex = num >> 3; 
            
            // num%8得到在byte[index]的位置
            int position = num & 0x07; 
            
            //將1左移position后,那個位置自然就是1,然后和以前的數據做或運算,這樣,那個位置就替換成1了。
            bits[arrayIndex] |= 1 << position; 
        }
    

    2. clear(int num)

    對1進行左移,然后取反,最后與byte[index]作與操作。
    在這里插入圖片描述

    public void clear(int num){
            // num/8得到byte[]的index
            int arrayIndex = num >> 3; 
            
            // num%8得到在byte[index]的位置
            int position = num & 0x07; 
            
            //將1左移position后,那個位置自然就是1,然后對取反,再與當前值做&,即可清除當前的位置了.
            bits[arrayIndex] &= ~(1 << position); 
    
        }
    

    3. contain(int num)

    在這里插入圖片描述

     public boolean contain(int num){
            // num/8得到byte[]的index
            int arrayIndex = num >> 3; 
            
            // num%8得到在byte[index]的位置
            int position = num & 0x07; 
            
            //將1左移position后,那個位置自然就是1,然后和以前的數據做&,判斷是否為0即可
            return (bits[arrayIndex] & (1 << position)) !=0; 
        }
    

    全部代碼

    package com.chs.alg.bitmap;
    
    public class BitMap {
        //保存數據的
        private byte[] bits;
        
        //能夠存儲多少數據
        private int capacity;
        
        
        public BitMap(int capacity){
            this.capacity = capacity;
            
            //1bit能存儲8個數據,那么capacity數據需要多少個bit呢,capacity/8+1,右移3位相當于除以8
            bits = new byte[(capacity >>3 )+1];
        }
        
        public void add(int num){
            // num/8得到byte[]的index
            int arrayIndex = num >> 3; 
            
            // num%8得到在byte[index]的位置
            int position = num & 0x07; 
            
            //將1左移position后,那個位置自然就是1,然后和以前的數據做|,這樣,那個位置就替換成1了。
            bits[arrayIndex] |= 1 << position; 
        }
        
        public boolean contain(int num){
            // num/8得到byte[]的index
            int arrayIndex = num >> 3; 
            
            // num%8得到在byte[index]的位置
            int position = num & 0x07; 
            
            //將1左移position后,那個位置自然就是1,然后和以前的數據做&,判斷是否為0即可
            return (bits[arrayIndex] & (1 << position)) !=0; 
        }
        
        public void clear(int num){
            // num/8得到byte[]的index
            int arrayIndex = num >> 3; 
            
            // num%8得到在byte[index]的位置
            int position = num & 0x07; 
            
            //將1左移position后,那個位置自然就是1,然后對取反,再與當前值做&,即可清除當前的位置了.
            bits[arrayIndex] &= ~(1 << position); 
    
        }
        
        public static void main(String[] args) {
            BitMap bitmap = new BitMap(100);
            bitmap.add(7);
            System.out.println("插入7成功");
            
            boolean isexsit = bitmap.contain(7);
            System.out.println("7是否存在:"+isexsit);
            
            bitmap.clear(7);
            isexsit = bitmap.contain(7);
            System.out.println("7是否存在:"+isexsit);
        }
    }
    

    四、bitmap排序實例

    以下參考https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/06.07.html

    //定義每個Byte中有8個Bit位  
    #include <memory.h>  
    #define BYTESIZE 8  
    void SetBit(char *p, int posi)  
    {  
        for(int i=0; i < (posi/BYTESIZE); i++)  
        {  
            p++;  
        }  
    
        *p = *p|(0x01<<(posi%BYTESIZE));//將該Bit位賦值1  
        return;  
    }  
    
    void BitMapSortDemo()  
    {  
        //為了簡單起見,我們不考慮負數  
        int num[] = {3,5,2,10,6,12,8,14,9};  
    
        //BufferLen這個值是根據待排序的數據中最大值確定的  
        //待排序中的最大值是14,因此只需要2個Bytes(16個Bit)  
        //就可以了。  
        const int BufferLen = 2;  
        char *pBuffer = new char[BufferLen];  
    
        //要將所有的Bit位置為0,否則結果不可預知。  
        memset(pBuffer,0,BufferLen);  
        for(int i=0;i<9;i++)  
        {  
            //首先將相應Bit位上置為1  
            SetBit(pBuffer,num[i]);  
        }  
    
        //輸出排序結果  
        for(int i=0;i<BufferLen;i++)//每次處理一個字節(Byte)  
        {  
            for(int j=0;j<BYTESIZE;j++)//處理該字節中的每個Bit位  
            {  
                //判斷該位上是否是1,進行輸出,這里的判斷比較笨。  
                //首先得到該第j位的掩碼(0x01<<j),將內存區中的  
                //位和此掩碼作與操作。最后判斷掩碼是否和處理后的  
                //結果相同  
                if((*pBuffer&(0x01<<j)) == (0x01<<j))  
                {  
                    printf("%d ",i*BYTESIZE + j);  
                }  
            }  
            pBuffer++;  
        }  
    }  
    
    int _tmain(int argc, _TCHAR* argv[])  
    {  
        BitMapSortDemo();  
        return 0;  
    }
    
    版權聲明:本文為weixin_43260026原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/weixin_43260026/article/details/106572018

    智能推薦

    bitmap 算法的實現 與作用

    問題引入 有一個無序有界int數組{1,2,5,7},初步估計占用內存44=16字節,因為只有4個數,很容易,可以很快找到需要的數。但是假如有10億個這樣的數呢,10億個不重復并且沒有排過序的無符號的int整數,給出一個整數,找出給定的某個數,你該如何操作? 需求分析:Int類型在Java中的存儲占用4個Byte,32Bit。10億4/(102410241024)=3.72G左右。如果這樣的一個大...

    BitMap算法的說明以及驗證

    核心 1、什么是BitMap算法 2、BitMap的優缺點 3、BitMap的實現 4、BitMap 的比對 1、什么是BitMap算法 在大數據時代,我們如果將一個上億的整數文件來做排序或者查詢使用,這個就將面臨一個問題,內存不夠用,例如1億個整數的文件放入內存將會占用380MB(100000000*4/1024/1024)空間.如果是10億或者更多呢,這個將對內存是一個巨大的挑戰。為了解決這個...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    猜你喜歡

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    精品国产乱码久久久久久蜜桃不卡