C++中的位运算和位图bitmap解析

目录
  • 位运算总结
    • 移位运算
    • 位运算应用举例
  • 位图

位运算总结

移位运算

  • 移位运算是双目运算符,两个运算分量都是整形,结果也是整形。
  • “<<” 左移:右边空出的位上补0,左边的位将从首位挤掉,其值相当于乘2。
  • ">>"右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。

二进制补码运算公式:

-x = ~x + 1 = ~(x-1)
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y:    ~(x-y|y-x)
x!=y:    x-y|y-x
x< y:    (x-y)^((x^y)&((x-y)^x))
x<=y:    (x|~y)&((x^y)|~(y-x))
x< y:    (~x&y)|((~x|y)&(x-y))//无符号x,y比较
x<=y:    (~x|y)&((x^y)|~(y-x))//无符号x,y比较

位运算应用举例

(1) 判断int型变量a是奇数还是偶数

a&1 = 0 偶数
a&1 = 1 奇数

(2) 取int型变量a的第k位 (k=0,1,2……sizeof(int)),即a>>k&1

(3) 将int型变量a的第k位清0,即

a = a&~(1<<k)

(4) 将int型变量a的第k位置1,

a=a|(1<<k)

(5) int型变量循环左移k次,

a=a<<k|a>>sizeof(unsigned int)*8-k   

(6) int型变量a循环右移k次,

a=a>>k|a<<sizeof(unsigned int)*8-k   

(7) 整数的平均值

对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,但是我们知道它们的平均值是肯定不会溢出的,我们用如下算法:

int average(int x, int y)   //返回X,Y 的平均值
{
     return (x&y)+((x^y)>>1);
}

(8)判断一个整数是不是2的幂,对于一个数 x >= 0,判断他是不是2的幂

bool power2(int x)
{
    return ((x&(x-1))==0)&&(x!=0);
}

(9)不用 temp交换两个整数,可以是负整数

void swap( int& x , int& y)
{
    x ^= y;
    y ^= x;
    x ^= y;
}

void swap01(int& x , int& y){
   x += y;
   y = x - y;
   x = x - y;
}

(10) 计算绝对值

int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ;        //or: (x+y)^y
}

int abs01(int a){
	return (a>0)?a:(~a+1);
}

(11) 取模运算转化成位运算 (在不产生溢出的情况下)

a % (2^n) 等价于 a & (2^n - 1)

(12)乘法运算转化成位运算 (在不产生溢出的情况下)

a * (2^n) 等价于 a<< n

(13)除法运算转化成位运算 (在不产生溢出的情况下)

  a / (2^n) 等价于 a>> n
    例: 12/8 == 12>>3

(14) a % 2 等价于 a & 1

(15) x 的 相反数 表示为 (~x+1)

(16)两整数相加,可以是负整数

int add(int a,int b){
	while(b!=0){
		int temp=a^b;
		b=(unsigned int)(a&b)<<1;
		a = temp;
	}
	return a;
}

位图

题目

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

思路

这道题首先要判断40亿个不重复的无符号整数究竟占多大的内存,因为太大的内存我们无法加载到现有的计算机中。

一个整数是4个字节,40亿个整数就是160亿个字节,也就相当于16G内存,就一般的计算机而言很难实现这个加载,所以我们可以采取以下两种方案,一种是分割,一种是位图。

方法

①分割

采用分割处理,把40亿个数分批次处理完毕,当然可以实现我们最终的目标,但是这样做时间复杂度未免优点太高。

②位图BitMap

在介绍这种方法前我首先来介绍一下什么是位图。

位图BitMap:位图是一个数组的每一个数据的每一个二进制位表示一个数据,0表示数据不存在,1表示数据存在。

如上所示,当我们需要存放一个数据的时候,我们需要安装以下方法:

首先确定这个数字在整个数据的哪一个数据(区间)。

确定这个数据(区间)的哪一个Bit位上。

在这个位上置1即可。

实现代码:

#include <iostream>
#include <vector>
using namespace std;

class BitMap
{
public:
    BitMap(size_t range)
    {
        //此时多开辟一个空间
        _bits.resize(range / 32 + 1);
    }
    void Set(size_t x)
    {
        int index = x / 32;//确定哪个数据(区间)
        int temp = x % 32;//确定哪个Bit位
        _bits[index] |= (1 << temp);//位操作即可
    }
    void Reset(size_t x)
    {
        int index = x / 32;
        int temp = x % 32;
        _bits[index] &= ~(1 << temp);//取反
    }
    bool Test(size_t x)
    {
        int index = x / 32;
        int temp = x % 32;
        if (_bits[index]&(1<<temp))
            return 1;
        else
            return 0;
    }

private:
    vector<int> _bits;
};

void TestBitMap()
{
    BitMap am(-1);
    BitMap bm(200);
    bm.Set(136);
    bm.Set(1);
    cout << bm.Test(136) << endl;
    bm.Reset(136);
    cout << bm.Test(136) << endl;
}

int main()
{
    TestBitMap();
    return 0;
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 海量数据处理系列之:用C++实现Bitmap算法

    bitmap是一个十分有用的结构.所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省. 适用范围:可进行数据的快速查找,判重,删除,一般来说数据范围是int的10倍以下基本原理及要点:使用bit数组来表示某些元素是否存在,比如8位电话号码扩展:bloom filter可以看做是对bit-map的扩展问题实例:1)已知某个文件内包含一些电话号码,每个号码为8位数字,统计不同号码的个数.8位最

  • C++ 位图及位图的实现原理

    概念 位图就是bitmap的缩写,所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,该数据都是不重复的简单数据.通常是用来判断某个数据存不存在的 例如:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中 如果不看数据量,我们第一想到的肯定就是依次从头遍历,但是这个数据量是非常大的,有40亿,遍历40亿次消耗的时间和内存是非常多的.但是引入位图后,就可以专门解决这种大量数据查找是否存在的问题.查找这个数是否存在所消耗

  • C++中Cbitmap,HBitmap,Bitmap区别及联系

    加载一位图,可以使用LoadImage: HANDLE LoadImage(HINSTANCE hinst,LPCTSTR lpszName,UINT uType,int cxDesired,int CyDesired,UINT fuLoad): LoadImage可以用来加载位图,图标和光标 加载时可以规定加载图的映射到内存的大小: cxDesired:指定图标或光标的宽度,以像素为单位.如果此参数为零并且参数fuLoad值中LR_DEFAULTSIZE没有被使用,那么函数使用目前的资源宽度.

  • C++中的位运算和位图bitmap解析

    目录 位运算总结 移位运算 位运算应用举例 位图 位运算总结 移位运算 移位运算是双目运算符,两个运算分量都是整形,结果也是整形. “<<” 左移:右边空出的位上补0,左边的位将从首位挤掉,其值相当于乘2. ">>"右移:右边的位被挤掉.对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统. 二进制补码运算公式: -x = ~x + 1 = ~(x-1) -(~x) = x+1 ~(-x) = x-1 x+y = x -

  • 详细聊聊React源码中的位运算技巧

    目录 前言 几个常用位运算 按位与(&) 按位或(|) 按位非(-) 标记状态 优先级计算 总结 前言 这两年有不少朋友和我吐槽React源码,比如: 调度器为什么用小顶堆这种数据结构,直接用数组不行? 源码里各种单向链表.环状链表,直接用数组不行? 源码里各种位运算,有必要么? 作为业务依赖的框架,为了提升一点点运行时性能,React从不吝惜将源码写的很复杂. 在涉及状态.标记位.优先级操作的地方大量使用了位运算. 本文会讲解其中比较有代表性的部分.学到之后,当遇到类似场景时露一手,你就是业务

  • C#枚举中的位运算权限分配浅谈

    常用的位运算主要有与(&), 或(|)和非(~), 比如: 1 & 0 = 0, 1 | 0 = 1, ~1 = 0 在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理. 第一步, 先建立一个枚举表示所有的权限管理操作: 复制代码 代码如下: [Flags] public enum Permissions { Insert = 1, Delete = 2, Update = 4, Query = 8 } [Flags]表示该枚举可以支持C#位运算, 而枚举的每一项值, 我们用2的

  • Java 中的位运算与移位运算详解

    目录 位运算 按位"与" & 按位"或" | 异或 ^ 移位运算 左移 << 右移 >> 无符号右移 >>> 总结 位运算 按位"与" & 规则: 如果两个相应的二进制形式的对应的位数都为 1,则结果为 1:否则为 0: 4 & 5 4 0000 0100 5 0000 0101 按位与运算 & 4 & 5 = 4 0000 0100 1 * 2^2 = 4 -4

  • Java中的位运算符全解

    目录 1.&(按位与运算符) 2.|(按位或运算符) 3.^(异或运算符) 4.<<(左移运算符) 5.>>(右移移运算符) 6.~(取反运算符) 7.>>>(无符号右移运算符) (1)正数无符号右移 (2)负数无符号右移 总结 1. &(按位与运算符) &按位与的运算规则是将两边的数转换为二进制位,然后运算最终值,运算规则即(两个为真才为真):1&1=1 , 1&0=0 , 0&1=0 , 0&0=0 pu

  • 谈谈C语言中位运算你要知道的那些事儿

    目录 一.概念说明 1.概念 1.1位运算 1.2位运算符 2.举例及补充 2.1位运算 2.2位运算符 二.问题实战 1.问题描述(开放题) 2.输入输出 三.源码实现(+详细注释) 1.注释版 2.纯源码版 四.输出结果展示 1.输出结果 总结 一.概念说明 1.概念 先来看一下位运算的概念: 1.1位运算 位运算简单来说,就是按二进制位进行运算. 位运算: 从现代计算机中所有的数据二进制的形式存储在设备中.即 0.1 两种状态,计算机对二进制数据进行的运算(+.-.*./)都是叫位运算,即

  • JAVA位运算的知识点总结

    一.在计算机中数据是如何进行计算的? 1.1:java中的byte型数据取值范围 我们最开始学习java的时候知道,byte类型的数据占了8个bit位,每个位上或0或1,左边第一位表示符号位,符号位如果为1表示负数,为0则表示正数,因此要推算byte的取值范围,只需要让数值位每一位上都等于1即可. 我们来用我们的常规思维来分析下byte类型的取值范围: 图1 如果按照这种思路来推算,七个1的二进制数转换为十进制是127,算上符号位,取值范围应为:-127~+127,但事实上我们知道,byte的取

  • Java位运算知识点详解

    在日常的Java开发中,位运算使用的不多,使用的更多的是算数运算(+.-.*./.%).关系运算(<.>.<=.>=.==.!=)和逻辑运算(&&.||.!),所以相对来说对位运算不是那么熟悉,本文将以Java的位运算来详细介绍下位运算及其应用. 1. 位运算起源 位运算起源于C语言的低级操作,Java的设计初衷是嵌入到电视机顶盒内,所以这种低级操作方式被保留下来.所谓的低级操作,是因为位运算的操作对象是二进制位,但是这种低级操作对计算机而言是非常简单直接,友好高效

  • JS通过位运算实现权限加解密

    首先介绍一下js中的位运算: 1. "&" :与运算,转化为二进制数,如果相同位数都为1则得结果为1,否则为0: 2. "|" :或运算,转化为二进制数,如果相同位数只要有一个为1则得结果为1,否则为0: 3. "^" :异或运算,转化为二进制数,如果相同位数不同则得结果为1,否则为0: 4."<<" 异位运算符,1<<1,表示将1左移一位,也就是010,在二进制中代表2: 顺便说一下,十进制数

  • PHP 使用位运算实现四则运算的代码

    计算机最基本的操作单元是字节,一个字节由8个位组成,一个位只能存储一个0或1.所有数据在计算机中都是采用二进制,即 1 和 0 的编码存储和运算. 这次尝试在 PHP 中使用位运算实现四则运算,首先介绍一些基本概念: 原码:将最高位作为符号位(0表示正,1表示负),其它数字位代表数值本身的绝对值 反码:正数反码和原码一样:如果是负数,符号位不变,其余各位取反 补码:正数补码和原码一样:负数补码为反码加 1 计算机中的数使用 补码  的形式存储 ⒈ 加法 二进制中只有 0 和 1,0 + 0.0

随机推荐