數據結構面試題之位圖查找

題目: 給40個億不重複的無符號整數,沒有排序過,隨機給出一個無符號整數,快速的判斷這個數在或者不在40億個數中?

1. 思路 

  有的人一看到這個題,很簡單嘛最麻煩的就是從頭遍歷一遍的事情嘛. 不過要看清楚題! 40億個無符號整數.  咱們生活中1G內存佔用的字節數1024*1024*1024爲1073741824個字節.粗略就是10億個字節. 而40億個無符號整數是160億個字節. 也就是這些數據存儲下來須要16G的內存. 那麼問題來了,普通的工做電腦的內存都4G,好點的就是8G. (若是你是16G內存光速吃雞那麼當我沒說)咱們能夠發現這些數據的內存大於電腦的內存因此存儲不下. 這個時候就很頭大了,內存都存不下那麼你怎麼讀取呢? 固然你說你直接去硬盤裏面讀.好! 沒問題.從硬盤裏面讀取數據的速度和從內存中讀取的速度根本沒得比的.若是你的時間多也能夠.不過咱們有一個更厲害的方法就是咱們的位圖.位圖就是給定一段連續的空間而後讓這個空間的每一位都爲0,再而後讓每個位表示一個數字.再而後當你這個數字出現的 時候將它對應的那個位->置爲1.這樣的話存儲40億個數據,也就是存儲40億個位.也就是5億個字節.大概512MB的樣子. 這樣的話咱們的內存存儲這些數據也就是綽綽有餘了.因此位圖對於大數據的問題有着顯著的效果。

2. 代碼實現

#include "stdio.h"

// 用位圖的方式實現大數據的查找
#include <vector>
#include <iostream>
using namespace std;

class CBitmapFind
{
    enum{INFOBITS_IN_VECT = 8};
public:
    // 肯定容器大小
    explicit CBitmapFind(size_t nRange = 0)
    {
        BitmapVect.resize(nRange / INFOBITS_IN_VECT + 1);
    }
    // 添加單個元素並標記該元素
    void AddElement(int nNum)
    {
        // 肯定該數據所在vect中的位置
        int nVectIndex = nNum / INFOBITS_IN_VECT;
        // 肯定在vect索引中的byte位置
        int nByteIndex = nNum % 8;
        
        BitmapVect[nVectIndex] |= (1 << nByteIndex);
    }
    // 刪除單個元素並移除單個元素
    void MoveElement(int nNum)
    {
        // 肯定該數據所在vect中的位置
        int nVectIndex = nNum / INFOBITS_IN_VECT;
        // 肯定在vect索引中的byte位置
        int nByteIndex = nNum % 8;
        
        BitmapVect[nVectIndex] &= ~(1 << nByteIndex);
    }

    bool TestBit(int nNum)
    {
        // 肯定該數據所在vect中的位置
        int nVectIndex = nNum / INFOBITS_IN_VECT;
        // 肯定在vect索引中的byte位置
        int nByteIndex = nNum % 8;

        return (BitmapVect[nVectIndex] & (1 << nByteIndex)? true:false);
    }
private:
    vector<char> BitmapVect;
};

3. 擴展:判斷出現是次數是否大於3

// 用位圖的方式實現大數據的查找,判斷出現的次數,下面的代碼只能處理出現次數小於等於3的狀況
// 00 01 10 11
class CNBitmapFind
{
public:
    enum{ INFOBITS_IN_VECT = 4 };
    // 肯定容器大小
    explicit CNBitmapFind(size_t nRange = 0)
    {
        BitmapVect.resize(nRange / INFOBITS_IN_VECT + 1);
    }
    // 添加單個元素並標記該元素出現的次數
    void AddElement(int nNum)
    {
        // 肯定該數據所在vect中的位置
        int nVectIndex = nNum / INFOBITS_IN_VECT;
        // 肯定元素在vect索引中的byte位置
        int nByteIndex = nNum % INFOBITS_IN_VECT;
        nByteIndex *= 2;

        bool first = BitmapVect[nVectIndex] & (1 << nByteIndex);
        bool second = BitmapVect[nVectIndex] & (1 << (nByteIndex + 1));

        if (!(first && second))
        {
            BitmapVect[nVectIndex] += (1 << nByteIndex);
        }
    }

    int Test(int nNum)
    {
        // 肯定該數據所在vect中的位置
        int nVectIndex = nNum / INFOBITS_IN_VECT;
        // 肯定元素在vect索引中的byte位置
        int nByteIndex = nNum % INFOBITS_IN_VECT;

        nByteIndex *= 2;
        int first = BitmapVect[nVectIndex] & (1 << nByteIndex)?1:0;
        int second = BitmapVect[nVectIndex] & (1 << (nByteIndex + 1))?1:0;

        return second * 2 + first;
    }
private:
    vector<char> BitmapVect;
};

4. 測試

void main()
{
    int nReange = 4 * pow(10, 2);
    CBitmapFind BitmapFind(nReange);
    for (int i = 0; i < nReange; i++)
    {
        BitmapFind.AddElement(i);
    }
    cout << "CBitmapFind測試:" << endl;
    BitmapFind.TestBit(401) ? (cout << "找到:" << 401 << endl) : (cout << "未找到" << 401 << endl);
    BitmapFind.TestBit(388) ? (cout << "找到" << 388 << endl) : (cout << "未找到" << 388 << endl);

    CNBitmapFind NBitmapFind(6);
    NBitmapFind.AddElement(1);
    NBitmapFind.AddElement(1);
    NBitmapFind.AddElement(1);
    NBitmapFind.AddElement(2);
    NBitmapFind.AddElement(2);
    NBitmapFind.AddElement(3);

    cout << "CNBitmapFind測試:" << endl;
    cout << "1出現的次數:" << NBitmapFind.Test(1) << endl;
    cout << "2出現的次數:" << NBitmapFind.Test(2) << endl;
    cout << "3出現的次數:" << NBitmapFind.Test(3) << endl;
}

相關文章
相關標籤/搜索