您的位置:首页 > 编程语言 > C语言/C++

C++ STL系列 —— map

2016-03-10 19:45 393 查看

简介:

map的特性是,所有元素会根据元素的键值进行自动排序。map所有的元素都是pair,同时拥有实值(value)和键值(key)。pair的第一元素视为键值,第二元素视为实值。map不允许两个元素拥有相同的键值。如果通俗的来说map的话,map可以想象成为一个可以自动排序二维数组,一维坐标是键值,二维坐标是实值,但是区别于数组的是map是可以随意添加生成空间对应键值和实值的。

定义:

tmplate <class Key, class T,
class Compare = less<Key>,         //缺省采用递增排序的方法
class Alloc = alloc>
class map{
public:
typedef Key key_type;           //键值类别
typedef T data_type;            //数据(实值)类型
typedef T mapped_type;
typedef pair<const Key, T> value_type;  //元素型别
typedef Compare key_compare;    //键值比较函数

class value_compare
: public binary_function<value_type, value_type, bool>{
friend class map<Key T, Compare, Alloc>;
protected:
Compare comp;
value_compare(Compare c} : comp(c) {}
public:
bool operator()(const value_type& x, const value_type& y) const{
return comp(x.first, y.first);
}
};
private:
typedef typename rep_type::iterator iterator;  //map并不像set一样将iterator定义为const_iterator,也就是说它允许用户通过迭代器修改元素实值
};

上面给出了STL中map源码的一部分,可以了解map的大致结构,特别需要说的一点时,map使用的是底层RB-tree的insert_unique()而非insert_equal(),因为map不允许相同键值的存在,multimap才允许相同键值的存在。

 

map的构造函数

map给定了如下六种模板构造函数

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) //带分配器

我们经常使用的方法如下:

map<string, int> testmap;

 

map的插入

插入有三种方式,分别是通过pair插入,insert插入value_type和数组直接输入。

数组直接输入如下:

testmap[string("firstinsert")] = 1;
testmap[string("secondeinsert")] = 2;
testmap[string("thirdinsert")] = 3;
testmap[string("fourthinsert")] = 4;

通过pair输入如下:

pair<string, int> value(string("fifthinsert"), 5);
testmap.insert(value);
//特别的,利用make_pair()直接返回pair类型也可以这样写:
testmap.insert(make_pair("sixth", 6));

通过insert插入value_type如下:

testmap.insert(map<string, int>::value_type("sixth", 6));
testmap.insert(map<string, int>::value_type("seventh", 7));
testmap.insert(map<string, int>::value_type("eighth", 8));

三种插入方法均可实现插入的功能,但是之前还是存在区别,区别在于是否使用数组来进行插入,insert成员函数源码如下:

pair<iterator, bool> insert(const value_type& x)
{   return t.insert_unique(x);  }

这说明insert直接将工作转向底层的RB-tree的insert_unique()去执行,要注意的是其返回值类型是一个pair,由一个迭代器和一个bool值组成,后者表示插入成功与否,成功的话前者即指向被插入的那个元素。假设我们已经插入pair<"firstinsert", 1>,那我们再次进行插入以后进行返回值测试如下:

pair<map<string, int>::iterator, bool> h;
cout << &h.first << endl;                                   //0x28fe34
h = testmap.insert(pair<string, int>("firstinsert", 1));
cout << &h.first << " " << h.second << endl;                //0x28fe34 0

显然,插入失败了,迭代器没有移动,代表插入成功与否的bool型参数也是false。但是倘若我们使用数组直接插入,我们简单做测试:

testmap[string("firstinsert")] = 100;
cout << testmap[string("firstinsert")] << endl;  //100

经过上面的例子,我们发现,原本存在的键值对应的实值被覆盖了。所以数组插入会导致覆盖,这一点需要注意。

map的其他操作

删除与查找操作:

删除使用自带的erase成员函数,查找使用自带的find函数。

testmap.erase("firstinsert");
if(testmap.find("firstinsert") != testmap.end()){
cout << testmap["firstinsert"] << endl;
}
else {
cout << "delete yet"  << endl;                    //delete yet
}

清空操作,使用自带的成员函数clear

testmap.clear();
cout << testmap.size() << endl;                      //0

排序操作,map自带的排序是从小到大排序,如果要是map中存储结构体的话,就不能单纯的使用小于号来完成排序,而排序最简单的方法就是重载小于号。我们来简单举个例子。

struct node {
int x;
int y;
bool operator < (node const & A) const {
if(x == A.x){
return y < A.y;
}
else
return x < A.x;
}
}test;

map<node, int> testmap;

int main(void){
freopen("out.txt", "w", stdout);
node x = {2 ,3};
testmap.insert(make_pair(x, 1));
x = {1, 4};
testmap.insert(make_pair(x, 2));
x = {1, 2};
testmap.insert(make_pair(x, 3));
map<node, int>::iterator it = testmap.begin();
for(; it != testmap.end(); it ++){
cout << it -> first.x << " " << it -> first.y << " " << it -> second << endl;
}

return 0;
}

/*
1 2 3
1 4 2
2 3 1
*/

我们来看个简单的使用map的题目

C. Watchmen

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Watchmen are in a danger and Doctor Manhattan together with his friend Daniel Dreiberg should warn them as soon as possible. There are n watchmen on a plane, the i-th watchman is located at point (xi, yi).

They need to arrange a plan, but there are some difficulties on their way. As you know, Doctor Manhattan considers the distance between watchmen i and j to be |xi - xj| + |yi - yj|. Daniel, as an ordinary person, calculates the distance using the formula

.

The success of the operation relies on the number of pairs (i, j) (1 ≤ i < j ≤ n), such that the distance between watchman i and watchmen j calculated by Doctor Manhattan is equal to the distance between them calculated by Daniel. You were asked to compute the number of such pairs.

Input
The first line of the input contains the single integer n (1 ≤ n ≤ 200 000) — the number of watchmen.

Each of the following n lines contains two integers xi and yi (|xi|, |yi| ≤ 109).

Some positions may coincide.

Output
Print the number of pairs of watchmen such that the distance between them calculated by Doctor Manhattan is equal to the distance calculated by Daniel.

Examples

input
3
1 1
7 5
1 5


output
2


input
6
0 0
0 1
0 2
-1 1
0 1
1 1


output
11


Note
In the first sample, the distance between watchman 1 and watchman 2 is equal to |1 - 7| + |1 - 5| = 10 for Doctor Manhattan and

for Daniel. For pairs (1, 1), (1, 5) and (7, 5), (1, 5) Doctor Manhattan and Daniel will calculate the same distances.

题意是两种计算操作,如果相等则答案加1,这个我们稍作计算就可以得到只有两个点的两个坐标中的一个相同才满足题意计算结果,所以我们维护两个map,分别记录x坐标y坐标的个数,然后维护一个(x,y)坐标的map每次计算加上前两个的个数减去(x,y)的个数就是所得结果。代码如下:

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

map<int, int>aa, bb;
map<pair<int, int> , int> cc;
int x, y;
int n;
int main()
{
long long ans = 0;
cin >> n;
for(int i = 0; i < n ; i ++){
scanf("%d%d", &x, &y);
ans += aa[x] + bb[y] - cc[make_pair(x, y)];
aa[x] ++;
bb[y] ++;
cc[make_pair(x, y)] ++;
}
cout << ans << endl;
return 0;
}

 

查看原文:http://chilumanxi.org/2016/03/10/c-stl%e7%b3%bb%e5%88%97-map/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: