アフィリエイト広告を利用しています

広告

posted by fanblog

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

d02_0013.png


新版 明解C 入門編 (明解シリーズ)

新品価格
¥2,916から
(2017/11/10 13:13時点)

新版 明解C 中級編 (明解シリーズ)

新品価格
¥2,916から
(2017/11/10 13:14時点)





この記事へのコメント
コメントを書く

お名前:

メールアドレス:


ホームページアドレス:

コメント:

※ブログオーナーが承認したコメントのみ表示されます。

この記事へのトラックバックURL
https://fanblogs.jp/tb/6975169
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


検索
<< 2018年08月 >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
プロフィール
こうすけさんの画像
こうすけ

 たまに、クリック お願いします m(_ _)m

 AA にほんブログ村 IT技術ブログ C/C++へ

こうすけ:メール kousuke_cpp@outlook.jp

【1】★★C++ 記事目次★★ ← 利用可能です。
・新版明解C++入門編 / 新版明解C++中級編
・その他 C++ 関連記事

【2】★★こうすけ@C#★★
・C# の初歩的な記事


×

この広告は30日以上新しい記事の更新がないブログに表示されております。