「マップ」とは「キー(key)と値(value)の対応表」であり、 キーと値の「登録(Insert)」、 キーを指定した「検索(Find)」、「削除(Erase)」ができる抽象データ型である。
具体例としては、 電話帳「名前(キー)と電話番号(値)の対応」、 学籍名簿「学籍番号(キー)と名前(値)の対応」 などを考えれば良い。
#include <iostream>
#include <string>
using namespace std;
// 最初からテンプレートにするとデバッグが大変なので、
// まずは、「キー」も「値」も string 型のマップを作成する。
// テンプレート化は後で行う。
/* 線形リストによるマップ MapLinear クラス */
class MapLinear
{
class Cell {
string key;
string value;
Cell* next;
public:
Cell( string k, string d, Cell* n) : key(k), value(d), next(n) { };
friend class MapLinear;
};
Cell* head;
public:
MapLinear( );
~MapLinear( );
bool Insert( string key, string value );
// key と value を対で登録する。
// key が同じデータを2重に登録することはできないものとする。
// 登録に失敗した場合は false 成功した場合は true を返す。
bool Find( string key, string & value ) const;
// key に対応するデータを見つける。
// 無ければ false を返す。
// 有れば true を返し、対応する「値」を参照引数 value で返す。
private:
void makeEmpty( Cell* p );
bool find( string key, string & value, Cell* p ) const;
};
MapLinear::MapLinear( )
{
head=NULL;
}
MapLinear::~MapLinear( )
{
makeEmpty( head );
}
void MapLinear::makeEmpty( Cell* p )
{
if ( p != NULL ) {
if ( p->next != NULL )
makeEmpty( p->next );
delete p;
}
}
bool MapLinear::Insert( string key, string value )
{
string dummy;
if ( ! Find( key, dummy ) ) {
// ここを埋めよ。
// 同じキーのデータが無ければ追加する。
// 場所はどこでも良いが、先頭が楽だろう。
return true;
}
else
return false;
// 同じキーを持つデータが存在した場合は、false を返す。
}
bool MapLinear::Find( string key, string & value ) const
{
return find( key, value, head );
// リストの先頭を指定して、プライベート関数 find を呼んでいる。
}
bool MapLinear::find( string key, string & value, Cell* p ) const
{
if ( p == NULL ) {
return false;
}
else if ( p->key == key ) {
// ここを埋めよ。
//
}
else {
// ここを埋めよ。再帰呼び出しを使うこと。
}
}
/* 利用例 */
int main()
{
MapLinear staff; // 教員のアドレス帳
staff.Insert( "mino", "mino_at_csci.yanamashi.ac.jp" );
staff.Insert( "yoshikawa", "yoshi_at_yanamashi.ac.jp" );
staff.Insert( "watanabe", "nabe_at_s.cs.yanamashi.ac.jp" );
staff.Insert( "kobayashi", "masaki_at_esi.yanamashi.ac.jp" );
staff.Insert( "suzuki", "stomo_at_yanamashi.ac.jp" );
string address;
if ( staff.Find( "mino", address ) ) {
cout << address;
}
return 0;
}
|
class MapLinear
{
class Cell {
public:
string key;
string value;
Cell* next;
Cell( string k, string d, Cell* n) : key(k), value(d), next(n) { };
};
Cell* head;
public:
MapLinear( );
~MapLinear( );
bool Insert( string key, string value );
bool Find( string key, string & value ) const;
bool Erase( string key );
// key の値に対応するデータを削除する
// 該当するデータが無い場合は false を返す
private:
void makeEmpty( Cell* p );
bool find( string key, string & value, Cell* p ) const;
bool erase( string key, Cell* & p );
// p が参照引数であることが重要!
};
...
bool MapLinear::Erase( string key )
{
return erase( key, head );
}
bool MapLinear::erase( string key, Cell* & p )
// p が参照引数であることが重要!
{
if ( p == NULL ) {
return false;
}
else if ( p->key == key ) {
// ここを埋めよ。
// ..
// ..
// ..
}
else {
// ここを埋めよ。再帰呼び出しを使うこと。
}
}
|
以下は線形リストを用いたマップについての上記関数の実装例である。これらを MapLinear に追加し、登録された全データを出力するテストを行いなさい。
class MapLinear {
...
//private member を一つ追加
Cell* current;
...
};
MapLinear:: MapLinear( ) {
...
current = NULL;
...
}
void MapLinear:: SetBegin( )
{
current = head;
}
void MapLinear:: Next( )
{
if ( current != NULL )
current = current->next;
}
bool MapLinear:: IsValid( ) const
{
return ( current != NULL );
}
bool MapLinear:: CurrentItem( string & k , string & v ) const
{
if ( current == NULL ) {
return false;
}
else {
k = current->key;
v = current->value;
return true;
}
}
|
template < typename KeyType, typename ValueType >
class MapLinear {
KeyType key;
ValueType value;
...
}
template < typename KeyType, typename ValueType >
MapLinear<KeyType,ValueTpe>::MapLinear( )
{
...
}
...
int main( )
{
MapLinear<string,string> pr;
....
}
|