[C++] multimapの基本的な使い方

C++のmultimapは、キーと値のペアを格納するコンテナで、同じキーに対して複数の値を持つことができます。

これは、キーが重複する可能性があるデータを扱う際に便利です。

multimapは、キーの順序を保ちながら要素を格納するため、内部的にはバランスの取れた二分探索木を使用しています。

要素の挿入にはinsertメソッドを使用し、特定のキーに関連するすべての要素を取得するにはequal_rangeメソッドを利用します。

また、findメソッドを使って特定のキーを持つ要素を検索することも可能です。

この記事でわかること
  • multimapの基本的な特性と用途
  • 要素の挿入や削除、検索の方法
  • イテレーションを用いたデータの操作
  • multimapを活用した具体的な応用例

目次から探す

multimapとは

C++のSTL(Standard Template Library)には、データを効率的に管理するためのさまざまなコンテナが用意されています。

その中で、multimapはキーと値のペアを格納する連想コンテナの一つです。

multimapは、同じキーに対して複数の値を持つことができるという特徴があります。

multimapの基本

multimapは、キーと値のペアを格納するためのコンテナで、キーの重複を許容します。

これは、同じキーに対して複数の関連する値を持つ必要がある場合に非常に便利です。

multimapは内部的にバランスの取れた二分探索木を使用しており、要素の挿入、削除、検索が効率的に行えます。

#include <iostream>
#include <map>
int main() {
    // multimapの宣言
    std::multimap<int, std::string> multiMap;
    // 要素の挿入
    multiMap.insert(std::make_pair(1, "りんご"));
    multiMap.insert(std::make_pair(2, "バナナ"));
    multiMap.insert(std::make_pair(1, "オレンジ"));
    // 要素の表示
    for (const auto& pair : multiMap) {
        std::cout << "キー: " << pair.first << ", 値: " << pair.second << std::endl;
    }
    return 0;
}
キー: 1, 値: りんご
キー: 1, 値: オレンジ
キー: 2, 値: バナナ

この例では、multimapに同じキー1で異なる値を挿入しています。

multimapはキーの順序を保ちながら、重複したキーを許容していることがわかります。

multimapとmapの違い

スクロールできます
特徴mapmultimap
キーの重複許可しない許可する
要素の順序キーの順序でソートキーの順序でソート
使用例一意のキーに対する値の管理同じキーに対する複数の値の管理

mapはキーの重複を許可しないため、同じキーで異なる値を持つことができません。

一方、multimapは同じキーに対して複数の値を持つことができるため、特定のキーに関連する複数のデータを管理するのに適しています。

multimapの用途

multimapは、以下のような用途で利用されます。

  • データのグループ化: 同じカテゴリや属性を持つデータをグループ化して管理する場合に便利です。
  • 複数の関連データの管理: 例えば、同じ商品IDに対して異なる価格や在庫情報を持つ場合などに使用されます。
  • イベントのスケジューリング: 同じ時間に複数のイベントが発生する場合に、時間をキーとしてイベントを管理することができます。

これらの用途により、multimapは特定の条件下で非常に有用なコンテナとなります。

multimapの基本操作

multimapを効果的に利用するためには、基本的な操作方法を理解することが重要です。

ここでは、multimapの宣言から要素の挿入、削除までの基本操作について説明します。

multimapの宣言と初期化

multimapを使用するには、まずその宣言と初期化を行います。

multimapはテンプレートクラスであり、キーと値の型を指定して宣言します。

#include <iostream>
#include <map>
int main() {
    // int型のキーとstring型の値を持つmultimapの宣言
    std::multimap<int, std::string> multiMap;
    // 初期化リストを使った初期化
    std::multimap<int, std::string> initializedMultiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    return 0;
}

この例では、multimapを宣言し、初期化リストを使用して初期化しています。

要素の挿入方法

multimapに要素を挿入する方法として、insert関数emplace関数があります。

insert関数の使い方

insert関数は、キーと値のペアをmultimapに挿入します。

std::make_pairを使用してペアを作成することが一般的です。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap;
    // insert関数を使って要素を挿入
    multiMap.insert(std::make_pair(1, "りんご"));
    multiMap.insert(std::make_pair(2, "バナナ"));
    multiMap.insert(std::make_pair(1, "オレンジ"));
    return 0;
}

emplace関数の使い方

emplace関数は、insert関数と似ていますが、オブジェクトを直接構築するため、効率的です。

コンストラクタの引数をそのまま渡すことができます。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap;
    // emplace関数を使って要素を挿入
    multiMap.emplace(1, "りんご");
    multiMap.emplace(2, "バナナ");
    multiMap.emplace(1, "オレンジ");
    return 0;
}

要素の削除方法

multimapから要素を削除するには、erase関数clear関数を使用します。

erase関数の使い方

erase関数は、指定したキーに関連するすべての要素を削除します。

また、イテレータを指定して特定の要素を削除することも可能です。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // キー1に関連するすべての要素を削除
    multiMap.erase(1);
    // イテレータを使って特定の要素を削除
    auto it = multiMap.find(2);
    if (it != multiMap.end()) {
        multiMap.erase(it);
    }
    return 0;
}

clear関数の使い方

clear関数は、multimap内のすべての要素を削除します。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // すべての要素を削除
    multiMap.clear();
    return 0;
}

これらの基本操作を理解することで、multimapを効果的に利用することができます。

multimapの検索機能

multimapは、キーに基づいて要素を検索するための便利な機能を提供しています。

ここでは、multimapの検索機能について詳しく説明します。

要素の検索方法

multimapでは、特定のキーに関連する要素を検索するために、find関数count関数を使用します。

find関数の使い方

find関数は、指定したキーに関連する最初の要素を検索し、そのイテレータを返します。

キーが見つからない場合は、end()イテレータを返します。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // キー1に関連する最初の要素を検索
    auto it = multiMap.find(1);
    if (it != multiMap.end()) {
        std::cout << "見つかった要素: キー: " << it->first << ", 値: " << it->second << std::endl;
    } else {
        std::cout << "キーが見つかりませんでした。" << std::endl;
    }
    return 0;
}

count関数の使い方

count関数は、指定したキーに関連する要素の数を返します。

multimapでは、同じキーに対して複数の要素が存在する可能性があるため、count関数は便利です。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // キー1に関連する要素の数を取得
    int count = multiMap.count(1);
    std::cout << "キー1に関連する要素の数: " << count << std::endl;
    return 0;
}

範囲検索

multimapでは、特定のキーに関連するすべての要素を取得するために、equal_range関数lower_boundupper_bound関数を使用します。

equal_range関数の使い方

equal_range関数は、指定したキーに関連する要素の範囲を表すペアのイテレータを返します。

この関数は、キーに関連するすべての要素を効率的に取得するのに役立ちます。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // キー1に関連する要素の範囲を取得
    auto range = multiMap.equal_range(1);
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << "キー: " << it->first << ", 値: " << it->second << std::endl;
    }
    return 0;
}

lower_boundとupper_boundの使い方

lower_bound関数は、指定したキー以上の最初の要素を指すイテレータを返し、upper_bound関数は、指定したキーより大きい最初の要素を指すイテレータを返します。

これらを組み合わせることで、特定のキーに関連する要素の範囲を取得できます。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // lower_boundとupper_boundを使ってキー1に関連する要素の範囲を取得
    auto lower = multiMap.lower_bound(1);
    auto upper = multiMap.upper_bound(1);
    for (auto it = lower; it != upper; ++it) {
        std::cout << "キー: " << it->first << ", 値: " << it->second << std::endl;
    }
    return 0;
}

これらの検索機能を活用することで、multimap内のデータを効率的に操作することができます。

multimapのイテレーション

multimapのイテレーションは、コンテナ内の要素を順番に処理するための重要な手法です。

ここでは、イテレータの基本から、ループ処理、constイテレータの使い方について説明します。

イテレータの基本

イテレータは、multimap内の要素を指し示すオブジェクトで、ポインタのように振る舞います。

イテレータを使用することで、multimap内の要素を順番にアクセスすることができます。

multimapのイテレータは、双方向イテレータとして実装されており、前後に移動することが可能です。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // イテレータの宣言
    std::multimap<int, std::string>::iterator it;
    // イテレータを使って要素にアクセス
    it = multiMap.begin();
    std::cout << "最初の要素: キー: " << it->first << ", 値: " << it->second << std::endl;
    return 0;
}

イテレータを使ったループ処理

イテレータを使ったループ処理は、multimap内のすべての要素を順番に処理するために使用されます。

begin()関数で最初の要素を指すイテレータを取得し、end()関数で最後の要素の次を指すイテレータを取得します。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // イテレータを使ったループ処理
    for (auto it = multiMap.begin(); it != multiMap.end(); ++it) {
        std::cout << "キー: " << it->first << ", 値: " << it->second << std::endl;
    }
    return 0;
}

このループでは、multimap内のすべての要素を順番に出力しています。

constイテレータの使い方

constイテレータは、要素を変更せずに読み取るために使用されます。

const_iteratorを使用することで、multimapの要素を安全に参照することができます。

#include <iostream>
#include <map>
int main() {
    std::multimap<int, std::string> multiMap = {
        {1, "りんご"},
        {2, "バナナ"},
        {1, "オレンジ"}
    };
    // constイテレータを使ったループ処理
    for (std::multimap<int, std::string>::const_iterator it = multiMap.cbegin(); it != multiMap.cend(); ++it) {
        std::cout << "キー: " << it->first << ", 値: " << it->second << std::endl;
    }
    return 0;
}

const_iteratorを使用することで、multimapの要素を変更することなく、読み取り専用でアクセスすることができます。

これにより、意図しない変更を防ぐことができます。

multimapの応用例

multimapは、キーの重複を許容する特性を活かして、さまざまな応用が可能です。

ここでは、multimapを使った具体的な応用例を紹介します。

複数の値を持つデータの管理

multimapは、同じキーに対して複数の値を持つデータを管理するのに適しています。

例えば、同じ商品IDに対して異なる価格や在庫情報を持つ場合に利用できます。

#include <iostream>
#include <map>
int main() {
    // 商品IDと価格のペアを管理するmultimap
    std::multimap<int, double> productPrices = {
        {101, 29.99},
        {102, 49.99},
        {101, 34.99} // 同じ商品IDに異なる価格
    };
    // 商品ID101に関連する価格を表示
    auto range = productPrices.equal_range(101);
    std::cout << "商品ID101の価格: ";
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << it->second << " ";
    }
    std::cout << std::endl;
    return 0;
}

この例では、商品ID101に対して複数の価格を管理しています。

順序付きデータの重複管理

multimapは、順序付きデータの中で重複を管理するのに便利です。

例えば、同じ日付に複数のイベントがある場合に、日付をキーとしてイベントを管理できます。

#include <iostream>
#include <map>
int main() {
    // 日付とイベント名のペアを管理するmultimap
    std::multimap<std::string, std::string> events = {
        {"2023-10-01", "会議"},
        {"2023-10-01", "ランチ"},
        {"2023-10-02", "プレゼンテーション"}
    };
    // 2023-10-01に関連するイベントを表示
    auto range = events.equal_range("2023-10-01");
    std::cout << "2023-10-01のイベント: ";
    for (auto it = range.first; it != range.second; ++it) {
        std::cout << it->second << " ";
    }
    std::cout << std::endl;
    return 0;
}

この例では、日付2023-10-01に関連する複数のイベントを管理しています。

データのグループ化と集計

multimapは、データをグループ化して集計するのにも役立ちます。

例えば、同じカテゴリに属する商品をグループ化し、カテゴリごとの商品数を集計することができます。

#include <iostream>
#include <map>
int main() {
    // カテゴリと商品名のペアを管理するmultimap
    std::multimap<std::string, std::string> categoryProducts = {
        {"果物", "りんご"},
        {"果物", "バナナ"},
        {"野菜", "にんじん"},
        {"果物", "オレンジ"}
    };
    // カテゴリごとの商品数を集計
    std::map<std::string, int> categoryCount;
    for (const auto& pair : categoryProducts) {
        categoryCount[pair.first]++;
    }
    // 集計結果を表示
    for (const auto& pair : categoryCount) {
        std::cout << "カテゴリ: " << pair.first << ", 商品数: " << pair.second << std::endl;
    }
    return 0;
}

この例では、multimapを使ってカテゴリごとの商品をグループ化し、商品数を集計しています。

multimapの特性を活かすことで、データの管理や集計が効率的に行えます。

よくある質問

multimapはどのような場合に使うべきですか?

multimapは、同じキーに対して複数の値を持つ必要がある場合に使用するのが適しています。

例えば、同じ日付に複数のイベントがある場合や、同じ商品IDに対して異なる価格や在庫情報を持つ場合などです。

キーの重複を許容することで、関連するデータをグループ化して管理することができます。

multimapのパフォーマンスはmapと比べてどうですか?

multimapmapは、どちらも内部的にバランスの取れた二分探索木を使用しているため、基本的な操作(挿入、削除、検索)の時間計算量は同じです。

ただし、multimapはキーの重複を許容するため、特定のキーに関連するすべての要素を操作する場合には、mapよりも多くの要素を処理する必要があります。

そのため、キーの重複が多い場合は、multimapの方が若干パフォーマンスに影響が出ることがあります。

multimapでキーの重複を避ける方法はありますか?

multimapは設計上、キーの重複を許容するコンテナです。

そのため、キーの重複を避けるためには、multimapではなくmapを使用することを検討するべきです。

mapはキーの重複を許可しないため、一意のキーに対してのみ値を持つことができます。

もしmultimapを使用しつつ重複を避けたい場合は、要素を挿入する前にfind関数を使ってキーの存在を確認し、既に存在する場合は挿入をスキップするなどの工夫が必要です。

例:if (multiMap.find(key) == multiMap.end()) { multiMap.insert(std::make_pair(key, value)); }

まとめ

この記事では、C++のmultimapについて、その基本的な使い方から応用例までを詳しく解説しました。

multimapは、同じキーに対して複数の値を持つことができる特性を活かし、データの管理やグループ化において非常に有用なコンテナです。

これを機に、multimapを活用して、より効率的なデータ管理を実現してみてはいかがでしょうか。

当サイトはリンクフリーです。出典元を明記していただければ、ご自由に引用していただいて構いません。

関連カテゴリーから探す

  • URLをコピーしました!
目次から探す