前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

13.5. ハッシュマップ

SFXLinkedHashMap クラスと SFXFlatHashMap クラスは、 複数のキーと値のペア要素を持つハッシュマップを操作するためのデータ構造です。

SFXLinkedHashMap クラスは、 ペア要素の追加順の双方向リンクリストを内部に保持しています。

SFXFlatHashMap クラスには、 ペア要素の双方向リンクリストがありません。

SFXLinkedHashMap クラスと SFXFlatHashMap クラスには、 双方向リンクリストの有無の違いにより、 下記の表のような特徴があります。

表 13.2. SFXLinkedHashMapSFXFlatHashMap

項目 解説
反復子や列挙子を利用した要素の巡回 双方向リンクリストを保持している SFXLinkedHashMap クラスの方が高速。
ハッシュマップ全体の比較 双方向リンクリストを利用して比較できるので、SFXLinkedHashMap クラスの方が高速。
要素の追加や削除、ハッシュマップのクリア 双方向リンクリストの管理が不要なので、SFXFlatHashMap クラスの方が高速。

以下は、(キー: SFXAnsiString 型, 値: SInt32 型) のペア要素を持つ SFXLinkedHashMap ハッシュマップを定義するコードです。

// (キー: SFXAnsiString 型, 値: SInt32 型)のペア要素を持つ SFXLinkedHashMap ハッシュマップの定義
SFXLinkedHashMap<SFXAnsiString, SInt32> hashmap;
// SFXFlatHashMap ハッシュマップの場合:
// SFXFlatHashMap<SFXAnsiString, SInt32> hashmap;

// 現在のハッシュマップの状態: hashmap = []
[Tip] Tip
SFXLinkedHashMap / SFXFlatHashMap ハッシュマップでは、 SFXAnsiString / SFXWideString 文字列をペア要素のキーに設定できます。

以下は、 SFXLinkedHashMap::Set / SFXFlatHashMap::Set 関数を使用してハッシュマップにペア要素(キーと値)を追加するコードです。

// 現在のハッシュマップの状態: hashmap = []

hashmap.Set("abc", 7);
// 現在のハッシュマップの状態: hashmap = [("abc", 7)]

hashmap.Set("def", 15);
// 現在のハッシュマップの状態: hashmap = [("abc", 7), ("def", 15)]

SFXAnsiString str1("ghi");
SFXAnsiString str2("jkl");
SFXAnsiString str3("mno");

hashmap.Set(str1, 31);
// 現在のハッシュマップの状態: hashmap = [("abc", 7), ("def", 15), ("ghi", 31)]

hashmap.Set(str2, 45);
// 現在のハッシュマップの状態: hashmap = [("abc", 7), ("def", 15), ("ghi", 31), ("jkl", 45)]

hashmap.Set(str3, 51);
// 現在のハッシュマップの状態: hashmap = [("abc", 7), ("def", 15), ("ghi", 31), ("jkl", 45), ("mno", 51)]

キーに対応するペア要素の値を取得するには、 SFXLinkedHashMap::Get / SFXFlatHashMap::Get 関数を呼び出します。

// 現在のハッシュマップの状態: hashmap = [("abc", 7), ("def", 15), ("ghi", 31), ("jkl", 45), ("mno", 51)]
SInt32 n = hashmap.Get("def"); // n = 15
[Caution] 注意
指定したキーのペア要素が存在しない場合、 SFXLinkedHashMap::Get / SFXFlatHashMap::Get 関数は値のタイプに応じて 0 または null を返します。

キー反復子/値反復子、キー列挙子/値列挙子を利用してハッシュマップのペア要素を巡回することができます。 SFXLinkedHashMap クラスは要素の双方向リンクリストを保持しているので、 要素の巡回は SFXFlatHashMap クラスよりも高速です。

例 13.7. キー反復子による巡回

// 現在のハッシュマップの状態: hashmap = [("abc", 7), ("def", 15), ("ghi", 31), ("jkl", 45), ("mno", 51)]

// キー反復子を取得する
SFXLinkedHashMap<SFXAnsiString, SInt32>::KeyIterator k_iterator = hashmap.GetFirstKeyIterator();
// SFXFlatHashMap ハッシュマップの場合: 
// SFXFlatHashMap<SFXAnsiString, SInt32>::KeyIterator k_iterator = hashmap.GetKeyIterator();

while(k_iterator.HasNext()) {

    SFXAnsiString key = k_iterator.GetNext(); // キーを取得する

    // ペア要素のキーと値を表示する
    TRACE("Key: %s, Value: %d", key.GetCString(), hashmap.Get(key));
}

上記コードを実行すると、デバッグウィンドウには以下の内容が表示されます。

// SFXLinkedHashMap を使用する場合
*dbgprintf*:0 - Key: abc, Value: 7
*dbgprintf*:0 - Key: def, Value: 15
*dbgprintf*:0 - Key: ghi, Value: 31
*dbgprintf*:0 - Key: jkl, Value: 45
*dbgprintf*:0 - Key: mno, Value: 51

// SFXFlatHashMap を使用する場合
*dbgprintf*:0 - Key: abc, Value: 7
*dbgprintf*:0 - Key: jkl, Value: 45
*dbgprintf*:0 - Key: def, Value: 15
*dbgprintf*:0 - Key: mno, Value: 51
*dbgprintf*:0 - Key: ghi, Value: 31
[Note] 注意

SFXLinkedHashMap の場合、 追加順にペア要素の内容が表示されます。 一方、SFXFlatHashMap の場合は、 追加順ではありません。

構造体など 4 バイトよりも大きな値を要素にしたい場合は、 以下のようにポインタを格納します。

// ハッシュマップのペア要素の値に格納するデータの型(実際にはこのポインタを値に格納する)
SFMTYPEDEFSTRUCT(Address)
struct Address {
    ACharPtr zip;
    ACharPtr prefecture;
    ACharPtr city;
    Address(ACharPtr zip, ACharPtr prefecture, ACharPtr city) 
        : zip(zip), prefecture(prefecture), city(city) {}
};

AddressPtr pAddr;

// ハッシュマップを構築する
SFXLinkedHashMap<SFXAnsiString, AddressPtr> hashmap;

pAddr = new Address("102-0072", "Tokyo", "Chiyoda-ku");
hashmap.Set("Yamada", pAddr);
pAddr = new Address("606-8203", "Kyoto", "Kyoto-shi");
hashmap.Set("Suzuki", pAddr);
pAddr = new Address("060-0000", "Hokkaido", "Sapporo-shi");
hashmap.Set("Satou", pAddr);

// ハッシュマップのペア要素数を表示する
TRACE("HashMap count = %d", hashmap.GetSize());

// ハッシュマップのキー反復子を取得する
SFXLinkedHashMap<SFXAnsiString, AddressPtr>::KeyIterator k_iterator = hashmap.GetFirstKeyIterator();

while(k_iterator.HasNext()) {

    SFXAnsiString name = k_iterator.GetNext(); // ペア要素のキーを取得する

    pAddr = (AddressPtr) hashmap.Get(name);

    // ハッシュマップのペア要素を表示する
    TRACE("Name = %s, Zip = %s, Prefecture = %s, City = %s", name.GetCString(), pAddr->zip, pAddr->prefecture, pAddr->city);
}

// ハッシュマップの値反復子を取得する
SFXLinkedHashMap<SFXAnsiString, AddressPtr>::ValueIterator v_iterator = hashmap.GetFirstValueIterator();

while(v_iterator.HasNext()) {

    pAddr = v_iterator.GetNext(); // ペア要素の値を取得する

    delete pAddr;  // ペア要素の値であるポインタが指すメモリ領域を解放する
}

// ハッシュマップをクリアする(キーである SFXAnsiString 文字列は自動的に解放される)
hashmap.Clear();
[Note] 注意

4 バイトよりも大きなデータは、そのポインタをペア要素の値に格納します。 ハッシュマップをクリアするとき、ポインタが指すメモリ領域は自動的に解放されません。 上記コードにあるようにクリアする直前に、 delete 文を使用して明示的にポインタが指すメモリ領域を解放する必要があります。 さもなければ、メモリリークが発生します。

ペア要素のキーに格納した SFXAnsiString 文字列は、 ペア要素を削除したときに自動的に解放されます。

上記コードを実行すると、デバッグウィンドウには以下の内容が表示されます。

*dbgprintf*:0 - HashMap count = 3
*dbgprintf*:0 - Name = Yamada, Zip = 102-0072, Prefecture = Tokyo, City = Chiyoda-ku
*dbgprintf*:0 - Name = Suzuki, Zip = 606-8203, Prefecture = Kyoto, City = Kyoto-shi
*dbgprintf*:0 - Name = Satou, Zip = 060-0000, Prefecture = Hokkaido, City = Sapporo-shi