C++のbitsetに関するメモ


このエントリーをはてなブックマークに追加

競技プログラミングで使いたいと思いつつずっと未履修だったbitsetの使い方を勉強しました。

基本操作

以下ではすべて以下が書かれているものとします。

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

初期化は、文字列を与えるか、整数を与えるかで行えます。

int main(void)
{
    bitset<8> bs1("10001111");
    cout << bs1 << endl;  // 10001111

    bitset<8> bs2(127);
    cout << bs2 << endl;  // 01111111

    return 0;
}

n桁目を1にするにはset, n桁目を0にするにはresetを使うのがシンプルです。

int main(void)
{
    bitset<8> bs("10001111");
    cout << bs << endl;  // 10001111

    bs.set(4); // 4番目の桁を1に変更
    cout << bs << endl;  // 10011111

    bs.reset(2); // 2番目の桁を0に変更
    cout << bs << endl;  // 10011011

    return 0;
}

n番目の桁を1にするか0にするかを変数で制御したい場合は、引数が2個バージョンのset()を使います。

int main(void)
{
    bitset<8> bs("10001111");
    cout << bs << endl;  // 10001111

    bs.set(4, 1); // 4番目の桁を1に変更
    cout << bs << endl;  // 10011111

    bs.set(2, 0); // 2番目の桁を0に変更
    cout << bs << endl;  // 10011011

    return 0;
}

引数なしでset(), reset()を呼ぶと、ビットが1または0で埋められます。

int main(void)
{
    bitset<8> bs("10001111");
    cout << bs << endl;;  // 10001111

    bs.set();
    cout << bs << endl;  // 11111111

    bs.reset();
    cout << bs << endl;  // 00000000

    return 0;
}

n番目の桁が0か1かを確かめるには、添字かtest()を使います。

int main(void)
{
    bitset<8> bs("10001111");
    cout << bs << endl;

    // 1,1,1,1,0,0,0,1, と表示される
    for(size_t i = 0; i < bs.size(); ++i) {
        cout << bs[i] << ",";
    }
    cout << endl;

    // 同上
    for(size_t i = 0; i < bs.size(); ++i) { 
        cout << bs.test(i) << ",";
    }

    return 0;
}

当然、ビット演算も可能です。

int main(void)
{
    bitset<8> bs1("10001111");
    bitset<8> bs2("01010101");

    cout << (bs1 & bs2) << endl;  // 00000101
    cout << (bs1 | bs2) << endl;  // 11011111
    cout << (bs1 ^ bs2) << endl;  // 11011010

    return 0;
}

count()で1が立ったビットの数を数えられるのはかなり便利です。

int main(void)
{
    bitset<8> bs(127);
    cout << bs.count() << endl;  // 7
    return 0;
}

その他、使う可能性が高そうな便利機能です。

int main(void)
{
    bitset<8> bs("10001111");
    cout << bs << endl;  // 10001111

    // 0と1を反転
    bs.flip();
    cout << bs << endl;  // 01110000

    // 左に2個シフト
    bs <<= 2;
    cout << bs << endl;  // 11000000

    // 右に2個シフト
    bs >>= 2;
    cout << bs << endl;  // 00110000

    // 整数に変換
    unsigned long n = bs.to_ulong();
    cout << n << endl;  // 48

    // 文字列に変換
    string str = bs.to_string();
    cout << str << endl;  // 00110000

    // 文字列に変換する際、0, 1それぞれを任意の記号にすることも可能
    string str2 = bs.to_string('a', 'z');
    cout << str2 << endl;  // aazzaaaa

    return 0;
}

応用例

ビット全探索

2の5乗をビット探索するときは以下のように書きます。

int main(void)
{
    for(int i = 0; i < (1 << 5); ++i) {
        bitset<5> s(i);
        cout << s << endl;
    }
    return 0;
}

出力は以下です。

00000
00001
00010
00011
...
11110
11111

参考URL