标签: C++ bitset 位运算
by 小威威
bitset能实现对数字的位的操作,同时也能通过类似于数组的下标来访问各个位的数值,以执行相应的操作。模拟bitset就是用一个普通的数组来存储数据以达到模拟的目的。
先声明一下,本篇文章并不是讲述标准库中bitset这个类的用法,而是去讲述如何实现一个模拟bitset的类。
众所周知,int类型在64位系统中占4个字节,也就是32位,倘若我建立一个大小为5的数组,那么我就能存储5*32=160个位。然后我可以通过对数组的每个元素单独处理,通过位运算,来实现对位的操作。
bitset.h如下:
#ifndef BITSET_H
#define BITSET_H
#include<iostream>
#define N 5
const int max_length = 32 * N;
class bitset {
private:
int a[N];
public:
bitset(); // 初始化全部置0
void set(int pos); // 将pos位变为1
void reset(int pos); // 将pos位变为0
int count() const; // 计算1的个数
bool test(int pos) const; // 检测位的数据是否为1
bool any() const; // 检测是否存在1
bool none() const; // 检测是否不存在1
bool all() const; // 检测是否全为1
bitset& operator&= (const bitset& b);
bitset& operator|= (const bitset& b);
bitset& operator^= (const bitset& b);
bitset& operator= (const bitset& b);
bitset& operator <<= (int pos);
bitset& operator >>= (int pos);
bitset operator~() const;
bitset operator&(const bitset& b) const;
bitset operator|(const bitset& b) const;
bitset operator^(const bitset& b) const;
bitset operator<<(int pos) const;
bitset operator>>(int pos) const;
bool operator== (const bitset& b) const;
bool operator!= (const bitset& b) const;
bool operator[] (int pos) const; // 下标访问
friend std::ostream& operator << (std::ostream& os, const bitset& s) {
for (int i = N-1; i >= 0; i--) {
for (int j = 31; j >= 0; j--) {
if (s.a[i] & (1 << j)) os << 1;
else os << 0;
}
}
return os;
}
};
#endif
要完成该模拟,需要有一定的位运算知识:
&, |, ^, ~, <<, >>,&=, |=, ^=, <<=, >>=所代表的含义以及执行的原理。(不懂的自行查书\百度\google)
本题需要的位运算的操作:(在最后的代码会呈现这些方法,所以有些方法没有附上代码只讲解了思路)
(1)将第一位变成1:
这个很简单,用位运算符就可以实现。
int i;
i = i | 1;
(2)将第一位变成0:
int i;
i = i & ~1;
(3)将某位变成0:
由(2)我们可以知道,要将某位变成0,需要&运算。如果我们能够创造出一个数字,其对应位的数字为0,其它位的数字为1,然后对二者进行&运算,就能将那一位变成0了。
(4)将某位变成1:
由(1)我们可以知道,要将某位变成1,需要|运算。如果我们能够创造出一个数字,使其对应为位1,其它位为0,然后对二者进行 | 运算,就能将那一位变成0了。
(5)统计二进制数中1的个数;
这个有两种方法:I.公式法;II. 逐位扫描法。
我们先来谈谈公式法。
int i, count = 0;
while (i) {
i &= i-1;
count++;
}
换句话来说就是”1的个数=(i&(i-1))的执行次数”。
第二种法方法就是逐位扫描法。
int num, count = 0;
for (int i = 0; i < 32; i++) {
if (num & (1<<i)) count++;
}
(6)检验某位是0还是1。
在(5)中的if的条件就是用来判断位是0还是1.因为num & (1<<i)
在对应位为1时返回非0值,在对应位为0时返回0.
但是,我个人觉得最有意思的部分就是实现左移和右移。
有两种方法:
(1)一劳永逸法(质变法):
就是直接将所有位进行左移右移n位。采取的思路是对数组逐个元素进行移位操作,然后将移位后出现的补位进行重新赋值(也就是下一个元素的头几位).
(2)量变法:
就是将所有位进行逐次左移右移1位。
下面是这两种左移右移代码的对比:
// 一劳永逸法
bitset& bitset :: operator <<= (int pos) {
for (int i = N-1; i >= 1; i--) {
a[i] <<= pos;
for (int j = 0; j < pos; j++) {
if (test(i*32+j-pos)) {
(*this).set(i*32+j);
} else {
(*this).reset(i*32+j);
}
}
}
a[0] <<= pos;
for (int i = 0; i < pos; i++) {
(*this).reset(i);
}
}
bitset& bitset :: operator >>= (int pos) {
for (int i = 0; i < N-1; i++) {
a[i] >>= pos;
for (int j = 0; j < pos; j++) {
if (test((i+1)*32+j)) {
(*this).set((i+1)*32+j-pos);
} else {
(*this).reset((i+1)*32+j-pos);
}
}
}
a[N-1] >>= pos;
for (int i = 0; i < pos; i++) {
(*this).set(32*N-1-i);
}
}
// 量变法
bitset& bitset::operator <<= (int pos) {
while (pos--) {
for (int i = N-1; i >= 0; i--) {
if (i == 0) {
a[i] <<= 1;
continue;
}
a[i] <<= 1;
if (a[i-1] & (1 << 31))
a[i] |= 1;
else
a[i] &= ~1;
}
}
return *this;
}
bitset& bitset::operator>>= (int pos) {
while (pos--) {
for (int i = 0; i < N; i++) {
if (i == N-1) {
a[i] >>= 1;
continue;
}
a[i] >>= 1;
if (a[i+1] & 1)
a[i] |= 1 << 31;
else
a[i] &= ~(1 << 31);
}
}
return *this;
}
下面呈现实现该类的完整代码:
/*int a[N];*/
# include "Bitset.h"
#define N 5
bitset :: bitset() {
for (int i = 0; i < N; i++) {
a[i] = 0;
}
}
void bitset :: set(int pos) {
int i = pos / 32;
int j = pos % 32;
a[i] = a[i] | (1 << j);
}
void bitset :: reset(int pos) {
int i = pos / 32;
int j = pos % 32;
int value = 0;
a[i] &= (~value^(1 << j));
}
int bitset :: count() const {
int num[N];
for (int i = 0; i < N; i++) {
num[i] = a[i];
}
int count = 0;
for (int i = 0; i < N; i++) {
while (num[i]) {
count++;
num[i] &= num[i]-1;
}
}
return count;
}
bool bitset :: test(int pos) const {
int i = pos / 32;
int j = pos % 32;
if (a[i] & (1 << j)) {
return true;
}
return false;
}
bool bitset :: any() const {
for (int i = 0; i < N; i++) {
for (int j = 0; j < 32; j++) {
if (a[i] & (1 << j)) {
return true;
}
}
}
return false;
}
bool bitset :: none() const {
for (int i = 0; i < N; i++) {
if (a[i] != 0) {
return false;
}
}
return true;
}
bool bitset :: all() const {
for (int i = 0; i < N; i++) {
if (~a[i] != 0) {
return false;
}
}
return true;
}
bitset& bitset :: operator&= (const bitset& b) {
for (int i = 0; i < N; i++) {
a[i] &= b.a[i];
}
return *this;
}
bitset& bitset :: operator|= (const bitset& b) {
for (int i = 0; i < N; i++) {
a[i] |= b.a[i];
}
return *this;
}
bitset& bitset :: operator^= (const bitset& b) {
for (int i = 0; i < N; i++) {
a[i] ^= b.a[i];
}
return *this;
}
bitset& bitset :: operator= (const bitset& b) {
for (int i = 0; i < N; i++) {
a[i] = b.a[i];
}
return *this;
}
bitset& bitset :: operator <<= (int pos) {
for (int i = N-1; i >= 1; i--) {
a[i] <<= pos;
for (int j = 0; j < pos; j++) {
if (test(i*32+j-pos)) {
(*this).set(i*32+j);
} else {
(*this).reset(i*32+j);
}
}
}
a[0] <<= pos;
for (int i = 0; i < pos; i++) {
(*this).reset(i);
}
}
bitset& bitset :: operator >>= (int pos) {
for (int i = 0; i < N-1; i++) {
a[i] >>= pos;
for (int j = 0; j < pos; j++) {
if (test((i+1)*32+j)) {
(*this).set((i+1)*32+j-pos);
} else {
(*this).reset((i+1)*32+j-pos);
}
}
}
a[N-1] >>= pos;
for (int i = 0; i < pos; i++) {
(*this).set(32*N-1-i);
}
}
bitset bitset :: operator~() const {
bitset copy;
for (int i = 0; i < N; i++) {
copy.a[i] = ~a[i];
}
return copy;
}
bitset bitset :: operator&(const bitset& b) const {
bitset copy;
for (int i = 0; i < N; i++) {
copy.a[i] = a[i] & b.a[i];
}
return copy;
}
bitset bitset :: operator|(const bitset& b) const {
bitset copy;
for (int i = 0; i < N; i++) {
copy.a[i] = a[i] | b.a[i];
}
return copy;
}
bitset bitset :: operator^(const bitset& b) const {
bitset copy;
for (int i = 0; i < N; i++) {
copy.a[i] = a[i] ^ b.a[i];
}
return copy;
}
bitset bitset :: operator<<(int pos) const {
bitset copy;
copy = *this;
for (int i = N-1; i >= 1; i--) {
copy.a[i] <<= pos;
for (int j = 0; j < pos; j++) {
if (copy.test(i*32+j-pos)) {
copy.set(i*32+j);
} else {
copy.reset(i*32+j);
}
}
}
copy.a[0] <<= pos;
for (int i = 0; i < pos; i++) {
copy.reset(i);
}
return copy;
}
bitset bitset :: operator>>(int pos) const {
bitset copy;
copy = *this;
for (int i = 0; i < N-1; i++) {
copy.a[i] >>= pos;
for (int j = 0; j < pos; j++) {
if (copy.test((i+1)*32+j)) {
copy.set((i+1)*32+j-pos);
} else {
copy.reset((i+1)*32+j-pos);
}
}
}
copy.a[N-1] >>= pos;
for (int i = 0; i < pos; i++) {
copy.set(32*N-1-i);
}
return copy;
}
bool bitset :: operator== (const bitset& b) const {
for (int i = 0; i < N; i++) {
if (a[i] != b.a[i]) {
return false;
}
}
return true;
}
bool bitset :: operator!= (const bitset& b) const {
int count = 0;
for (int i = 0; i < N; i++) {
if (a[i] == b.a[i]) {
count++;
}
}
if (count == N) {
return false;
}
return true;
}
bool bitset :: operator[] (int pos) const {
int i = pos / 32;
int j = pos % 32;
if (a[i] & (1 << j)) {
return true;
}
return false;
}
以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!