C++: 模拟实现类bitset

C++: 模拟实现类bitset

标签: C++ bitset 位运算

by 小威威

1.bitset简介

bitset能实现对数字的位的操作,同时也能通过类似于数组的下标来访问各个位的数值,以执行相应的操作。模拟bitset就是用一个普通的数组来存储数据以达到模拟的目的。

先声明一下,本篇文章并不是讲述标准库中bitset这个类的用法,而是去讲述如何实现一个模拟bitset的类。

众所周知,int类型在64位系统中占4个字节,也就是32位,倘若我建立一个大小为5的数组,那么我就能存储5*32=160个位。然后我可以通过对数组的每个元素单独处理,通过位运算,来实现对位的操作。

2.类的实现

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

要完成该模拟,需要有一定的位运算知识:

  1. &, |, ^, ~, <<, >>,&=, |=, ^=, <<=, >>=所代表的含义以及执行的原理。(不懂的自行查书\百度\google)

  2. 本题需要的位运算的操作:(在最后的代码会呈现这些方法,所以有些方法没有附上代码只讲解了思路)

(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;
}

以上内容皆为本人观点,欢迎大家提出批评和指导,我们一起探讨!

你可能感兴趣的:(位运算,C++,bitset,模拟)