English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

簡単にcについて話す++stlのmapの使用法の詳細な説明

MapはSTLの関連コンテナであり、一对一(最初のものはキーと呼ばれ、キーはmapに一度しか出現しません。第二のものはキーの値と呼ばれます)のデータ処理能力を提供します。この特性により、一对一データを処理する際に、プログラミング上の高速パスを提供することが可能です。ここで、map内部データの構造について説明します。map内部は自前の红黑木(厳密にはバランスの取れた二分木ではない)を持っており、データを自動的にソートする機能があります。したがって、map内部のすべてのデータはソートされています。後で、ソートされたデータの利点を目撃します。

以下に、一对一データマッピングとは何かを説明します。例えば、クラスの中で、各生徒の学生番号と名前は一一対応しています。このモデルはmapで簡単に表現できます。明らかに、学生番号はintで表現され、名前は文字列で表現されます(この記事ではcharを使用しません)。 *を使用して文字列を表現するのではなく、STLのstringを使用して表現します)。以下にmapの表現コードを示します:

Map<int, string> mapStudent;

1. mapのコンストラクタ

mapは以下のような機能を提供しています:6のコンストラクタ、ここではメモリ割り当てなどのものが関与しますが、ここでは省略します。以下では、mapの構築方法について触れます。ここで言いたいのは、通常、以下のようにmapを構築します:

Map<int, string> mapStudent;

2データの挿入

mapコンテナを構築した後、データを挿入することができます。ここで、データを挿入する三つの方法について説明します:

第一種:insert関数を使用してpairデータを挿入する方法を以下に例示します。(以下のコードは手早く書いたものであり、VCとGCCでコンパイルできるはずです。皆さんは結果を確認してみてください。VCではこの文を追加して、警告を抑制してください。4786警告 #pragma warning (disable:4786) )

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(pair<int, string>(1, “student_one”));
    mapStudent.insert(pair<int, string>(2, “student_two”));
    mapStudent.insert(pair<int, string>(3, “student_three”));
    map<int, string>::iterator iter;
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
    Cout << iter->first << "  " << iter->second << end;
}
}

第二種:insert関数を使用してvalue_typeデータを挿入する方法を以下に例示します。

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(map<int, string>::value_type (1, “student_one”));
    mapStudent.insert(map<int, string>::value_type (2, “student_two”));
    mapStudent.insert(map<int, string>::value_type (3, “student_three”));
    map<int, string>::iterator iter;
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
    Cout << iter->first << "  " << iter->second << end;
}
}

第三種:配列方式を使用してデータを挿入する方法を以下に例示します。

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent[1] = “student_one”;
    mapStudent[2] = “student_two”;
    mapStudent[3] = “student_three”;
    map<int, string>::iterator iter;
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
    Cout << iter->first << "  " << iter->second << end;
}
}

これらの三つの用法は、データの挿入が可能ですが、違いがあります。もちろん、最初のものと二番目のものは効果が同じです。insert関数を使用してデータを挿入すると、データの挿入に集合のユニーク性の概念が関与します。つまり、mapにそのキーワードがある場合、insert操作はデータを挿入できませんが、配列方式では異なります。それは以前のキーワードに対応する値を上書きできます。プログラムで説明します。

mapStudent.insert(map<int, string>::value_type (1, “student_one”));
mapStudent.insert(map<int, string>::value_type (1, “student_two”));

上面这两条语句执行后,map中1这个关键字对应的值是“student_one”,第二条语句并没有生效,那么这就涉及到我们如何知道insert语句是否插入成功的问题了,可以使用pair来获取是否插入成功,程序如下

Pair<map<int, string>::iterator, bool> Insert_Pair;
Insert_Pair = mapStudent.insert(map<int, string>::value_type (1, “student_one”));

我们通过pair的第二个变量来判断是否插入成功,它的第一个变量返回的是一个map的迭代器,如果插入成功的话Insert_Pair.second应该是true的,否则为false。

下面给出完成代码,演示插入成功与否的问题

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
Pair<map<int, string>::iterator, bool> Insert_Pair;
    Insert_Pair = mapStudent.insert(pair<int, string>%1, “student_one”));
    If(Insert_Pair.second == true)
    {
       Cout<<”Insert Successfully”<<endl;
    }
    Else
    {
       Cout<<”Insert Failure”<<endl;
    }
    Insert_Pair = mapStudent.insert(pair<int, string>%1, “student_two”));
    If(Insert_Pair.second == true)
    {
       Cout<<”Insert Successfully”<<endl;
    }
    Else
    {
       Cout<<”Insert Failure”<<endl;
    }
    map<int, string>::iterator iter;
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
    Cout << iter->first << "  " << iter->second << end;
}
}

大家可以使用以下程序,看看使用数组插入数据覆盖的效果

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent[1] = “student_one”;
    mapStudent[1] = “student_two”;
    mapStudent[2] = “student_three”;
    map<int, string>::iterator iter;
    for(iter = mapStudent.begin(); iter != mapStudent.end(); iter++)
{
    Cout << iter->first << "  " << iter->second << end;
}
}

3map的大小

在向map中插入数据后,我们如何知道已经插入了多少数据呢?可以使用size函数,使用方法如下:

Int nSize = mapStudent.size();

4数据遍历

这里也提供了三种遍历map的方法

第一种:使用正向迭代器,上面给出的示例程序中到处都是,此处省略不述

第二种:使用逆序迭代器,以下举例说明,为了体会效果,请自行运行程序

#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(pair<int, string>(1, “student_one”));
    mapStudent.insert(pair<int, string>(2, “student_two”));
    mapStudent.insert(pair<int, string>(3, “student_three”));
    map<int, string>::reverse_iterator iter;
    for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++)
{
    Cout << iter->first << "  " << iter->second << end;
}
}

第三種:配列方式、プログラムの説明如下

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(pair<int, string>(1, “student_one”));
    mapStudent.insert(pair<int, string>(2, “student_two”));
    mapStudent.insert(pair<int, string>(3, “student_three”));
    int nSize = mapStudent.size()
//ここに誤りがあります、for(int nIndex = 1; nIndex <= nSize; nIndex++)
//by rainfish
    for(int nIndex = 0; nIndex < nSize; nIndex++)
{
    Cout << mapStudent[nIndex] << end;
}
}

5. データの検索(このキーワードがmapに存在するかどうかを判定することも含みます)

ここで、mapにデータを挿入する際にソートを保証する利点を実感します

データ(キーワード)がmapに存在するかどうかを判定する方法はたくさんあります、ここではタイトルはデータの検索ですが、mapの基本的な使い方を多く交えて説明します

ここでは、データの検索方法の三種類を示します

第一種:count関数を使ってキーワードが存在するかどうかを判定しますが、欠点はデータの位置を特定できないことです、mapの特性である一対一のマッピング関係により、count関数の返値は二つのうちのいずれかです、0か1発生する場合、もちろん、返されます1、

第二種:find関数を使ってデータの位置を特定します、この関数はイテレータを返します、データが存在する場合、データの位置のイテレータを返します、mapに検索するデータがない場合、返されるイテレータはend関数が返すイテレータと同じです、プログラムの説明

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(pair<int, string>(1, “student_one”));
    mapStudent.insert(pair<int, string>(2, “student_two”));
    mapStudent.insert(pair<int, string>(3, “student_three”));
    map<int, string>::iterator iter;
    iter = mapStudent.find(1;
if(iter != mapStudent.end())
{
    Cout << "Find, the value is " << iter->second<<endl;
}
Else
{
    Cout << "Do not Find" << endl;
}
}

第三種:このメソッドはデータが存在するかどうかを判定するために使われますが、少し退屈ですが、ここで説明します

Lower_bound関数の使い方、この関数は検索するキーワードの下界(イテレータ)を返します

Upper_bound関数の使い方、この関数は検索するキーワードの上界(イテレータ)を返します

例えば:mapにはすでに挿入されています1、2、3、4の場合、lower_bound(2)の場合、返されるのは2、そしてupper-bound(2)の場合、返されるのは3

Equal_range関数はpairを返します、pairの最初の変数はLower_boundが返すイテレータ、pairの二番目のイテレータはUpper_boundが返すイテレータです、この二つのイテレータが等しい場合、mapにはそのキーワードが存在しないことを示します、プログラムの説明

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent[1] = “student_one”;
    mapStudent[3] = “student_three”;
    mapStudent[5] = “student_five”;
    map<int, string>::iterator iter;
iter = mapStudent.lower_bound(2;
{
    //が返されますのは下界です3のイテレータ
    Cout << iter->second<<endl;
}
iter = mapStudent.lower_bound(3;
{
    //が返されますのは下界です3のイテレータ
    Cout << iter->second<<endl;
}
iter = mapStudent.upper_bound(2;
{
    //が返されますのは上界です3のイテレータ
    Cout << iter->second<<endl;
}
iter = mapStudent.upper_bound(3;
{
    //が返されますのは上界です5のイテレータ
    Cout << iter->second<<endl;
}
Pair<map<int, string>::iterator, map<int, string>::iterator> mapPair;
mapPair = mapStudent.equal_range(2;
if(mapPair.first == mapPair.second)
    {
    cout << ”Do not Find” << endl;
}
Else
{
Cout << ”Find” << endl;
}
mapPair = mapStudent.equal_range(3;
if(mapPair.first == mapPair.second)
    {
    cout << ”Do not Find” << endl;
}
Else
{
Cout << ”Find” << endl;
}
}

6. データのクリアと判空

データをクリアするにはclear()関数を使用し、マップにデータがあるかどうかを判定するにはempty()関数を使用します、それがtrueであれば空のマップです

7. データの削除

erase関数を使用する必要がありますが、それには3つのオーバーロードされた関数があります、以下の例でその使用法を詳細に説明します

#include <map>
#include <string>
#include <iostream>
Using namespace std;
Int main()
{
    Map<int, string> mapStudent;
    mapStudent.insert(pair<int, string>(1, “student_one”));
    mapStudent.insert(pair<int, string>(2, “student_two”));
    mapStudent.insert(pair<int, string>(3, “student_three”));
//出力効果をデモンストレーションする場合は、以下のいずれかを選んでください、見た方が良い効果が得られます
    //削除したい場合1イテレータを使用して削除します
    map<int, string>::iterator iter;
    iter = mapStudent.find(1;
    mapStudent.erase(iter);
    //削除したい場合1キーワードで削除します
    Int n = mapStudent.erase(1;//削除した場合は返されます1そうでない場合は0を返します
    //イテレータを使用して、一括で削除します
    //以下のコードはマップ全体をクリアします
    mapStudent.erase(mapStudent.begin(), mapStudent.end());
    //一括削除に注意すべきことは、STLの特性でもありますが、削除範囲は前閉後開の集合です
    //自分自身をループコードに追加して、出力を出力してください
}

8. 其他一些函数用法

这里有swap,key_comp,value_comp,get_allocator等函数,感觉到这些函数在编程用的不是很多,略过不表,有兴趣的话可以自个研究

9. 排序

这里要讲的是一点比较高深的用法了,排序问题,STL中默认是采用小于号来排序的,以上代码在排序上是不存在任何问题的,因为上面的关键字是int型,它本身支持小于号运算,在一些特殊情况,比如关键字是一个结构体,涉及到排序就会出现问题,因为它没有小于号操作,insert等函数在编译的时候过不去,下面给出两个方法解决这个问题

第一种:小于号重载,程序举例

#include <map>
#include <string>
Using namespace std;
Typedef struct tagStudentInfo
{
    Int   nID;
    String  strName;
}StudentInfo, *PStudentInfo; //学生信息
Int main()
{
  int nSize;
    //学生情報をスコアにマッピング
    map<StudentInfo, int>mapStudent;
  map<StudentInfo, int>::iterator iter;
    StudentInfo studentInfo;
    studentInfo.nID = 1;
    studentInfo.strName = “student_one”;
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
    studentInfo.nID = 2;
    studentInfo.strName = “student_two”;
mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));
for (iter=mapStudent.begin(); iter!=mapStudent.end(); iter++)
  cout<<iter->first.nID<<endl<<iter->first.strName<<endl<<iter->second<<endl;
}

以上程序是无法编译通过的,只要重载小于号,就OK了,如下:

Typedef struct tagStudentInfo
{
    Int   nID;
    String  strName;
    Bool operator < (tagStudentInfo const& _A) const
    {
       //这个函数指定排序策略,按nID排序,如果nID相等的话,按strName排序
       If(nID < _A.nID) return true;
       If(nID == _A.nID) return strName.compare(_A.strName) < 0;
       Return false;
    }
}StudentInfo, *PStudentInfo; //学生信息

第二种:仿函数的应用,这个时候结构体中没有直接的小于号重载,程序说明

#include <map>
#include <string>
Using namespace std;
Typedef struct tagStudentInfo
{
    Int   nID;
    String  strName;
}StudentInfo, *PStudentInfo; //学生信息
Classs sort
{
    Public:
    Bool operator() (StudentInfo const &_A, StudentInfo const &_B) const
    {
       If(_A.nID < _B.nID) return true;
       If(_A.nID == _B.nID) return _A.strName.compare(_B.strName) < 0;
       Return false;
    }
};
Int main()
{
    //学生情報をスコアにマッピング
    Map<StudentInfo, int, sort>mapStudent;
    StudentInfo studentInfo;
    studentInfo.nID = 1;
    studentInfo.strName = “student_one”;
    mapStudent.insert(pair<StudentInfo, int>(studentInfo, 90));
    studentInfo.nID = 2;
    studentInfo.strName = “student_two”;
mapStudent.insert(pair<StudentInfo, int>(studentInfo, 80));
}

10. また

STLは統一された全体であり、mapの多くの使用法はSTLの他のものと組み合わせられています。例えば、ソートでは、ここではデフォルトで小于号(less<>)を使用しており、逆順にソートするには多くのことが関わってきますが、ここではすべてを説明することはできません。

また、mapは内部が整列しており、赤黒木によって保証されていますので、多くの関数の実行時間複雑度はlog2Nの、map関数で実現できる機能があれば、STL Algorithmでも同じ機能を完了できますが、mapのビルトイン関数を使用することを推奨します。効率が少し高くなります。

次に、mapの空間的特性について説明します。さもなければ、使うときに時々イライラするかもしれません。mapの各データは赤黒木のノードに対応しており、データを保存していないときにそのノードは占有16バイトの文字、1つの親ノードポインタ、左右の子供ポインタ、そして1つの列挙値(赤黒の標示、平衡二叉木の平衡因子に相当)があって、これらの場所が非常にメモリを消費するのは分かっているでしょう、言わないで……

これで、編集者が皆さんに提供した軽く言ったcのことについての話はこれで終わりです++中のstlのmapの使用法の詳細な内容がすべて含まれています。皆さん、呐喊ガイドを多く応援してください~

おすすめ