关联容器

关联容器支持通过键来高效地查找和读取元素。两个基本的关联容器类型是map和set。map的元素以键-值对的形式组织:键用作元素在map的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。set和map类型的对象不允许为同一个键添加第二个元素。如果一个键必须对应多个实例,则需使用multimap或mutiset类型,这两种类型允许多个元素拥有相同的键。

pair类型:在头文件utility中定义。

pair的创建和使用:

#include<utility>
pair
<string,int> author("Peter",30);
cout
<<author.first<<"/t"<<author.second<<endl;//可以直接访问数据成员
//使用typedef进行简化
typedef pair<string,string> Student;
Student s1,s2(
"aaa","bbb");
s1.first
="ccc";
s1.second
="ddd";
//使用make_pair函数生成一个新的pair对象
string first="eee",second="fff";
Student s3
=make_pair(first,second);

map类型:map是键-值对的集合。

map<K,V>::key_type 在map中用做索引的键的类型

map<K,V>::mapped_type 在map中用作关联的值的类型

map<K,V>::value_type 一个pair类型

map迭代器进行解引用将产生pair类型的对象:

map<string,int>::iterator map_it = word_count.begin();
cout
<<map_it->first<<" "<<map_it->second<<endl;

使用下标访问map对象:

添加键-值对,有两种实现方法。可以用insert成员实现,或者,先用下标操作符获取元素,然后给获取的元素赋值。

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

方法一:

map<string,int> word_count;
word_count[
"Peter"]=10;//相当于增加一个键值对
//创建一个map对象,用来记录每个单词出现的次数,十分简洁。
map<string,int> word_count;
string word;
while(cin>>word)
{
++word_count[word];
}

方法二:使用insert:

map<string,int> word_count;
word_count.insert(map
<string,int>::value_type("aaa",1));
//用insert方法重写单词统计程序
map<string,int> word_count;
string word;
while(cin>>word)
{
pair
<map<string,int>::iterator,bool> ret=word_count.insert(make_pair<string,int>(word,1));
if(!ret.second)//如果没插入成功,证明原来已经存在键值,将统计值+1
{
++ret.first->second;// first是一个迭代器,指向插入的键
}
}

查找并读取map中的元素:

 用下标操作符,是一种比较简单的方法,但是该方法有副作用,就是当该键不在map容器中,那么下标操作会插入一个具有该键的新元素。

map容器提供了两种操作:count和find

m.count(k) 返回m中k的出现次数,对于map对象只能是1或0,而对于mutimap容器,则可能会出现更多的值。

m.find(k) 返回按k索引返回的迭代器

count方法用于在map中查找指定键是否存在的问题,而find方法适合用于解决在map容器中查找指定键对应的元素的问题。

//读取元素而又不插入新元素
int occurs;
map
<string,int>::iterator it= word_count.find("foobar");//不存在,则返回end迭代器
if(it!=word_count.end())//可能找不到
{
occurs
=it.second;
}

从map对象中删除元素

m.erase(k) 删除m中键为k的元素。返回值为被删除元素的个数,对于map容器而言,其值必然是0或1。

m.erase(p) 从m中删除迭代器p所指向的元素。返回值为void类型。

m.erase(b,e) 从m中删除一段由一对迭代器范围的元素。返回值为void类型。

map对象的迭代遍历:

map<string,int> word_count;
word_count[
"aaa"]=1;
word_count[
"bbb"]=2;
word_count[
"ccc"]=3;
map
<string,int>::const_iterator iter = word_count.begin();
while(iter!=word_count.end())
{
cout
<<iter->second<<endl;
iter
++;
}

set类型:

map容器是键-值对的集合,而set容器只是单纯的键的集合。当只想知道一个值是否存在时,使用set容器是最合适的。

在set中添加元素:

set<int> set1;
pair
<set<int>::iterator,bool> p=set1.insert(1);//返回pair类型对象,包含一个迭代器和一个布尔值
set1.insert(2);
int arr[]={1,2,3};
set<int> set2;
set2.insert(arr,arr
+3);//返回void类型

从set中获取元素:与map方法使用类似,使用find和count函数。

multimap和multiset类型:

  map和set容器中,一个键只能对应一个实例。而multimap和multiset类型则允许一个键对应多个实例。其支持的操作分别于map和set的操作相同,只有一个例外:multiply不支持下标运算。

C++中的关联容器是一类用于存储和管理键值对(Key-Value Pairs)的数据结构,它们提供了高效的查找、插入和删除操作。关联容器基于二叉搜索树或哈希表实现,因此在查找时具有对数时间复杂度(如`map`、`set`)或常数时间复杂度(如`unordered_map`、`unordered_set`)。 ### 关联容器的类型 C++标准库提供了以下主要的关联容器: 1. **`set`** - 存储唯一的键(key),键值本身即为元素。 - 内部结构基于红黑树,键默认按升序排列。 - 键是常量(`const`),不可修改,只能删除后重新插入。 - 示例: ```cpp std::set<int> s; s.insert(10); s.insert(20); ``` 2. **`multiset`** - 与`set`类似,但允许重复键值。 - 示例: ```cpp std::multiset<int> ms; ms.insert(10); ms.insert(10); // 允许重复插入 ``` 3. **`map`** - 存储键值对(`pair<const Key, T>`),键唯一。 - 值通过键进行快速查找。 - 键是常量,但值可修改。 - 示例: ```cpp std::map<std::string, int> m; m["apple"] = 5; m.insert(std::make_pair("banana", 3)); ``` 4. **`multimap`** - 与`map`类似,但允许重复键。 - 示例: ```cpp std::multimap<int, std::string> mm; mm.insert({1, "one"}); mm.insert({1, "uno"}); // 允许重复键 ``` 5. **`unordered_set`** 和 **`unordered_multiset`** - 使用哈希表实现,不保证元素顺序。 - 插入和查找操作平均为常数时间复杂度。 - `unordered_set`不允许重复键,`unordered_multiset`允许。 6. **`unordered_map`** 和 **`unordered_multimap`** - 类似于`map`和`multimap`,但基于哈希表实现。 - 示例: ```cpp std::unordered_map<std::string, int> um; um["apple"] = 5; ``` ### 关联容器的基本操作 - **插入元素** 使用`insert()`方法插入元素,对于`map`也可以使用`operator[]`直接赋值[^3]。 ```cpp std::map<int, std::string> m; m.insert(std::make_pair(1, "one")); m[2] = "two"; // 更简洁的方式 ``` - **查找元素** 使用`find()`方法查找指定键,返回迭代器。 ```cpp auto it = m.find(2); if (it != m.end()) { std::cout << it->second << std::endl; // 输出 "two" } ``` - **删除元素** 使用`erase()`方法删除指定键或迭代器位置的元素。 ```cpp m.erase(2); // 删除键为2的元素 ``` - **遍历元素** 使用迭代器遍历容器,注意关联容器的迭代器是按关键字升序排列的[^2]。 ```cpp for (const auto& kv : m) { std::cout << kv.first << ": " << kv.second << std::endl; } ``` ### 关联容器的特性 - **键的不可变性** 在`map`、`set`等容器中,键是`const`类型,不能被修改,只能通过删除后重新插入来更新键值。 - **排序行为** `map`、`set`等容器默认使用`<`运算符进行排序,可以通过自定义比较器来改变排序规则。 - **效率** - `set`、`map`等基于红黑树实现,查找、插入、删除操作的时间复杂度为`O(log n)`。 - `unordered_set`、`unordered_map`基于哈希表实现,平均时间复杂度为`O(1)`。 ### 示例代码:使用`map`存储和查找数据 ```cpp #include <iostream> #include <map> #include <string> int main() { std::map<std::string, int> word_count; // 插入数据 word_count["apple"] = 3; word_count["banana"] = 2; // 查找数据 auto it = word_count.find("apple"); if (it != word_count.end()) { std::cout << "apple count: " << it->second << std::endl; } // 遍历数据 for (const auto& pair : word_count) { std::cout << pair.first << ": " << pair.second << std::endl; } return 0; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值