位图

例题1

给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在 这40亿个数中。

首先肯定不能用传统的int数据存储  因为内存不够  40亿的整数大概为16G左右

思路1: 因为byte位数据小 1字节就有8个byte 那么40亿byte数据大概只有500mb左右

    template<size_t N>//先开好总有数据大小
    class moxuan_bit
    {
    public:
        //开空间
        moxuan_bit()
        {
            //char类型有8个字节  所以N个数据就/8即可  假如开10 只开了一个char  不够 所以
            //要+1
            _bits.resize(N / 8 + 1, 0);
        }

        //把x映射的位置标记成1  表示存在
        void set(size_t x)
        {
            //计算在第几个char范围内
            size_t i = x / 8;

            //计算在第i个char范围内的第几个
            size_t j = x % 8;

            _bits[i] |= (1 << j);
        }

        void reset(size_t x)
        {
            //计算在第几个char范围内
            size_t i = x / 8;

            //计算在第i个char范围内的第几个
            size_t j = x % 8;

            //将第j个数改为1  然后取反  其他bit位变为1  j的数变为0
            //这时候 按位与  其他比特位为不变  j的比特位为0  就删除了这个值不存在
            _bits[i] &= (~(1 << j));
        }

        bool test(size_t x)
        {
            //计算在第几个char范围内
            size_t i = x / 8;

            //计算在第i个char范围内的第几个
            size_t j = x % 8;

            //如果跟1是相同 就返回1 true  如果跟1不相同 就返回0 false
            //并且不是&= 不会改变里面的值
            return _bits[i] & (1 << j);

        }

    private:
        std::vector<char> _bits;
    };

 

 测试:

    void test1()
    {
        moxuan_bit<100> v;
        v.set(20);
        v.set(77);
        v.set(0);

        cout << v.test(20) << " " << v.test(77) << " " << v.test(0) << endl;

        v.reset(0);

        cout << v.test(20) << " " << v.test(77) << " " << v.test(0) << endl;
    }

 

例题2:

. 给定100亿个整数,设计算法找到只出现一次的整数?

思路 :用两个位图表示  大概数据量为 1G

    template<size_t N>
    class two_bit
    {
    public:
        void set(size_t x)
        {
            //返回它的状态 1或 0
            int in1 = bit1.test(x);
            int in2 = bit2.test(x);
            //当两个都为0 状态改为 0 1
            if (in1 == 0 && in2 == 0)
            {
                bit2.set(x);
            }
            //当为 01 存在时 又遇到了  就改为 10  表示存在1次以上
            else if(in1==0&&in2==1)
            {
                bit1.set(x);
                bit2.reset(x);
            }
        }

        //如果该值为  0 1 表示就存在过一次 
        bool is_once(size_t x)
        {
            return bit1.test(x) == 0 && bit2.test(x) == 1;
        }

    private:
        //用两个位图表示3种状态   0  0 表示不存在 0 1 表示存在一次 1 0 表示存在一次以上
        moxuan_bit<N> bit1;
        moxuan_bit<N> bit2;
    };

 

 测试:

    void test2()
    {
        two_bit<13> v1;
        int a[] = { 5,8,9,2,5,9,4,2,1,0,7,6,5 };

        for (auto e : a)
        {
            v1.set(e);
        }

        for (int i = 0; i <= 10; i++)
        {
            if (v1.is_once(i))
            {
                cout << i << " ";
            }
        }
    }

 

按位与

按位“与”运算符 (&) 会将第一操作数的每一位与第二操作数的相应位进行比较。如果两个位均为 1,则对应的结果位将设置为 1。否则,将对应的结果位设置为 0。

| 按位或:

按位“与或”运算符 (|) 将第一个操作数的每个位与第二个操作数的对应位进行比较。如果其中一个位是 1,则将对应的结果位设置为 1。否则,将对应的结果位设置为 0。

^ 按位异或:

按位“异或”运算符 (^) 将第一操作数的每个位与第二操作数的相应位进行比较。如果一个位是 0,另一个位是 1,则相应的结果位将设置为 1。否则,将对应的结果位设置为 0。

~取反:

若操作数为1 设置为0 若为1 则设置为1

>>右移 实际不是向右移动 而是向低位移动

<<左移 实际不是向右移动 而是向高位移动

posted @ 2022-09-15 18:04  lemon-Breeze  阅读(14)  评论(0编辑  收藏  举报