STL map

7443 ワード

STLにおけるmapの用法剖析【完全版】について
1 map概要STL(Standard Template Library標準テンプレートライブラリ)はC++標準ライブラリの核心であり、標準ライブラリの全体構造に深刻な影響を及ぼしている.STLはモデルライブラリであり、先進的で効率的なアルゴリズムを利用してデータを管理する一連のソフトウェアスキームを提供しています.STLの利点は、mapがその典型的な代表である多くのデータ構造およびアルゴリズム(algorithm)をカプセル化することである.mapはSTLの関連コンテナであり、1対1(key/valueのうち1つ目はキーワードと呼ぶことができ、各キーワードはmapに1回しか現れず、2つ目はキーワードの値と呼ぶことができる)のデータ処理能力を提供する.この特性のため、1対1のデータを処理する際にプログラミングの高速チャネルを提供することができる.2 mapの用法は1つのクラスの中で、各学生の学号と彼の名前には1つ1つのマッピングの関係があると仮定し、このモデルはmapで簡単に記述することができ、学号はintで記述し、名前は文字列で記述し、mapの記述コードを与える:mapmapStudio.2.1データmap要素を挿入する挿入機能は、mapの要素をプライマリ・キーで取得し、取得した場合、対応するノードに対応する実値(mapノードに格納されているオブジェクト)を返すことによって実現できます.しかし、この方法は副作用を生じ、プライマリ・キー「key」でノードの実値を取得し、mapにこのノードが存在しない場合、keyをプライマリ・キーとするノードを直接mapに挿入し、このノードに戻ると、付与操作を行うことができる.ただし、mapにキーをプライマリキーとするノードが存在する場合は、そのノードの実値が返され、このときコピー操作を行うと、元のノードが新しいノードで上書きされる危険性があり、ポインタタイプであればメモリ漏れなどの問題が発生します.このような副作用があるため,この方法では元素の挿入は推奨されない.2番目の挿入value_typeデータ.Insertメソッドインタフェースのプロトタイプ:pairinsert(const value_type&X)このメソッドは、value_typeは、次にinsertメソッドを呼び出し、キー値ペアのkey値に基づいて対応するノードを検索し、検索された場合、現在のノードを挿入せず、検索されたノードを返し、pairの2番目の量をfalseに設定する.そうでなければ、現在のノードを挿入し、挿入された現在のノードを返し、2番目の値をtrueにします.ノードを挿入するとmap内部に新しいvalue_が再構築されます.typeノードは、入力されたXをcopy構造し、内部でplacement new方式を使用し、メモリディスペンサにmapノードを割り当て、取得したノード空間でvalue_を呼び出す.type構造関数.だから呼び出し者が構築したキー値はvalue_に対してtypeは一時変数であり、mapには含まれません(参照オペレータに惑わされないでください.ここではパラメータ効率の考慮にすぎません).このようなノード挿入の方式は安全であり,mapに要素を挿入し,返された挿入結果を判断し,挿入結果に基づいて後続処理を行うことを提案する.
#pragma warning(disable:4786)
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
map<int,string> mapStudent;
mapStudent.insert(map<int,string>::value_type(1,"one"));
mapStudent.insert(map<int,string>::value_type(2,"two"));
mapStudent.insert(map<int,string>::value_type(3,"three"));
map<int,string>::iterator iter;
for(iter=mapStudent.begin();iter!=mapStudent.end();iter++)
{
     cout<<iter->first<<" "<<iter->second<<endl;
}
}
.2.2 mapの大きいはmapの中でデータを挿入して、size()関数で現在すでにどれだけのデータを挿入したことを得ることができます:int nSize=mapStudio.size()2.3ソートSTLではデフォルトでは小さい番号でソートされますが、上記のコードはソートに問題はありません.上記の例のキーワードはint型であり、それ自体が小さい番号演算をサポートしているためです.いくつかの特殊な場合、例えばキーワードは構造体であり、ソートに関連すると問題が発生します.それは番号演算よりも小さくないので、insertなどの関数はコンパイル時に通過できません.ソートの問題を解決する方法を示します.番号より小さいリロードです.
#pragma warning(disable:4786)
#include <map>
#include <string>
#include <iostream>
using namespace std;
typedef struct tagStudentInfo 
{
int nID;
string strName;
} StudentInfo, *PStudentInfo;   //     
int main()
{
//         
map<StudentInfo, int> mapStudent;
StudentInfo studentInfo;
studentInfo.nID=2;
studentInfo.strName="one";
mapStudent.insert(map<StudentInfo, int>::value_type (studentInfo,90));
studentInfo.nID=1;
studentInfo.strName="two";
mapStudent.insert(map<StudentInfo, int>::value_type (studentInfo,80));
}
以上のプログラムはコンパイルできません.番号未満の再ロードが必要です.
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; 
2.4 map        
          :
       :    map          。
            ,        map   ,             。
#pragma warning(disable:4786)
#include <map>
#include <string>
#include <iostream>
using namespace std;
void main()
{
map<int,string> mapStudent;
mapStudent.insert(map<int,string>::value_type(1,"one"));
mapStudent.insert(map<int,string>::value_type(2,"two"));
mapStudent.insert(map<int,string>::value_type(3,"three"));
map<int,string>::iterator iter;
iter=mapStudent.find(1);
mapStudent.erase(iter);
for(iter=mapStudent.begin();iter!=mapStudent.end();iter++)
{
     cout<<iter->first<<" "<<iter->second<<endl;
}
}
第2種:mapからすべてのノードを遍歴検査し、条件に合致するノードを削除する.適用シーンの説明:システムは定期的にゴミセッション(セッションをmapテーブルに配置)をチェックし、現在のシステム時間からセッションの最近のアクティビティ時間を減算して、セッションの最近の非アクティブ時間間隔を得、この間隔が所定の値を超えた場合(セッションがゴミセッションであると判断され、強制的に削除できる)、セッションを削除し、mapからこのノードを削除する.作り方は2つあります.(1)まずmapを遍歴し,条件を満たすすべてのノードを探し出し,対応する各ノードのkeyを1つのvectorに入れ,後でvectorからkey値を順次取り出し,単ノード削除操作を行う.この方法は原始的で効率の低い方法であり,このように実現するのは,開発者がmapの使用をあまり知らない上で行われたためである.1つの方法は、中間処理プロセスのシステムオーバーヘッド(キャッシュ空間を複数構築)を増加させるだけでなく、N(ノードを削除するノード数)回のクエリー操作を多くするだけでなく、頻繁に発生する操作に対して、このような低効率は許容できない.(2)map遍歴の過程で,条件に合致するノードの削除操作を完了する(これはmap自体のデータ構造特性によって保証される).遍歴の過程で最も重要なのは、削除されたノードが削除前に次のノードにポインタを向けることを保証する方法であり、現在のノードを削除した後、mapのデータ構造は後続の反復器ポインタが有効であることを保証することができる.さらに後続のノードは遍歴していない(この特性はmap下層の赤黒樹の関連操作によって保証されている).したがって、反復器を次のノードに向けてから、現在の条件に合致するノードを削除する必要があります.
#pragma warning(disable:4786)
#include <map>
#include <string>
#include <iostream>
using namespace std;
void main()
{
map<int,string> mapStudent;
mapStudent.insert(map<int,string>::value_type(1,"one"));
mapStudent.insert(map<int,string>::value_type(2,"two"));
mapStudent.insert(map<int,string>::value_type(3,"three"));
map<int,string>::iterator iter;
string aa="three";
iter=mapStudent.begin();
for(;iter!=mapStudent.end();)
{
     if((iter->second)>=aa)
     {
         //      ,      ,         
              mapStudent.erase(iter++);
     }
     else
     {
     //     ,        
     iter++;
     }
}
for(iter=mapStudent.begin();iter!=mapStudent.end();iter++)
{
     cout<<iter->first<<" "<<iter->second<<endl;
}
}
このような削除方式もSTLソース一書で推奨されている方式である.比較してみましょうerase(iter+)とmapStudio.erase(iter); iter++;この実行シーケンス.簡単なテストをして、アセンブリ実行の実行シーケンスを見てみましょう.void func(int a){}int main(int,char*){int iPos=0;func(iPos++)}関数呼び出しfunc(iPos++)実行シーケンス:iPosをレジスタedxに入れ(キャッシュ)、iPosをランダムに加算操作inc dword ptr[ebp-0 x 04].すなわち,関数呼び出しにおけるiPos++の実行時期は関数体funcの実行前に完了しており,関数体のパラメータはiPosが加算操作を行わない前のコピーを用いている.再分析erase(iter++)文、mapでiterを削除するときは、まずiterをキャッシュし、次にiter++を実行して次のノードを指し示し、erase関数体に入って削除操作を実行し、削除時に使用するiterはキャッシュされたiter(すなわち、現在のiter(加算操作をしたiter)がノードを指す前のノード)である.以上の分析からmapStudentが分かる.erase(iter+)とmap Studio.erase(iter); iter++;この実行シーケンスは異なります.前者はerase実行前に加算操作を行い、iterが削除(失効)される前に加算操作を行い、安全である.後者はeraseが実行された後に加算操作を行うが、iterは削除され(現在の反復器は失効している)、失効した反復器を加算操作し、動作は予想できない.このような書き方はmap操作の失敗を招き、プロセスの異常を引き起こすに違いない.3終わりの語はmapの強大な機能を十分に利用して、プログラマーの仕事量を大幅に軽減することができて、伝統的な方法で書いた多くの行のコードを採用して、往々にして1、2つのアルゴリズムのテンプレートを呼び出すことによって実現することができます.mapテクノロジーは、プログラマーに簡潔で効率的なコードを記述させ、プログラミング作業をより簡単で効率的にすることができます.参考文献[1]Nicolai M.Josuttis.C++標準ライブラリ[M].武漢:華中科学技術大学出版社、2006.[2] Scott Meyers. Effective STL中国語版——STLを有効に使用した経験50件[M].北京:清華大学出版社、2006.[3]侯捷.STLソースの剖析[M].武漢:華中科学技術大学出版社、2002.[4]王昌晶、薛錦雲.C++からSTL[J].江西師範大学学報、2004(8):231-234.