【C++】STL:map例項分析
【1】map容器
map 是關聯容器。容器中的每一個元素都是由一個鍵值和一個數據值組成的。
set 是一個集合它以其元素作為鍵值(同一個鍵值只能出現一次),且預設以升序排列。
list 是一個順序容器。
【2】map容器使用方法以及例項
(1)定義、插入資料方法例項
// map容器定義、插入資料方式程式碼 #include<map> #include<string> #include<iostream> using namespace std; // 列印map容器資料 void print(map<int, string>& mapStu, int nValue) { cout << "mapStu" << nValue << "資料資訊:" << endl; cout << "size: " << mapStu.size() << endl; map<int, string>::iterator iter = mapStu.begin(); for (; iter != mapStu.end(); ++iter) { cout << "key: " << iter->first << " value: " << iter->second << endl; } cout << endl; } int main() { // 第一種定義map的方法 map<int, string> mapStu1; // 第二種定義map的方法 typedef map<int, string> mapType; mapType mapStu2, mapStu3, mapStu4; // 第一種插入資料方法:用insert函式插入value_type資料 mapStu1.insert(map<int, string>::value_type(1, "Qin")); mapStu1.insert(map<int, string>::value_type(2, "Sun")); mapStu1.insert(map<int, string>::value_type(3, "Wang")); mapStu1.insert(map<int, string>::value_type(2, "Zhao")); print(mapStu1, 1); // 第二種插入資料方法:用insert函式插入pair資料 mapStu2.insert(pair<int, string>(1, "Qin")); mapStu2.insert(pair<int, string>(2, "Sun")); mapStu2.insert(pair<int, string>(3, "Wang")); mapStu2.insert(pair<int, string>(2, "Zhao")); print(mapStu2, 2); // 第三種插入資料方法:用insert函式插入make_pair資料 mapStu3.insert(make_pair<int, string>(1, "Qin")); mapStu3.insert(make_pair<int, string>(2, "Sun")); mapStu3.insert(make_pair<int, string>(3, "Wang")); mapStu3.insert(make_pair<int, string>(2, "Zhao")); print(mapStu3, 3); // 第四種插入資料方法:陣列插入法 mapStu4[1] = "Qin"; mapStu4[2] = "Sun"; mapStu4[3] = "Wang"; mapStu4[2] = "Zhao"; print(mapStu4, 4); pair<map<int, string>::iterator, bool> iter_pair; iter_pair = mapStu1.insert(map<int, string>::value_type(3, "Li")); //mapStu1.insert(map<int, string>::value_type(3, "Li"))返回的型別為‘std::pair<std::_Rb_tree_iterator<std::pair<const int, std::__cxx11::basic_string<char> > >, bool>’ cout << "插入成功與否:" << iter_pair.second << endl; //system("pause"); return 0; } // run out /* mapStu1資料資訊: size: 3 key: 1 value: Qin key: 2 value: Sun key: 3 value: Wang mapStu2資料資訊: size: 3 key: 1 value: Qin key: 2 value: Sun key: 3 value: Wang mapStu3資料資訊: size: 3 key: 1 value: Qin key: 2 value: Sun key: 3 value: Wang mapStu4資料資訊: size: 3 key: 1 value: Qin key: 2 value: Zhao key: 3 value: Wang 插入成功與否:0 請按任意鍵繼續. . . */
分析總結:
以上四種用法,雖然都可以實現資料的插入,但是它們是有區別的。
當然,第一、二、三種在效果上是完全一樣的,用insert函式插入資料,在資料的插入過程中涉及到集合的唯一性這個概念:
即當map中有這個關鍵字時,insert操作再插入資料是不會成功的。
但是,用陣列(第四種)方式就不同了,它可以覆蓋以前該關鍵字對應的值,用程式說明如下:
mapStu1.insert(map<int, string>::value_type(2, "Sun"));
mapStu1.insert(map<int, string>::value_type(2, "Zhao"));
上面這兩條語句執行後,mapStu1中2這個關鍵字對應的值是“Sun”,第二條語句並沒有生效。
那麼,這就涉及到我們怎麼知道insert語句是否插入成功的問題?可以用pair來獲得是否插入成功,程式如下:
pair<map<int, string>::iterator, bool> iter_pair; iter_pair = mapStu1.insert(map<int, string>::value_type(3, "Li")); //mapStu1.insert(map<int, string>::value_type(3, "Li"))返回的型別為‘std::pair<std::_Rb_tree_iterator<std::pair<const int, std::__cxx11::basic_string<char> > >, bool>’
我們通過pair的第二個變數來判斷是否插入成功,它的第一個變數返回的是一個map的迭代器,
如果插入成功的話迭代器的變數iter_pair.second應該是true,否則為false。
(2)遍歷map容器的三種方式
程式程式碼如下:
#include <map>
#include <iostream>
#include <string>
using namespace std;
// 第一種方式
void print1(map<int, string>& mapStu)
{
cout << "第一種遍歷方式:" << endl;
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
map<int, string>::iterator iter = mapStu.begin();
for (; iter != mapStu.end(); ++iter)
{
cout << "key: " << iter->first << " value: " << iter->second << endl;
}
cout << endl;
}
// 第二種方式
void print2(map<int, string>& mapStu)
{
cout << "第二種遍歷方式:" << endl;
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
map<int, string>::reverse_iterator iter = mapStu.rbegin();
for (; iter != mapStu.rend(); ++iter)
{
cout << "key: " << iter->first << " value: " << iter->second << endl;
}
cout << endl;
}
// 第三種方式
void print3(map<int, string>& mapStu)
{
cout << "第三種遍歷方式:" << endl;
int nSize = mapStu.size();
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
for(int nIndex = 1; nIndex < nSize + 1; ++nIndex)
{
cout << "<" << nIndex << " :: " << mapStu[nIndex] << ">" << endl;
}
}
int main()
{
typedef map<int, string> mapType;
mapType mapStu;
// 用insert函式插入value_type資料
mapStu.insert(map<int, string>::value_type(1, "Qin"));
mapStu.insert(map<int, string>::value_type(2, "Sun"));
mapStu.insert(map<int, string>::value_type(3, "Wang"));
mapStu.insert(map<int, string>::value_type(4, "Zhao"));
print1(mapStu); // 第一種方式
print2(mapStu); // 第二種方式
print3(mapStu); // 第三種方式
//system("pause");
return 0;
}
// run out:
/*
第一種遍歷方式:
size: 4
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Zhao
第二種遍歷方式:
size: 4
key: 4 value: Zhao
key: 3 value: Wang
key: 2 value: Sun
key: 1 value: Qin
第三種遍歷方式:
size: 4
<1 :: Qin>
<2 :: Sun>
<3 :: Wang>
<4 :: Zhao>
請按任意鍵繼續. . .
*/
(3)查詢資料的三種方式
都是已知鍵值查詢對應的value。應用例項程式碼如下:
// 三種查詢資料的方式
#include <map>
#include <iostream>
#include <string>
using namespace std;
// 第一種方式
void print1(map<int, string>& mapStu)
{
cout << "遍歷容器資料:" << endl;
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
map<int, string>::iterator iter = mapStu.begin();
for (; iter != mapStu.end(); ++iter)
{
cout << "key: " << iter->first << " value: " << iter->second << endl;
}
}
int main()
{
typedef map<int, string> mapType;
mapType mapStu;
// 用insert函式插入value_type資料
mapStu.insert(map<int, string>::value_type(1, "Qin"));
mapStu.insert(map<int, string>::value_type(2, "Sun"));
mapStu.insert(map<int, string>::value_type(3, "Wang"));
mapStu.insert(map<int, string>::value_type(4, "Zhao"));
// 第一種查詢資料方式
// count函式求的是關鍵字key的個數。key是不能重複的,所以返回只有0和1兩種結果。
cout << "查詢關鍵字3的結果 : " << mapStu.count(1) << endl;
cout << "查詢關鍵字5的結果: " << mapStu.count(5) << endl;
// 第二種查詢資料方式
map<int, string>::iterator iter;
iter = mapStu.find(1);
if (iter != mapStu.end())
{
cout << "Find, the value is " << iter->second << endl;
}
else
{
cout << "Do not Find !" << endl;
}
// 第三種查詢資料方式
print1(mapStu);
iter = mapStu.lower_bound(2);
{
cout << "lower_bound(2) :: (不小於2) " << iter->second << endl;
}
iter = mapStu.lower_bound(3);
{
cout << "lower_bound(3) :: (不小於3) " << iter->second << endl;
}
iter = mapStu.upper_bound(2);
{
cout << "upper_bound(2) :: (大於2) " << iter->second << endl;
}
iter = mapStu.upper_bound(3);
{
cout << "upper_bound(3) :: (大於3) " << iter->second << endl;
}
pair<map<int, string>::iterator, map<int, string>::iterator> mapPair;
mapPair = mapStu.equal_range(2);
if (mapPair.first == mapPair.second)
{
cout << "equal_range(2) :: Do not Find!" << endl;
}
else
{
cout << "equal_range(2) :: Find!" << endl;
}
mapPair = mapStu.equal_range(5);
if (mapPair.first == mapPair.second)
{
cout << "equal_range(5) :: Do not Find!" << endl;
}
else
{
cout << "equal_range(5) :: Find!" << endl;
}
//system("pause");
return 0;
}
// run out:
/*
查詢關鍵字3的結果 : 1
查詢關鍵字5的結果: 0
Find, the value is Qin
遍歷容器資料:
size: 4
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Zhao
lower_bound(2) :: (不小於2) Sun
lower_bound(3) :: (不小於3) Wang
upper_bound(2) :: (大於2) Wang
upper_bound(3) :: (大於3) Zhao
equal_range(2) :: Find!
equal_range(5) :: Do not Find!
請按任意鍵繼續. . .
*/
注意:
lower_bound(x)不是下界,而是大於等於x的最小值。
upper_bound(x) 大於x的最小值。
equal_range如果不明白可以檢視部落格https://blog.csdn.net/u013066730/article/details/84138564。
(4)查詢、修改、刪除、大小、比較、清空、判空等等方法。
應用例項程式碼如下:
#include <map>
#include <string>
#include <iostream>
using namespace std;
// 列印map容器資料
void print(map<int, string>& mapStu)
{
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
map<int, string>::iterator iter = mapStu.begin();
for (; iter != mapStu.end(); ++iter)
{
cout << "key: " << iter->first << " value: " << iter->second << endl;
}
cout << endl;
}
int main()
{
typedef map<int, string> mapType;
mapType mapStu1;
// 用insert函式插入value_type資料
mapStu1.insert(map<int, string>::value_type(1, "Qin"));
mapStu1.insert(map<int, string>::value_type(2, "Sun"));
mapStu1.insert(map<int, string>::value_type(3, "Wang"));
mapStu1.insert(map<int, string>::value_type(2, "Zhao"));
print(mapStu1);
// 查詢資料的兩種方式:
// 方式1:
string str2 = mapStu1[2];
cout << str2 << endl;
// 方式2:
mapType::iterator my_Iter;
my_Iter = mapStu1.find(3);
string str3 = my_Iter->second;
cout << str3 << endl;
// 修改資料的兩種方式:
// 方式1:
mapStu1[2] = "Ma";
// 方式2:
my_Iter->second = "Yuan";
print(mapStu1);
// size 函式 和 empty函式
cout << "size() :: " << mapStu1.size() << endl;
cout << "empty() :: " << mapStu1.empty() << endl;
mapStu1.clear();
cout << "size() :: " << mapStu1.size() << endl;
cout << "empty() :: " << mapStu1.empty() << endl;
// 比較 ==、>=、<=、!=
mapType mapStu2;
cout << "mapStu1 == mapStu2 :: " << (mapStu1 == mapStu2) << endl;
cout << "mapStu1 >= mapStu2 :: " << (mapStu1 >= mapStu2) << endl;
cout << "mapStu1 <= mapStu2 :: " << (mapStu1 <= mapStu2) << endl;
cout << "mapStu1 != mapStu2 :: " << (mapStu1 != mapStu2) << endl;
mapStu1.insert(map<int, string>::value_type(1, "Qin"));
mapStu1.insert(map<int, string>::value_type(2, "Sun"));
mapStu1.insert(map<int, string>::value_type(3, "Wang"));
mapStu1.insert(map<int, string>::value_type(4, "Qiang"));
mapStu1.insert(map<int, string>::value_type(5, "Huang"));
mapStu1.insert(map<int, string>::value_type(6, "Li"));
mapStu1.insert(map<int, string>::value_type(7, "Hou"));
mapStu1.insert(map<int, string>::value_type(8, "Lin"));
mapStu1.insert(map<int, string>::value_type(9, "Li"));
// 刪除操作
cout << "刪除前列印資料資訊:" << endl;
print(mapStu1);
mapType::iterator iter;
// 第一種刪除(程式碼1)
for (iter = mapStu1.begin(); iter != mapStu1.end();)
{
if (5 == iter->first)
{
mapStu1.erase(iter++);
}
else
{
++iter;
}
}
// 第一種刪除(程式碼2)(注意程式碼層面的差異)
for (iter = mapStu1.begin(); iter != mapStu1.end();)
{
if ("Li" == iter->second)
{
mapStu1.erase(iter++);
}
else
{
++iter;
}
}
cout << "刪除關鍵字5 以及 值“Li”後: " << endl;
print(mapStu1);
// 第一種刪除(程式碼3)(注意程式碼層面的差異)
my_Iter = mapStu1.find(2);
mapStu1.erase(my_Iter);
cout << "刪除關鍵字2後: " << endl;
print(mapStu1);
// 第二種刪除(直接刪除關鍵字)
int nResult = mapStu1.erase(3); // 如果刪除了會返回1,否則返回0
cout << nResult << endl;
cout << "刪除關鍵字3後: " << endl;
print(mapStu1);
// 第三種刪除(用迭代器,成片的刪除)
mapStu1.erase(++mapStu1.begin(), mapStu1.end());
cout << "剩第一位,其它全部刪除後: " << endl;
print(mapStu1);
return 0;
}
// run out:
/*
size: 3
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
Sun
Wang
size: 3
key: 1 value: Qin
key: 2 value: Ma
key: 3 value: Yuan
size() :: 3
empty() :: 0
size() :: 0
empty() :: 1
mapStu1 == mapStu2 :: 1
mapStu1 >= mapStu2 :: 1
mapStu1 <= mapStu2 :: 1
mapStu1 != mapStu2 :: 0
刪除前列印資料資訊:
size: 9
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Qiang
key: 5 value: Huang
key: 6 value: Li
key: 7 value: Hou
key: 8 value: Lin
key: 9 value: Li
刪除關鍵字5 以及 值“Li”後:
size: 6
key: 1 value: Qin
key: 2 value: Sun
key: 3 value: Wang
key: 4 value: Qiang
key: 7 value: Hou
key: 8 value: Lin
刪除關鍵字2後:
size: 5
key: 1 value: Qin
key: 3 value: Wang
key: 4 value: Qiang
key: 7 value: Hou
key: 8 value: Lin
1
刪除關鍵字3後:
size: 4
key: 1 value: Qin
key: 4 value: Qiang
key: 7 value: Hou
key: 8 value: Lin
剩第一位,其它全部刪除後:
size: 1
key: 1 value: Qin
請按任意鍵繼續. . .
*/
(5)map 容器排序問題
請看下面一段程式碼:
#include <map>
#include <string>
#include "iostream"
using namespace std;
typedef struct tagStudentInfo
{
int nID;
string strName;
} StudentInfo, *PStudentInfo; // 學生資訊
void main()
{
// 用學生資訊對映分數
map<StudentInfo, int> 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));
}
注意:以上程式編譯無法通過!
由編譯器錯誤提示分析:排序問題!STL中預設是採用小於號來排序的,當關鍵字是一個結構體時,涉及到排序就會出現問題。
因為它沒有小於號操作,insert等函式在編譯的時候過不去,下面給出兩個方法解決這個問題:
1、解決方法1,過載運算子。
// 解決方法1
#include <map>
#include <string>
#include "iostream"
using namespace std;
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; // 學生資訊
void print(map<StudentInfo, int>& mapStu)
{
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
map<StudentInfo, int>::iterator iter = mapStu.begin();
for (; iter != mapStu.end(); ++iter)
{
cout << "key: " << iter->first.nID << " value: " << iter->second << endl;
}
cout << endl;
}
int main()
{
// 用學生資訊對映分數
map<StudentInfo, int> 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));
print(mapStudent);
return 0;
}
/*
//run out:
size:2
key:1 value:90
key:2 value:80
*/
2、解決方法2,仿函式。
// 解決方法2
#include <map>
#include <string>
#include "iostream"
using namespace std;
typedef struct tagStudentInfo
{
int nID;
string strName;
} StudentInfo, *PStudentInfo; // 學生資訊
class 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;
}
};
void print(map<StudentInfo, int, sort>& mapStu)
{
cout << "size: " << mapStu.size() << endl;
// 迭代map容器中的資料
map<StudentInfo, int>::iterator iter = mapStu.begin();
for (; iter != mapStu.end(); ++iter)
{
cout << "key: " << iter->first.nID << " value: " << iter->second << endl;
}
cout << endl;
}
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));
print(mapStudent);
return 0;
}
/*
//run out:
size:2
key:1 value:90
key:2 value:80
*/
6)待續...
【3】總結說明
(1)由於STL是一個統一的整體,map的很多用法都和STL中其它的東西結合在一起。
比如,在排序方面,這裡預設用的是小於號,即less<>,如果要從大到小排序呢,這裡涉及到的東西很多,在此無法一一加以說明。
(2)map容器內部有序,由紅黑樹保證,因此很多函式執行的時間複雜度都是log2N的,用map函式可以實現的功能,而STL Algorithm也可以完成該功能。
但是,建議用map自帶函式,效率更高一些。
(3)map在空間上的特性。
由於map的每個資料對應紅黑樹上的一個節點,這個節點在不儲存你的資料時,是佔用16個位元組:
一個父節點指標,左右兩個孩子指標,還有一個列舉值(標示紅黑的,相當於平衡二叉樹中的平衡因子)。