アリスは同じ鞄を抱えない

更にアリプラシリーズ。

同じ鞄をプレゼントした場合は、アリスは貰わない…と言いますから、同じ鞄なんだからなんでもう一度プレゼントするの?というコードです。

// for アリスは同じ鞄を抱えない
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;

class Bag {
protected:
	bool used;
public:
	virtual bool getUsed() { return used; }  
	virtual void Used() { this->used = true; }  
};

class Prada : public Bag {};
class Tiffany : public Bag {};

class Alice
{
private:
	list<Bag*> bags;
public:
	Alice() {
	}
	void Present( Bag *bag ) 
	{
		if ( find(bags.begin(),bags.end(),bag) == bags.end() &&
             dynamic_cast<Prada*>(bag) != NULL ) {
			bags.push_back( bag );
		}
	}
	int CountBags() 
	{
		return bags.size();
	}
};

int main(void)
{
	Alice alice;
	
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	Bag *bag = new Prada();
	alice.Present(bag);
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Tiffany());
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(bag); // 同じものをプレゼントする
	cout << "alice has " << alice.CountBags() << " bags." << endl;
	alice.Present(new Prada());
	cout << "alice has " << alice.CountBags() << " bags." << endl;

	return 0;
}

実行するとこんな感じ。

D:\work\blog\src\alice>a
alice has 0 bags.
alice has 1 bags.
alice has 1 bags.
alice has 1 bags.
alice has 2 bags.

プレゼントすると、一度、タンス(bags)を find 関数で照合します。何故か知らないけど、タンス(bags)にあったものが再び Present される訳で、変なのという感じなのですが、bags には追加しません。
データベースで言うところの、同じ名前だったらデータベースに insert しない処理ってのと同じですね。

SELECT @COUNT = count(*) FROM bags WHERE ...
IF @COUNT = 0 THEN
  INSERT bags VALUES ( ... )
END IF

のようなものです。重複チェックをして挿入ってな具合。これは、bags にある量が多くなるとだんだんと遅くなっていきます。いわゆる O(n) の確率。ただし、find のアルゴリズムを変えていけば O(log n) だっけ? になります。ハッシュテーブルとかバイナリツリーとかを使います。大変ですよね。不安ですね。

しかし、ちょっと工夫すると、一発で貰った鞄かどうかが分かります。Bag クラス自体にマーキングを示す mark 変数を用意して、これに自分のポインターを入れておきます。そうすると、mark を調べるだけで一発で分かりますよね。

class Bag {
protected:
	void *_mark;
public:
	Bag() : _mark(NULL) {}
	virtual void setMark( void *mark ) {
		_mark = mark;
	}
	virtual void *getMark() {
		return _mark;
	}
};

特性を知って、ちょっとクラスに工夫を加えるとうまくいくっていうパターンです。

カテゴリー: C++ パーマリンク