关联容器与hash table(1)

来源:互联网 发布:装甲恶鬼村正 知乎 编辑:程序博客网 时间:2024/06/07 14:13

在leetcode中,我们已经很熟悉数组顺序容器vector。这一节,我们来看看关联容器。关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的,与之相对,顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。

先来看看关联容器的类型:

按关键字有序保存元素:
map 关联数组:保存关键字-值对
set 关键字即值,即只保存关键字的容器
multimap 关键字可重复出现的map
multiset 关键字可重复出现的set

无序集合:
unordered_map 用hash函数组织的map
unordered_set 用hash函数组织的set
unordered_multimap hash组织的map:关键字可以重复出现
unordered_multiset hash组织的set:关键字可以重复出现

map类型通常是被称为关联数组(associative array),关联数组与正常的数组类似,不同之处在于其下标不必是整数。与之相对,set就是关键字的简单集合,当只是想知道一个值是否存在时,set是最有用的。

使用map

map<string,size_t> word_count;string word;while(cin>>word)      ++word_count[word]; //相当于用make_pair()来生成pair对象for(const auto &w:word_count)    cout<<w.first<<"occurs"<<w.second<<((w.second)>1) ?" times" :"time")<<endl;       

这段程序是读取输入,报告每个单词出现多少次。用for循环遍历map,打印每个单词对应的计数器。当从map中提取一个元素时,会得到一个pair类型的对象。简单来说,pair是一个模板类型,保存两个名为first和second的公有数据成员。map所使用的pair用first成员保存关键字,用second成员保存对应的值。这个名为pair的标准库类型,它定义在头文件utility中。下面介绍map初始化的两种方法:

 map<string, int> map1;   map1[string("tttt")] = 1;    map1.insert(pair<string, int>("niubi", 3)); 

使用set
上一个例子程序的合理扩展是:忽略常见单词,如“the”,“and”,“or”等。我们可以使用set保存想忽略的单词,最对不在集合中的单词统计出现次数:

map<string,size_t> word_count;//string 到size_t的空mapset<string> exclude ={"The","But","And","Or","An","A","the","but","and","or","an","a"};string word;while(cin>>word)     if(exclude.find(word)==exclude.end())         ++word_count[word];//获取并递增word的计数器

find调用返回一个迭代器,如果给定义关键字在set中,迭代器指向该关键字。否则,find返回尾后迭代器,在此程序中,仅当word不在exclude中时我们才更新word计数器。

关联容器操作
关联容器额外的类型别名

key_type: 此容器类型的关键字类型
mapped_type: 每个关键字关联的类型:只适用于map(全部map类型)
value_type: 对于set,与key_type相同;对于map,为pair< const key_type,mapped_type >

对于set类型,key_type和value_type是一样的;set中保存的值就是关键字,在一个map中,元素是关键字-值对,即,每一个元素是一个pair对象,包含一个关键字和一个关联的值。由于我们不能改变一个元素的关键字,因此这些pair的关键字部分是const的。

set< string >: : value_type v1 //v1是一个string
set< string >: : key_type v2 //v2是一个string
map< string ,int>: :value_type v3 //v3是一个pair< const string int>
map< string ,int>: :key_type v4 //v4是一个string
map< string,int> : :mapped_typed v5; //v5是一个int

关联容器迭代器
当引用一个关联容器时,我们会得到一个类型为容器的value_type的值的引用,对map而言,value_type是一个pair类型,其first成员保存const的关键字,second成员保存值:

auto map_it=word_count.begin();//*map_it是指向一个pair<const string,size_t>cout<<map_it->first;cout<<" "<<map_it->second;map_it->first="new key";//error:第一个关键字是const的,我们不能改变++map_it->second;

set的迭代器是const的,虽然set同时定义了iterator和const_iterator类型,但两种类型都只允许只读访问set中的元素。与不能改变一个map元素的关键字一样,一个set中的关键字也是const的,可以用一个set迭代器来读取元素的值,但不能修改:

set<int> iset={0,1,2,3,4,5,6,7,8,9};set<int>::iterator set_it=set_it=iset.begin();if(set_it!=iset.end()){   *set_it=42; //error   cout<<*set_it_endl;

我们通常不对关联容器适应泛型算法。关键字是const这一特性意味着不能将关联容器传递给修改或重排容器的算法,因为这类算法需要向元素写入值,而set类型中的元素是const的,map中的元素是pair,其第一个成员是const的。

遍历关联容器
map和set类型都支持begin和end的操作。与往常一样,我们可以用这些函数获取迭代器,然后用迭代器来遍历容器:

auto map_it=word_count.cbegin();//end和cend类似,带c的返回const_iterator类型,含const属性while(map_it!=word_count.cend){      cout<<map_it->first<<"occurs "          <<map_it->second<<"times"<<endl;          ++map_it;         }
0 0
原创粉丝点击