关联容器

本文详细介绍了C++中关联容器和无序容器的概念、初始化方式、关键字类型、操作方法以及与顺序容器的区别。关联容器如map、set、multimap和multiset,它们按照关键字进行组织;而无序容器则通过哈希函数和关键字的==运算符进行组织。文章还讨论了如何在实际应用中选择合适的容器类型,并提供了实例说明。

顺序容器是按照它们在容器中的位置来顺序保存和访问的,而关联容器是按照关键字来保存和访问的。

1、初始化

关联容器分为两类:map和set.

a)、map是关键字-值对;set只有关键字。

map定义:

map<string,size_t> word_count = { {“Jon”,0},
{"Lucy",1},
{"Dicken",2} };

该定义将string映射到size_t,也就是说string是下标,size_t是值。

如:word_count[word];//返回下标为word的map容器的size_t的值。

b)、set定义:

map<string,size_t> word_count = { {“Jon”,0},
{"Lucy",1},
{"Dicken",2} };

新标准中可以列表初始化。

multimap和multiset:

关键字不唯一,即多个元素可以具有相同的关键字。

2、关键字类型

不是所有类型都可以用作关联容器的关键字。对于有序容器——map、multimap、set、multiset,关键字类型必须定义元素比较的方法(默认使用“<”关键字)。

使用自己定义的操作,在定义关联容器时需要提供比较操作类型。

如:

multiset<Sales_data, decltype(compareIsbn)*>
bookstore(compareIsbn);

其中decltype(compareIsbn)*定义了一个指向compareIsbn函数的指针类型,该函数定义了Sales_data中的元素比较的方法。函数定义如下:

bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() < rhs.isbn();
}

该函数对Sales_data中的成员函数.isbn()进行比较,返回一个布尔量表示两者的大小。

3、pair对象

map的成员是pair类对象。

pair与容器类似,是用来生成特定类型的模板。一个pair保存两个数据成员,它们类型可以不同。

如:

pair<string, size_t> word_count;//该pair保存一个string 和一个size_t

pair可以列表初始化,如:

pair<string, string> author{"James", "Joyce"};

定义了一个包含两个string的pair类对象author。

pair数据成员的获取:

pair.first;//返回pair第一个(公有)数据成员
pair.second;//返回pair第二个(公有)数据成员

4、关联容器操作

a)、对关联容器迭代器解引用,得到一个类型为容器的value_type的值的引用。

对map而言,value_type是一个pair类型,其first成员保存const的关键字,second成员保存值。

b)、和顺序容器一下,我们也可以通过迭代器遍历关联容器。

c)、增加元素:

c.insert(arge);

arge可以是对象(将此对象插入容器中)、迭代器范围(将迭代器范围内的所有元素插入容器)、迭代器和对象(将对象插入迭代器所指定的范围)。

d)、删除元素:

c.erase(arge);

arge可以为关键字(删除该关键字对应的所有对象)、迭代器(删除该迭代器指向的对象)、迭代器范围(删除迭代器范围所有元素)。

e)、下标操作:

set类型不支持下标操作。

map类型下标运算返回与下标关键字关联的值。注意,如果关键字不在map中,则会自动创建一个元素并插入到map中。

特别注意,对一个map进行下标操作时,会获得一个mapped_type对象(map类的值);但当解引用一个map迭代器时,得到一个value_type对象(pair)。

f)、访问元素

c.find(k);//返回第一个指向关键字k的迭代器

对map的下标操作可能会改变map(当下标关键字不在map中时),因此对于不想改变原有map内容的访问元素操作,我们应该使用find代替来下标操作。

c.count(k);//返回关键字等于k的元素数量
c.lower_bound(k);//返回一个迭代器,指向第一个关键字不小于k 的元素
c.upper_bound(k);//返回一个迭代器,指向第一个关键字大于k的元素

结合使用c.lower_bound(k)和c.upper_bound(k)可以获得一个迭代器范围,表示所有具有关键字k的元素范围。

c.equal_range(k);//返回一个pair,保存一对迭代器,分别指向第一个关键字不小于k 的元素和第一个关键字大于k的元素

5、无序容器

无序容器不使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。


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; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值