C++ 关联容器

本文详细介绍了关联容器如map、set、multimap和multiset的概念、底层实现、查询增删效率,以及它们在单词计数、字符串转换等场景的应用。同时涵盖了pair类型和无序容器(unordered_map, unordered_set)的使用和特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

关联容器map和set

最简单的散列表:数组,arr[key] = value

按关键字有序保存元素底层实现查询效率增删效率
map关联数组:保存关键字-值对红黑数O(log n)O(log n)
set关键字即值,即只保存关键字的容器红黑数O(log n)O(log n)
multimap关键字可重复出现的map红黑数O(log n)O(log n)
multiset关键字可重复出现的set红黑数O(log n)O(log n)
按关键字无序保存元素
unordered_map用哈希函数组织的map哈希表O(1)O(1)
unordered_set用哈希函数组织的set哈希表O(1)O(1)
unordered_multimap哈希组织的map:关键字可以重复出现
unordered_multiset哈希组织的set:关键字可重复出现

一、使用

一个值是否存在用set

//单词计数
//       key type,value type
std::map<string, size_t>  word_count;
string word;
while (cin >> word) ++word_count[word]; //若word不在关键字中,自动创建关键字,其值为0
for (const auto &w : word_count)
	cout << w.first << " occurs " << w.second
	     << ( (w.second>1)?" times ":" time " ) << endl;

//使用set
map<string, size_t> word_count;
set<setstring> exclude = {"The", "But"};
string word;
while (cin >> word)
// 若word在exclude中find返回指向该元素的迭代器,否则返回尾后迭代器
	if (exclude.find(word) == exclude.end())
		++ word_count[word];

看一个例子:

bool my_tolower(string &wd){
    for (auto it = wd.begin(); it != wd.end(); ++it)
        *it = std::tolower(*it); 
    return true;
}
int main(){
    vector<string> lst1 ={"AVC", "sIdf"},lst2;
    std::copy_if(lst1.begin(), lst1.end(), 
    //泛型算法向谓词传递的是 解引用的迭代器,即引用类型,指向lst1的元素
    //变为小写后,根据谓词返回结果决定是否将该元素 拷贝 到迭代器所指的位置
            std::inserter(lst2, lst2.begin()), my_tolower/*通过该谓词将单词变为小写*/ );
    for (auto c:lst1) cout << c << " "; cout << endl;   //avc sidf
    for (auto c:lst2) cout << c << " "; cout << endl;   //avc sidf
    for (auto it = lst2.begin(); it != lst2.end(); ++it){
        *it = "aa";
    }
    for (auto c:lst1) cout << c << " "; cout << endl;  //avc sidf
    for (auto c:lst2) cout << c << " "; cout << endl;  //aa aa
return 0;}

二、关联容器概述

关联容器的迭代器都是双向的

map<string, size_t> wd_count; //空容器
//列表初始化
set<string> exlude = {"a", "asdf"};
map<string, string> authors = {{key:value}, {key2:value2}};
vector<int> ivec = {1,1,2,2};
set<int> iset(ivec.cbegin(), ivec.end());
multiset<int> miset(ivec.cbegin(), ivec.cend());

要求:
有序容器要求其key必须定义比较的方法,默认用 <

bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs){
	return lhs.isbn() < rhs.isbn();
}
std::multiset<Sales_data, decltype(compareIsbn)*> bookstore(compareIsbn);
std::multiset<Sales_data, bool(*)(const Sales_data &,const Sales_data &)> 
			  bookstore(compareIsbn);

在这里插入图片描述

pair类型

标准库类型pair定义在头文件 utility

pair<T1, T2> p;
pair<T1, T2> p(v1, v2);
pair<T1, T2> p={v1, v2};
std::make_pair(v1, v2);  /返回一个用v1, v2初始化的pair,pair的类型从v1和v2的类型推断出来
p.first
p.second
p1 relop p2    关系运算符(<<=>>=)

pair<string, int> process(vector<string> &v){b
	if (!v.empty())
		return {v.back(), v.back().size()}; //列表初始化
	else
		return pair<string, int> () ;       //隐式构造返回值
}

关联容器操作

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

在这里插入图片描述
在这里插入图片描述
一个map的value_type是一个pair, 可以改变pair的值,但是不能改变关键字成员的值
set的迭代器是 const 的

auto map_it = wd_count.cbegin();
while (map_it != wd_count.cend()){
	map_it -> first;
	map_it -> second;
	++ map_it;
}

关联容器的关键子是 const 的意味着

vector<int> ivec = {2,4,6,8,2,4,6,8};
set<int> set2;
set2.insert(ivec.cbegin(), ivec.ceng());
set2.insert({1,3,5,7,9});

wd_count.insert({word, 1});
.insert(make_pair(word, 1));
.insert(pair<string, size_t>(word, 1) );
.insert(map<string, size_t>::value_type(word, 1));

在这里插入图片描述

map<string, size_t> word_count;
string word;
while (cin >> word){
	auto res = word_count.insert({word, 1});
	if (!res.second)
		++  res.first -> second ;
}

multimap<string, string> authors;
authors.insert( {"A", "lele"} );
authors.insert( {"A", "haha"} );

c.erase(k);    //从c中删除每个关键字为k的元素。返回
c.erase(p);	   //删除迭代器p指定的元素,p必须指向一个真实的元素不能等于c.end()。
			   //返回一个指向p之后元素的迭代器,若p指向c中的尾元素,则返回c.end()
c.erase(b, e); //删除[b,e)范围内的元素

map下标

set 不支持下标

map<string, size_t> word_count;
word_count["Anna"] = 1;

c