std::map




映射和多重映射基於某一類型Key的鍵集的存在,提供對T類型的數據進行快速和高效的檢索。對map而言,鍵只是指存儲在容器中的某一成員。Map不支持副本鍵,multimap支持副本鍵。Map和multimap對象包涵了鍵和各個鍵有關的值,鍵和值的數據類型是不相同的,這與set不同。set中的key和value是Key類型的,而map中的key和value是一個pair結構中的兩個分量。

1.map介紹

  使用map得包含map類所在的頭文件: 

  #include <map> //注意,STL頭文件沒有擴展名.h

1.1 map的構造

  Template<class T1,class T2>

  map(); // 默認構造函數

  map(const map& m) // 拷貝構造函數

  map(iterator begin,iterator end ); //區間構造函數

  map(iterator begin,iterator end, const traits& _compare) //帶比較謂詞的構造函數

  map(iterator begin,iterator end, const traits& _compare, const allocator& all) //帶分配器

1.2 map定義

  1.2.1map的基本定義

  map對象是模板類,需要關鍵字和存儲對象兩個模板參數:

  std:map<int,string> personnel;

  這樣就定義了一個用int作爲索引,並擁有相關聯的指向string的指針.

  爲了使用方便,可以對模板類進行一下類型定義:

  typedef map<int,CString> UDT_MAP_INT_CSTRING;

  UDT_MAP_INT_CSTRING enumMap; //後面會依此例說明

  1.2.2 map的嵌套定義

  map<sring,map<string,long>> //注意:最後兩個>之間有個空格

  map支持下標運算符operator[],用訪問普通數組的方式來訪問map;不過下標爲map的鍵,在multimap中一個鍵可以對應多個不同的值。

2.map的方法

2.1 在map中插入元素

  三種插入方式:

  2.1.1用insert方法插入pair對象:

   enumMap.insert(pair<int,Cstring>(1, “One”));

  2.1.2 用insert方法插入value_type對象:

   enumMap.insert(map<int,Cstring>::value_type (1, “One”));

  2.1.3 用數組方式插入值:

   enumMap[1] ="One";

  enumMap[2] ="Two";

  ......

  這樣非常直觀,但存在一個性能的問題。插入2時,先在enumMap中查找主鍵爲2的項,沒發現,然後將一個新的對象插入enumMap,鍵是2,值是一個空字符串,插入完成後,將字符串賦爲"Two";該方法會將每個值都賦爲缺省值,然後再賦爲顯示的值,如果元素是類對象,則開銷比較大。用前兩種方法可以避免開銷。

2.2 查找並獲取map中元素

  2.2.1下標操作符給出了獲得一個值的最簡單方法:

  CString tmp = enumMap[2];

  但是,只有當map中有這個鍵的實例時纔對,否則會自動插入一個實例,值爲初始化值。

  2.2.2我們可以使用find()和count()方法來發現一個鍵是否存在

  查找map中是否包含某個關鍵字條目用find()方法,傳入的參數是要查找的key,在這裏需要提到的是begin()和end()兩個成員,分別代表map對象中第一個條目和最後一個條目,這兩個數據的類型是iterator.

  int nFindKey = 2; //要查找的Key

  //定義一個條目變量(實際是指針)

  UDT_MAP_INT_CSTRING::iteratorit= enumMap.find(nFindKey);

  if(it == enumMap.end()) {

  cout<<"沒找到"<<endl;

  }

  else {

  cout<<"找到了"<<endl;

  }

  通過map對象的方法獲取的iterator數據類型是一個std::pair對象,包括兩個數據。

  iterator->first 關鍵字(key)

  iterator->second 存儲的數據(value)

2.3 從map中刪除元素

  2.3.1移除某個map中某個條目用erase()

  該成員方法的定義如下:

  1.iterator erase(iteratorit); //通過一個條目對象刪除

  2.iterator erase(iteratorfirst, iterator last); //刪除一個範圍

  3.size_type erase(constKey& key); //通過關鍵字刪除

  2.3.2清除所有的元素clear()

  clear()就相當於enumMap.erase(enumMap.begin(), enumMap.end());

2.4 map中swap的用法

  map中的swap不是一個容器中的元素交換,而是兩個容器交換;

  For example:

  #include <map>

  #include <iostream>

  using namespace std;

  int main( )

  {

  map <int, int> m1,m2, m3;

  map <int,int>::iterator m1_Iter;

  m1.insert ( pair <int,int> ( 1, 10 ) );

  m1.insert ( pair <int,int> ( 2, 20 ) );

  m1.insert ( pair <int,int> ( 3, 30 ) );

  m2.insert ( pair <int,int> ( 10, 100 ) );

  m2.insert ( pair <int,int> ( 20, 200 ) );

  m3.insert ( pair <int,int> ( 30, 300 ) );

  cout << "Theoriginal map m1 is:";

  for ( m1_Iter = m1.begin(); m1_Iter != m1.end( ); m1_Iter++ )

  cout << "" << m1_Iter->second;

  cout <<"." << endl;

  // This is the memberfunction version of swap

  //m2 is said to be theargument map; m1 the target map

  m1.swap( m2 );

  cout << "Afterswapping with m2, map m1 is:";

  for ( m1_Iter = m1.begin(); m1_Iter != m1.end( ); m1_Iter++ )

  cout << "" << m1_Iter -> second;

  cout <<"." << endl;

  cout << "Afterswapping with m2, map m2 is:";

  for ( m1_Iter = m2.begin(); m1_Iter != m2.end( ); m1_Iter++ )

  cout << "" << m1_Iter -> second;

  cout <<"." << endl;

  // This is thespecialized template version of swap

  swap( m1, m3 );

  cout << "Afterswapping with m3, map m1 is:";

  for ( m1_Iter = m1.begin(); m1_Iter != m1.end( ); m1_Iter++ )

  cout << "" << m1_Iter -> second;

  cout <<"." << endl;

  }

2.5 map的sort問題

  Map中的元素是自動按key升序排序,所以不能對map用sort函數:

  For example:

  #include <map>

  #include <iostream>

  using namespace std;

  int main( )

  {

  map <int, int> m1;

  map <int,int>::iterator m1_Iter;

  m1.insert ( pair <int,int> ( 1, 20 ) );

  m1.insert ( pair <int,int> ( 4, 40 ) );

  m1.insert ( pair <int,int> ( 3, 60 ) );

  m1.insert ( pair <int,int> ( 2, 50 ) );

  m1.insert ( pair <int,int> ( 6, 40 ) );

  m1.insert ( pair <int,int> ( 7, 30 ) );

  cout << "Theoriginal map m1 is:"<<endl;

  for ( m1_Iter = m1.begin(); m1_Iter != m1.end( ); m1_Iter++ )

  cout <<m1_Iter->first<<" "<<m1_Iter->second<<endl;

  }

  The original map m1 is:

  1 20

  2 50

  3 60

  4 40

  6 40

  7 30

  請按任意鍵繼續. . .

2.6 map的基本操作函數

  C++ Maps是一種關聯式容器,包含“關鍵字/值”對

  begin() 返回指向map頭部的迭代器

  clear() 刪除所有元素

  count() 返回指定元素出現的次數

  empty() 如果map爲空則返回true

  end() 返回指向map末尾的迭代器

  equal_range() 返回特殊條目的迭代器對

  erase() 刪除一個元素

  find() 查找一個元素

  get_allocator() 返回map的配置器

  insert() 插入元素

  key_comp() 返回比較元素key的函數

  lower_bound() 返回鍵值>=給定元素的第一個位置

  max_size() 返回可以容納的最大元素個數

  rbegin() 返回一個指向map尾部的逆向迭代器

  rend() 返回一個指向map頭部的逆向迭代器

  size() 返回map中元素的個數

  swap() 交換兩個map

  upper_bound() 返回鍵值>給定元素的第一個位置

  value_comp() 返回比較元素value的函數

3.例子

  #include <iostream>

  #include <map>

  using namespace std;

  int main(void)

  {

  map<char,int,less<char>> map1;

  map<char,int,less<char>>::iterator mapIter;

  //char 是鍵的類型,int是值的類型

  //下面是初始化,與數組類似

  //也可以用map1.insert(map<char,int,less<char>>::value_type('c',3));

  map1['c']=3;

  map1['d']=4;

  map1['a']=1;

  map1['b']=2;

  for(mapIter=map1.begin();mapIter!=map1.end();++mapIter)

  cout<<""<<(*mapIter).first<<": "<<(*mapIter).second;

  //first對應定義中的char鍵,second對應定義中的int值

  //檢索對應於d鍵的值是這樣做的:

  map<char,int,less<char>>::const_iterator ptr;

  ptr=map1.find('d');

  cout<<''\n''<<""<<(*ptr).first<<" 鍵對應於值:"<<(*ptr).second;

  cin.get();

  return 0;

  }

  從以上例程中,我們可以看到map對象的行爲和一般數組的行爲類似。Map允許兩個或多個值使用比較操作符。下面我們再看看multimap:

  #include <iostream>

  #include <map>

  #include <string>

  using namespace std;

  int main(void)

  {

  multimap<string,string,less<string>>mulmap;

  multimap<string,string,less<string>>::iterator p;

  //初始化多重映射mulmap:

  typedefmultimap<string,string,less<string> >::value_type vt;

  typedef string s;

  mulmap.insert(vt(s("Tom"),s("is a student")));

  mulmap.insert(vt(s("Tom"),s("is a boy")));

  mulmap.insert(vt(s("Tom"),s("is a bad boy of blue!")));

  mulmap.insert(vt(s("Jerry"),s("is a student")));

  mulmap.insert(vt(s("Jerry"),s("is a beatutiful girl")));

  mulmap.insert(vt(s("DJ"),s("is a student")));

  //輸出初始化以後的多重映射mulmap:

  for(p=mulmap.begin();p!=mulmap.end();++p)

  cout<<(*p).first<<(*p).second<<endl;

  //檢索並輸出Jerry鍵所對應的所有的值

  cout<<"findJerry :"<<endl;

  p=mulmap.find(s("Jerry"));

  while((*p).first=="Jerry")

  {

  cout<<(*p).first<<(*p).second<<endl;

  ++p;

  }

  cin.get();

  return 0;

  }

  在map中是不允許一個鍵對應多個值的,在multimap中,不支持operator[],也就是說不支持map中允許的下標操作。



std::map 再學習

1.         map中的元素其實就是一個pair

2.         map的鍵一般不能是指針,比如int*char*之類的,會出錯。常用的就用string了,int也行。

3.         map是個無序的容器,而vector之類是有序的。所謂有序無序是指放入的元素並不是按一定順序放進去的,而是亂序,隨機存放的(被映射後近似隨機存放)。所以遍歷的時候有些效率差別。

4.         判斷有沒有找到該鍵的內容可以這樣:

//-----------------------------------------------------------------------------------------------

std::map<std::string,Record>::const_iterator cIter;

cIter= stdfile.m_map.find(s);

if(cIter == stdfile.m_map.end())  //沒找到就是指向END

{

m_vecMoreFile.push_back(s);

}

//-----------------------------------------------------------------------------------------------

如果鍵的內容是指針的話應該用NULL指針也可以判斷了.

5.         遍歷:

//-----------------------------------------------------------------------------------------------

std::map<std::string,Record>::iteratoriter;

for(iter = m_map.begin(); iter != m_map.end(); iter++)

{

std::string s = iter->second.filename;

}

//-----------------------------------------------------------------------------------------------

由於map內容可以相當一個PAIR,那就簡單了,用iter->second就可以取得值了。

 

std::map的一些注意點

std::map是一個很常用的標準容器,採用紅黑樹或者平衡二叉樹來儲存節點內容,具有對數複雜度的插入時間和查找時間。這裏簡單說下它的一些值得注意的關注點。

1.         插入:

//-----------------------------------------------------------------------------------------------

std::map<int,std::string> str_map;

str_map.insert( std::pair<const int, std::string>(2, "bb") );     //沒有轉型操作

str_map.insert( std::pair<int, std::string>(2, "bb") );     //需要轉型成std::pair<constint, std::string>再進行插入

str_map.insert( std::make_pair(3, "cc") );          //同上,需要轉型

str_map.insert( std::map<int, std::string>::value_type ( 4 , "dd" ) );     //沒有轉型操作

//-----------------------------------------------------------------------------------------------

還有一種方法是通過索引器[]去直接插入,這種方法在下邊再討論。

2.         刪除:

一種很常見的錯誤是:

//-----------------------------------------------------------------------------------------------

for( map<int, string>::iterator it = str_map.begin(); it!=str_map.end();it++ )

{

       if ( some_condition )str_map.erase(it);

}

//-----------------------------------------------------------------------------------------------

刪除操作會使it亂掉,再使用it++就出錯了。

正確的做法是:

//-----------------------------------------------------------------------------------------------

for( map<int, string>::iterator it = str_map.begin();it!=str_map.end(); )

{

       if ( some_condition ) {

              str_map.erase(it++);

       } else {

              it++;

       }

}

//-----------------------------------------------------------------------------------------------

3.         索引:

str_map[5]= "ee";

這條語句實際上是分兩個步驟執行的:先在str_map[5]的地方構造一個空string,然後通過str_map[5]返回這個stringreference;然後調用這個空stringassignment運算符,把"ee"賦給它。因此,這樣寫要比直接insert效率低些。

索引還有一個問題是需要注意的:

//-----------------------------------------------------------------------------------------------

map<int,string> m;

cout<<m.size()<<endl;// output: 0

if( m[4] == "aa" ) some_operation();

cout<<m.size()<<endl;//output: 1

//-----------------------------------------------------------------------------------------------

這裏m[4]已經指向了一個構造好了的空string

4.         functionobject

std::mem_fun的幫助下,vector等容器可以很容易地使用find_if等泛型算法,比如:

classX {

public:

       bool condition();

};

vector<X>vx;

....

vector<X>::iteratorit = std::find_if ( vx.begin(), vx.end(), std::mem_fun(&X::condition) );

由於map::iterator指向的是std::pair,所以要使用這些算法大部分時候就只好自己手寫相應的functionobject了。

但藉助boostlambda庫的幫助,我們就可以省去自己寫function object的麻煩了:

#include<boost/lambda/bind.hpp>

#include<boost/lambda/lambda.hpp>

usingboost::lambda::bind; 

std::map<int,X> mx;

....

std::map<int,X>::iterator it = find_if ( mx.begin(), mx.end(),

       bind ( &X::condition, bind(&std::map<int,X>::value_type::second, _1) ) );

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

std mapSTL的一個關聯容器,它提供一對一(其中第一個可以稱爲關鍵字,每個關鍵字只能在map中出現一次,第二個可能稱爲該關鍵字的值)的數據處理能力,由於這個特性,它完成有可能在我們處理一對一數據的時候,在編程上提供快速通道。這裏說下std map內部數據的組織,std map內部自建一顆紅黑樹(一種非嚴格意義上的平衡二叉樹),這顆樹具有對數據自動排序的功能,所以在std map內部所有的數據都是有序的,後邊我們會見識到有序的好處。

下面舉例說明什麼是一對一的數據映射。比如一個班級中,每個學生的學號跟他的姓名就存在着一一映射的關係,這個模型用map可能輕易描述,很明顯學號用int描述,姓名用字符串描述(本篇文章中不用char *來描述字符串,而是採用STLstring來描述),下面給出map描述代碼:

Map<int, string> mapStudent;

1. map
的構造函數

map
共提供了6個構造函數,這塊涉及到內存分配器這些東西,略過不表,在下面我們將接觸到一些map的構造方法,這裏要說下的就是,我們通常用如下方法構造一個map

Map<int, string> mapStudent;

2.
數據的插入

在構造map容器後,我們就可以往裏面插入數據了。這裏講三種插入數據的方法:

第一種:用insert函數插入pair數據,下面舉例說明(以下代碼雖然是隨手寫的,應該可以在VCGCC下編譯通過,大家可以運行下看什麼效果,在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”));

上面這兩條語句執行後,map1這個關鍵字對應的值是“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;

}

}

3. map
的大小

在往map裏面插入了數據,我們怎麼知道當前已經插入了多少數據呢,可以用size函數,用法如下:

Int nSize = mapStudent.size();

4.
數據的遍歷

這裏也提供三種方法,對map進行遍歷

第一種:應用前向迭代器,上面舉例程序中到處都是了,略過不表

第二種:應用反相迭代器,下面舉例說明,要體會效果,請自個動手運行程序

#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>::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中已經插入了1234的話,如果lower_bound(2)的話,返回的2,而upper-bound2)的話,返回的就是3

Equal_range
函數返回一個pairpair裏面第一個變量是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.
數據的清空與判空

清空map中的數據可以用clear()函數,判定map中是否有數據可以用empty()函數,它返回true則說明是空map

7.
數據的刪除

這裏要用到erase函數,它有三個重載了的函數,下面在例子中詳細說明它們的用法

#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


//
用迭代器,成片的刪除

//
一下代碼把整個map清空

mapStudent.earse(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函數可以實現的功能,而STLAlgorithm也可以完成該功能,建議用map自帶函數,效率高一些。

下面說下,map在空間上的特性,否則,估計你用起來會有時候表現的比較鬱悶,由於map的每個數據對應紅黑樹上的一個節點,這個節點在不保存你的數據時,是佔用16個字節的,一個父節點指針,左右孩子指針,還有一個枚舉值(標示紅黑的,相當於平衡二叉樹中的平衡因子),我想大家應該知道,這些地方很費內存了吧,不說了……

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

std::map用法



std::map用法

  STL是標準C++系統的一組模板類,使用STL模板類最大的好處就是在各種C++編譯器上都通用。

  STL模板類中,用於線性數據存儲管理的類主要有vector, list, map等等。本文主要針對map對象,結合自己學習該對象的過程,講解一下具體用法。本人初學,水平有限,講解差錯之處,請大家多多批評指正。

   map對象所實現的功能跟MFCCMap相似,但是根據一些文章的介紹和論述,MFCCMap在個方面都與STL map有一定的差距,例如不是C++標準,不支持賦值構造,對象化概念不清晰等等。

 使用map對象首先要包括頭文件,包含語句中必須加入如下包含聲明

#include<map>

注意,STL頭文件沒有擴展名.h

包括頭文件後就可以定義和使用map對象了,map對象是模板類,需要關鍵字和存儲對象兩個模板參數,例如:

std:map<int,CString> enumMap;

這樣就定義了一個用int作爲關鍵字檢索CString條目的map對象,std表示命名空間,map對象在std名字空間中,爲了方便,在這裏我仍然使用了CString類,其實應該使用標準C++std::string類,我們對模板類進行一下類型定義,這樣用的方便,當然,不定義也可以,代碼如下:

typedefstd:map<int, CString> UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;

如此map對象就定義好了,增加,改變map中的條目非常簡單,因爲map類已經對[]操作符進行了重載,代碼如下:

enumMap[1]= "One";
enumMap[2] = "Two";
.....
enumMap[1] = "One Edit";

或者insert方法

enumMap.insert(make_pair(1,"One"));

 

返回map中目前存儲條目的總數用size()方法:

intnSize = enumMap.size();

 

查找map中是否包含某個關鍵字條目用find方法,傳入的參數是要查找的key,在我們的例子裏,是一個int數據,map中的條目數據是順序存儲的,被稱作爲一個sequence,在這裏需要提到的是begin()end()兩個成員,分別代表map對象中第一個條目和最後一個條目,這兩個數據的類型是iteratoriterator被定義爲map中條目的類型,查找是否包含某個條目的代碼如下:

intnFindKey = 2;           //要查找的Key
UDT_MAP_INT_CSTRING::iterator it;    //
定義一個條目變量(實際是指針)
it = enumMap.find(nFindKey);
if(it == enumMap.end()) {
    //
沒找到
}
else {
    //
找到
}

//find的時候注意key的數據類型,最好用CString之類的能消除數據類型差異的key,否則可能會出現強制轉換後仍找不到的情況。

需要說明的是iterator, begin(), end()STL模板類的一個通用概念,操作方法也大同小異

通過map對象的方法獲取的iterator數據類型是一個std::pair對象,包括兩個數據 iterator.first iterator.second分別代表關鍵字和存儲的數據

移除某個條目用erase()該成員方法的定義如下

iteratorerase(iterator it);
iterator erase(iterator first, iterator last);
size_type erase(const Key& key);

分析一下這三個重載方法定義,大家不用說也能看明白一點點了吧,第一個通過一個條目對象刪除,這個對象可以從find之類的方法獲得,第二個定義刪除一個範圍,需要一個起始條目和一個終止條目,第三個通過關鍵字刪除,這個與我們的想法和習慣最接近,代碼例子如下:

enumMap.erase(1);           //刪掉關鍵字“1”對應的條目
enumMap.erase(enumMap.begin());        //
刪掉第一個條目
enumMap.erase(enumMap.begin(), enumMap.begin() + 1);    //
刪掉起始的兩個條目

呵呵,增刪改查都說完了,相信讀過本文,map對象也應該會使用了,這些是我1個多星期來鑽研的結果,拿出來與大家分享。

最後,還有一個empty(),不用問,全刪的時候就不要一個一個erase了,empty()就相當於enumMap.erase(enumMap.begin(),enumMap.end());

 

map的遍歷:

#include<map>
#include<string>
#include<iostream>
using namespace std;

int main()
{
   
 map<string,int>  m;
   
 m["a"]=1;
   
 m["b"]=2;
   
 m["c"]=3;
   
 map<string,int>::iterator it;
   
 for(it=m.begin();it!=m.end();++it)
    
    cout<<"key:"<<it->first <<" value:"<<it->second<<endl;
   
 return   0;
}

 

map<string,int>::iteratorit;   定義一個迭代指針it 

it->first爲索引鍵值,it->second爲值。


 

在對象中應用時,最好在析構函數中要調用它的clear方法,

例如class a{

   map<int,int> m;

 

  ~a(){

   m.clear();

 }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章