STL2—关联容器map基础总结

  map是键-对的集合。map类型通常可以理解为关联数组:可以通过使用键作为下标来获取一个值,正如内置数组类型一样;而关联的本质在于元素的值与某个特定的键相关联,而并非通过元素在容器中的位置来获取。

一、map对象的定义

map的构造函数

map<K,V>m;

创建一个名为m空对象,其键和值的类型分别为KV

map<K,V>m(m2);

创建m2的对象副本mmm2的键与值的类型必须完全一致

map<K,V>m(b,e);

创建map类型的对象m,存储迭代器be标记的范围内所有元素的副本。

迭代器元素的类型必须能转换为pair<constK, V>


键类型的约束

    在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。默认情况下,标准库使用键类型定义的<操作符来实现键(keytype)的比较。

    对于键类型,唯一的约束就是必须支持<操作符,至于是否支持其他的关系或相等运算,则不作要求。


二、map定义的类型

由于map对象的元素是键-值对,因此map对象的value_type是存储元素的键以及值类型的pair类型,而且键为const

因此键是不能直接修改的

map<K,V>::key_type

map<K,V>::mapped_type

map<K,V>::value_type

一个pair类型:first元素具有

constmap<K,V>::key_type类型,而second元素则为map<K,V>::mapped_type类型

注意value_type类型,因此解引用得到的数据类型是一个pair类型,分别有两个公有成员

    map<string,int> word_count;
    word_count.insert(make_pair("C++ Primer",1));
    map<string,int>::iterator map_iter = word_count.begin();
    cout << map_iter -> first << " "
         << map_iter -> second << endl;
    map_iter -> first = "Effective C++";    //Error 直接修改键值是不允许的
    map_iter -> second = 3;                 //OK

    map<string,int> word_count;
    word_count.insert(make_pair("C++ Primer",1));
    map<string,int>::iterator map_iter = word_count.begin();

    map<string,int>::key_type first = map_iter -> first;
    map<string,int>::mapped_type second = map_iter -> second;

    first = "Effective C++"; //<这里的key_value的类型是string而不是const 类型,因此可以相应的修改数据

    cout << first << " "
         << second << endl;

三、给map添加元素

添加元素:

    1、可以使用insert成员实现;

    2、或者先通过下标操作符获取元素,然后给获取的元素赋值。

使用下标访问 map 与使用下标访问数组或 vector 的行为截然不同 : 用下标访问不存在的元素将导致在 map 容器中添加一个新元素 , 它的键即为该下标值。同时对相应的值有初始化

有别于vectorstring类型,map下标操作符返回的类型与对map迭代器进行解引用或的类型不同:map迭代器返回的是value_type类型的值– 包含constkey_typemapped_type类型的pair对象;而下标操作符返回一个mapped_type类型的值。

    //通常来说,下标操作符返回左值
    cout << word_count["Anna"] << endl;
    ++ word_count["Anna"];
    cout << word_count["Anna"] << endl;  //<下标访问,返回的是对应的值,如果没有这个键,那么会根据传入的参数,初始化对应的键值对

五、 map::insert 的使用

map容器中,键影响了实参的类型,vector的差别:

    a.插入单个元素的insert版本使用键-pair类型的参数。类似地,对于参数为一对迭代器的版本,迭代器必须指向键-pair类型的元素。

    b. map容器的接受单个值的insert版本的返回类型。

map容器提供的insert操作

m.insert(e)

e是一个用在m上的value_type类型的值。如果键(e.first)不在m,则插入一个值为e.second的新元素;如果该键在m中已存在,则保持m不变。该函数返回一个pair类型对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素

m.insert(b,e)

begend是标记元素范围的迭代器,其中的元素必须为m.value_type类型的键-值对。对于该范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m返回void类型

m.insert(iter,e)

e是一个用在m上的value_type类型的值。如果键(e.first)不在m,则创建新元素,以迭代器iter为起点搜索新元素存储的位置。返回一个迭代器,指向m中具有给定键的元素


    //创建一个pair对象,将之直接插入到map容器中
    word_cnt.insert(map<string,int>::value_type("Anna",1));

    word_cnt.insert(make_pair("Anna",1));

    typedef map<string,int>::value_type valType;
    word_cnt.insert(valType("Anna",2));
使用 insert 成员可以有效的避免下标操作符带来的副作用:不必要的初始化。

2、检测insert的返回值

    带有一个键-pair形参insert版本将返回一个值:包含一个迭代器和一个bool值的pair对象,其中迭代器指向map中具有相应键的元素,bool值则表示是否插入了该元素。如果该键已在容器中,则其关联的值保持不变,返回的bool值为false,如果该键并不存在于容器中,则bool值为trul。在这两种情况下,迭代器都将指向具有给定键的元素。

    //重写前面的字符统计函数
    map<string,int> word_cnt;
    string word;

    while (cin >> word)
    {
        pair<map<string,int>::iterator,bool> res = word_cnt.insert(make_pair(word,1));

        if (!res.second)
            ++ res.first -> second;
    }

六、查找并读取map中的元素

map容器提供了两个操作:countfind,用于检查某个键是否存在而不会插入该键:

不修改map对象的查询

m.count(k)

返回mk的出现次数

m.find(k)

如果m容器中存在k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端的迭代器


1、使用count检查map对象中某键是否存在

    因为map容器只允许一个键对应一个实例,所以,对于map对象,count成员的返回值只能是10

    如果返回值非0,则可以使用下标操作符来获取该键所关联的值,而不必担心这样会在map容器中插入新元素:

    int occurs = 0;
    if (word_cnt.count("Dream"))
    {
        occurs = word_cnt["Dream"];
    }
    cout << occurs << endl;
2 、读取元素而不插入元素

    int occurs = 0;
    map<string,int>::iterator iter = word_cnt.find("Dream");
    if (iter != word_cnt.end())
    {
        occurs = iter -> second;
    }
    cout << occurs << endl;

七、从map对象中删除元素

map对象中删除元素

m.erase(K)

删除m中键为K的元素。返回size_type类型的值,表示删除的元素个数

m.erase(p)

m中删除迭代器p所指向的元素。p必须指向m中确实存在的元素,而且不能等于m.end()。返回void类型

m.erase(b,e)

m中删除一段范围内的元素,该范围由迭代器对be标记。be必须标记m中的一段有效范围:be都必须指向m中的元素或最后一个元素的下一个位置。而且,be要么相等(此时删除的范围为空),要么b所指向的元素必须出现在e所指向的元素之前。返回void类型


    int remCount = 0;
    if (remCount = word_cnt.erase("Dream")) //<返回删除的个数
    {
        cout << "Have removed " << remCount << " words" << endl;
    }
    else
    {
        cout << "Not found!" << endl;
    }

八、map对象的迭代遍历

    与其他容器一样,map同样提供了beginend运算,以生成用于遍历整个容器的迭代器:

在使用迭代器遍历map 容器时,迭代器指向的元素按照键的升序排列 。 同时迭代器++也表示了计算下一个迭代器所指向的pair数据
    cout << "First:\t\tSecond:" << endl;
    typedef map<string,int>::iterator mapIter;
    for (mapIter iter = word_cnt.begin(); iter != word_cnt.end(); ++iter)
    {
        cout << iter -> first << "\t\t" << iter -> second << endl;
    }

九、“单词转换”map对象

1、问题:

给出一个string对象,把它转换为另一个string对象。本程序的输入是两个文件。第一个文件包括了若干单词对,每对的第一个单词将出现在输入的字符串中,而第二个单词则是用于输出。本质上,这个文件提供的是单词转换的集合——在遇到第一个单词时,应该将之替换为第二个单词。第二个文件则提供了需要转换的文本。

#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
void main(int argc,char**argv)
{
	map<string,string> trans_map;
	string key,value;
	if (argc != 3) //<表示输入参数的个数
	{
		throw runtime_error("wrong number of arguments");
	}
	ifstream map_file;
	map_file.open(argv[1]);
	while (map_file>>key>>value)
	{
		trans_map.insert(make_pair(key,value));  //<初始化转换文本
	}

	ifstream input;
	input.open(argv[2]);
	string line;
	while (getline(input,line)) //,从输入文档中获取一行数据
	{
		istringstream stream(line);
		string word;
		while (stream >> word)  //<将每一行的单词提取出来
		{
			map<string,string>::const_iterator map_it = trans_map.find(word); //<查找操作
			if (map_it != trans_map.end())
			{
				word = map_it->second;
			}
			cout << word << " ";
		}
		cout << endl;
	}
	return;
}
补充一下istringstream对象串 ,然后以空格为分隔符把该行分隔开来。
#include<iostream>
#include<sstream>
using namespace std;
int main()
{
	string str, line;
	while(getline(cin, line))
	{
		istringstream stream(line);
		while(stream>>str)
			cout<<str.c_str()<<endl;
	}	
	return 0;
}







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值