2017年11月16日
《その131》 ビットベクトルによる集合
ビットベクトルによる集合
自分の使っている処理系では unsigned long型は 32ビットです。
0110・・・0000000100010
↑↑ ↑↑↑↑
|| |||要素 0 を表すビット
|| |||
|| ||要素 1 を表すビット
|| ||
|| |要素 2 を表すビット
|| |
|| 要素 3 を表すビット
||
|要素 30 を表すビット
|
要素 31 を表すビット
上の場合、この unsigned long型整数は
集合 { 1, 5, 29, 30 }
を意味します。
新版明解C++中級編 p.70 〜 p.79 にビットベクトルによる集合を実現する集合クラスのコードが載っていますが、
一部に誤植等があって正常に動作しないと思います。
以下は、正常に動作するように少し修正したプログラムです。
// BitSet.h
#ifndef ___Class_BitSet
#define ___Class_BitSet
#include <limits>
#include <string>
#include <iostream>
class BitSet {
static const int LONG_BIT
= std::numeric_limits<unsigned long>::digits;
// 集合本体
unsigned long bits;
// v は要素として妥当か
static bool is_valid(int v) {
return v >= 0 && v < LONG_BIT;
}
// 要素が e 一つだけの集合
static unsigned long set_of(int e) {
return 1UL << e;
}
public:
// 要素の値として許される最大値
static int max_element() { return LONG_BIT - 1; }
// 要素の値として許される最小値
static int min_element() { return 0; }
// デフォルトコンストラクタ
BitSet() : bits(0UL) { }
// コンストラクタ(受け取った配列を元に集合本体を生成)
BitSet(const int e[], int n) : bits(0UL) {
for (int i = 0; i < n; i++)
add(e[i]);
}
// 値 e は集合の要素か
bool contains(int e) const {
return is_valid(e) && (bits & set_of(e));
}
// 値 e を要素として追加
void add(int e) {
if (is_valid(e))
bits |= set_of(e);
}
// 値 e を要素から削除
void remove(int e) {
if (is_valid(e))
bits &= ~set_of(e);
}
// 空集合か
bool empty() const {
return !bits;
}
// 集合の要素数
int size() const {
int count = 0;
unsigned long x = bits;
while (x) { x &= x - 1; count++; }
return count;
}
// 集合 r との積集合に更新
BitSet& operator&=(const BitSet& r) {
bits &= r.bits;
return *this;
}
// 集合 r との和集合に更新
BitSet& operator|=(const BitSet& r) {
bits |= r.bits;
return *this;
}
// 新版明解C++中級編では
// BitSet& operator^=(const BitSet& r)が
// 「集合 r との差集合に更新」となっていますが誤植です。
// (私の本が古いのかも・・・中古本を買ったので) (´・ω・`A
// テキスト p.77 の 「 bits ^= r.bits; で rとの差集合が得られる 」
// となっている部分は誤植です。
// 正しくは、例えば「 bits &= ~r.bits 」です。
BitSet& operator^=(const BitSet& r) {
bits ^= r.bits;
return *this;
}
// テキストにはありませんが、
// 集合 r との差集合に更新する演算子関数として
// operator-=を定義しました。
BitSet& operator-=(const BitSet& r) {
bits &= ~r.bits;
return *this;
}
// 集合 r と等しいか
bool operator==(const BitSet& r) const {
return bits == r.bits;
}
// 集合 r と等しくないか
bool operator!=(const BitSet& r) const {
return bits != r.bits;
}
// "{ a, b, c }"タイプの文字列を作る。
std::string to_string() const;
// "11000・・・10100"タイプの文字列を作る。
std::string bit_string() const;
};
// 挿入子 << の多重定義
std::ostream& operator<<(std::ostream& os, const BitSet& x);
#endif
// BitSet.cpp
#include <sstream>
#include <iostream>
#include "BitSet.h"
using namespace std;
string BitSet::to_string() const {
ostringstream s;
int set[LONG_BIT];
int count = 0;
for (int i = 0; i < LONG_BIT; i++)
if (bits & set_of(i)) set[count++] = i;
s << "{";
if (count) {
for (int i = 0; i < count - 1; i++)
s << set[i] << ", ";
s << set[count - 1];
}
s << "}";
return s.str();
}
string BitSet::bit_string() const {
char bp[LONG_BIT + 1];
for (int i = LONG_BIT - 1; i >= 0; i--)
bp[LONG_BIT - i - 1] = (set_of(i) & bits) ? '1' : '0';
bp[LONG_BIT] = '\0';
return string(bp);
}
ostream& operator<<(ostream& os, const BitSet& x) {
return os << x.to_string();
}
// BitSetTest.cpp
#include <iostream>
#include "BitSet.h"
using namespace std;
int main()
{
BitSet b1;
int a[] = { 0, 4, 5, 15, 31 };
BitSet b2(a, sizeof(a) / sizeof(a[0]));
BitSet b3 = b2;
cout << "b1 = " << b1 << '\n';
cout << " " << b1.bit_string() << '\n';
cout << "b2 = " << b2 << '\n';
cout << " " << b2.bit_string() << '\n';
cout << "b3 = " << b3 << '\n';
cout << " " << b3.bit_string() << "\n\n";
b3.add(2); b3.add(6); b3.add(8);
b3.remove(31);
cout << "b3.add(2); b3.add(6); b3.add(8); b3.remove(31);"
<< '\n';
cout << "b3 = " << b3 << '\n';
cout << " " << b3.bit_string() << "\n\n";
cout << "この時点で…" << '\n';
cout << "b2 = " << b2 << '\n';
cout << " " << b2.bit_string() << '\n';
cout << "b3 = " << b3 << '\n';
cout << " " << b3.bit_string() << "\n\n";
BitSet temp_b2 = b2;
b2 ^= b3;
cout << "◆テキストの b2 ^= b3 では…" << '\n';
cout << "b2 = " << b2 << '\n';
cout << " " << b2.bit_string() << '\n';
cout << " …差集合は得られない。"
<< '\n';
b2 = temp_b2;
b2 -= b3;
cout << "◆差集合 (b2 - b3)" << '\n';
cout << " b2 -= b3; 多重定義した oparator-= を使用。"
<< '\n';
cout << "b2 = " << b2 << '\n';
cout << " " << b2.bit_string() << "\n\n";
}
この記事へのコメント
コメントを書く
この記事へのトラックバックURL
https://fanblogs.jp/tb/6975169
※ブログオーナーが承認したトラックバックのみ表示されます。
この記事へのトラックバック