C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でマップ(HashMap)を反復処理中にキーを指定してエントリを削除する方法

C++では、連想配列である std::map(いわゆるHashMapに相当)から、特定のキーを持つエントリを削除したい場面はよくあります。本チュートリアルでは、マップを走査(イテレーション)している最中に、キーを指定してエントリを削除する方法を詳しく解説します。

問題の例

入力: HashMap: { 1: “Tutorials”,
                 2: “Tutorials”,
                 3: “Point” }, key=1

出力: HashMap: { 2: “Tutorials”,
                 3: “Point” }

説明: キー「1」に対応する要素が削除されます。

入力: HashMap: { 1: “God”,
                 2: “is”,
                 3: “Great” }, key=2

出力: HashMap: { 1: “God”,
                 3: “Great” }

解決のためのアプローチ

C++では、erase() 関数にキーを渡すだけで、該当するエントリを簡単に削除できます。しかし、反復処理中に削除を行う場合は、イテレータも併用する必要があります。

基本的な考え方は、マップを先頭から順に走査し、各要素のキーが削除対象のキーと一致した時点でそのエントリを削除するというものです。ここで重要なのが、要素を削除するとその位置を指していたイテレータは無効化されるため、erase() の戻り値として返される「次の有効なイテレータ」を受け取る必要があるという点です。

実装例

1. 反復処理なしで削除する場合

まずは、イテレーションを行わずに、キーを直接指定して要素を削除する基本的なコードを見てみましょう。

#include<iostream>
#include<map> // map操作用ヘッダ
using namespace std;
int main(){
    // HashMapの作成
    map< int, string > mp;
    // キーと値のペアを挿入
    mp[1]="Tutorials";
    mp[2]="Tutorials";
    mp[3]="Point";
    int key = 2;
    // イテレータの作成
    map<int, string>::iterator it;
    // 削除前のHashMapを表示
    cout<< "HashMap before Deletion:\n";
    for (it = mp.begin(); it!=mp.end(); ++it)
        cout << it->first << "->" << it->second << endl;
    // キーを指定して削除
    mp.erase(key);
    // 削除後のHashMapを表示
    cout<< "HashMap After Deletion:\n";
    for (it = mp.begin(); it!=mp.end(); ++it)
        cout << it->first << "->" << it->second << endl;
    return 0;
}

出力結果

HashMap before Deletion:
1->Tutorials
2->Tutorials
3->Point

HashMap After Deletion:
1->Tutorials
3->Point

2. 反復処理中に要素を削除する場合

次に、マップを走査しながら条件に合致する要素を削除する方法を紹介します。ポイントは、erase(it) が戻り値として「削除した要素の次の要素」を指すイテレータを返すことを利用することです。これにより、イテレータの無効化による未定義動作を確実に防ぐことができます。

#include<iostream>
#include<map> // map操作用ヘッダ
using namespace std;
int main(){
    // HashMapの作成
    map< int, string > mp;
    // キーと値のペアを挿入
    mp[1]="Tutorials";
    mp[2]="Tutorials";
    mp[3]="Point";
    int key = 2;
    // 削除前のHashMapを表示
    cout<< "HashMap before Deletion:\n";
    for (auto it = mp.begin(); it!=mp.end(); ++it)
        cout << it->first << "->" << it->second << endl;
    // 反復処理しながら削除
    for (auto it = mp.begin(); it != mp.end(); ) {
        // 現在のキーが対象キーと一致するか確認
        if (it->first == key) {
            // 要素を削除し、次の有効なイテレータを取得
            it = mp.erase(it);
        } else {
            ++it;
        }
    }
    // 削除後のHashMapを表示
    cout<< "HashMap After Deletion:\n";
    for (auto it = mp.begin(); it!=mp.end(); ++it)
        cout << it->first << "->" << it->second << endl;
    return 0;
}

出力結果

HashMap before Deletion:
1->Tutorials
2->Tutorials
3->Point

HashMap After Deletion:
1->Tutorials
3->Point

注意点

反復処理中に mp.erase(it) を呼び出した後も同じイテレータを使い続けると、イテレータが無効化されているため、未定義動作(プログラムのクラッシュなど)を引き起こす恐れがあります。必ず it = mp.erase(it) のように戻り値を受け取り、イテレータを正しく更新してください。

まとめ

本チュートリアルでは、C++のマップ(HashMap)からエントリを削除する方法として、①キーを直接指定して削除する方法、②反復処理中に条件に合致する要素を削除する方法の2つを解説しました。特に反復処理中の削除では、イテレータの無効化に注意し、erase() の戻り値を活用することが重要です。この考え方は、JavaやPythonなど他のプログラミング言語でも同様に応用できます。皆さんの学習に役立てば幸いです。

  1. C++を使って文字列から特定の単語を削除する方法

    本記事では、与えられた文字列から指定した単語を削除する問題を解説します。まず、具体的な例を見てみましょう。入力 : str = remove a given word, word = remove 出力 : a given word 入力 : str = god is everywhere, word = is 出力 : god everywhere解決のためのアプローチ文字列から特定の単語を削除するには、シンプルな手法を用いることができます。手順は以下の通りです。まず、与えられた文字列を2次元配列(マトリックス)形式に変換し、各行に1つの単語を格納します。マトリックス内から対象の単語を検索

  2. 【C++】キューを使って二分探索木(BST)のパスを反転する方法

    問題の概要 二分探索木(BST)が与えられ、特定のキーからルートに至るパス上のノードの値を反転することが求められます。 たとえば次のようなイメージです。 解決のためのアプローチ このアプローチでは、まず空のキューを用意してルートから探索を開始します。木を辿りながら経路上のノードの値を順番にキューへプッシュしていき、目的のキーを持つノードが見つかったら、再帰の帰り道でキューの先頭から順に値を書き戻します。こうすることで、パス上のノードの値がきれいに反転されます。 C++での実装例 #include <bits/stdc++.h> using namespace std; stru