C++ 关联式容器:map,multimap,set,multiset

发布于:2025-05-11 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

引言

一、关联式容器概述

1.1 与序列式容器的区别

1.2 底层结构

二、set容器详解set介绍

2.1 set的特性

2.2 set的模板参数

2.3 set的常用接口

2.4 set使用示例

三、map容器详解map介绍

3.1 map的特性

3.2 map的模板参数

3.3 map的常用接口

3.4 map使用示例

四、multiset容器详解multiset介绍 ​

4.1 multiset的特性 ​

4.2 multiset的模板参数 

4.3 multiset的常用接口 

  4.4 multiset使用示例 

五、multimap容器详解multimap介绍 

​编辑5.1 multimap的特性 ​

5.2 multimap的模板参数 

5.3 multimap的常用接口 

 5.4 multimap使用示例 

六、总结


引言

在C++ 的标准模板库(STL)中,关联式容器是非常重要的一部分,它们为我们提供了高效的数据存储和检索方式。今天,我们就来深入探讨一下其中的  map  和  set  容器,看看它们是如何在实际编程中发挥作用的。

一、关联式容器概述

1.1 与序列式容器的区别

在之前的学习中,我们接触过像  vector 、 list 、 deque  这样的序列式容器,它们底层是线性序列的数据结构,存储的是数据本身。而关联式容器存储的是  <key, value>  结构的键值对,在数据检索时比序列式容器效率更高。

1.2 底层结构

关联式容器根据应用场景不同,主要有树形结构(如红黑树)和哈希结构。今天重点讨论的  map  和  set  以及它们的变体  multimap 、 multiset  底层多采用平衡搜索树(红黑树)实现,这使得容器中的元素是有序的序列。

二、set容器详解set介绍

2.1 set的特性

 set  是按照一定次序存储元素的容器,其中元素的  value  也标识它自己(即  value  就是  key  ),并且每个  value  必须是唯一的。 set  中的元素不能在容器中修改(元素总是  const  ),但可以插入或删除。其内部元素默认按照小于来比较排序。

2.2 set的模板参数

cpp

template <

    class T,

    class Compare = less<T>,

    class Allocator = allocator<T>

> class set;

-  T :存储元素的类型,实际底层存储  <value, value>  的键值对。

-  Compare :比较器类型,默认按小于比较。

-  Allocator :空间配置器,一般不用用户传递。

2.3 set的常用接口

1. 插入元素

cpp

#include <set>

#include <iostream>



int main() {

    std::set<int> s;

    std::pair<std::set<int>::iterator, bool> ret = s.insert(5);

    if (ret.second) {

        std::cout << "插入成功,元素值为:" << *ret.first << std::endl;

    } else {

        std::cout << "插入失败,元素已存在" << std::endl;

    }

    return 0;

}

1. 删除元素

cpp

#include <set>

#include <iostream>



int main() {

    std::set<int> s = {1, 2, 3, 4, 5};

    s.erase(s.find(3)); // 删除值为3的元素

    for (auto e : s) {

        std::cout << e << " ";

    }

    std::cout << std::endl;

    return 0;

}

1. 查找元素


 

cpp

#include <set>

#include <iostream>



int main() {

    std::set<int> s = {1, 2, 3, 4, 5};

    std::set<int>::iterator it = s.find(3);

    if (it != s.end()) {

        std::cout << "找到元素:" << *it << std::endl;

    } else {

        std::cout << "未找到元素" << std::endl;

    }

    return 0;

}



2.4 set使用示例

cpp

#include <set>

#include <iostream>



void TestSet() {

    int array[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 0, 1, 3, 5, 7, 9, 2, 4, 6, 8, 0};

    std::set<int> s(array, array + sizeof(array) / sizeof(array[0]));

    std::cout << "set的大小为:" << s.size() << std::endl;



    // 正向打印set中的元素

    std::cout << "正向打印set元素:";

    for (auto& e : s) {

        std::cout << e << " ";

    }

    std::cout << std::endl;



    // 使用迭代器逆向打印set中的元素

    std::cout << "逆向打印set元素:";

    for (auto it = s.rbegin(); it != s.rend(); ++it) {

        std::cout << *it << " ";

    }

    std::cout << std::endl;



    // set中值为3的元素出现了几次

    std::cout << "值为3的元素个数:" << s.count(3) << std::endl;

}



int main() {

    TestSet();

    return 0;

}

三、map容器详解map介绍

3.1 map的特性

 map  是关联容器,它按照特定的次序(按照  key  来比较)存储由键值  key  和值  value  组合而成的元素。 key  通常用于排序和唯一地标识元素, value  存储与此键值  key  关联的内容。

3.2 map的模板参数


 

cpp

template <

    class Key,

    class T,

    class Compare = less<Key>,

    class Allocator = allocator<pair<const Key, T>>

> class map;



-  Key :键值对中  key  的类型。

-  T :键值对中  value  的类型。

-  Compare :比较器类型,默认按  key  小于比较。

-  Allocator :空间配置器。

3.3 map的常用接口

1. 插入元素

cpp

#include <map>

#include <string>

#include <iostream>



int main() {

    std::map<std::string, std::string> m;

    // 方式一:用pair直接构造键值对插入

    std::pair<std::map<std::string, std::string>::iterator, bool> ret1 = m.insert(std::pair<std::string, std::string>("apple", "苹果"));

    if (ret1.second) {

        std::cout << "插入成功" << std::endl;

    } else {

        std::cout << "插入失败,元素已存在" << std::endl;

    }

    // 方式二:用make_pair函数构造键值对插入

    std::pair<std::map<std::string, std::string>::iterator, bool> ret2 = m.insert(std::make_pair("banana", "香蕉"));

    if (ret2.second) {

        std::cout << "插入成功" << std::endl;

    } else {

        std::cout << "插入失败,元素已存在" << std::endl;

    }

    // 方式三:通过operator[]插入

    m["pear"] = "梨";

    return 0;

}

1. 删除元素

cpp

#include <map>

#include <string>

#include <iostream>



int main() {

    std::map<std::string, std::string> m = {{"apple", "苹果"}, {"banana", "香蕉"}};

    m.erase("banana");

    for (const auto& e : m) {

        std::cout << e.first << " -> " << e.second << std::endl;

    }

    return 0;

}

1. 查找元素

cpp

#include <map>

#include <string>

#include <iostream>



int main() {

    std::map<std::string, std::string> m = {{"apple", "苹果"}, {"banana", "香蕉"}};

    std::map<std::string, std::string>::iterator it = m.find("apple");

    if (it != m.end()) {

        std::cout << "找到元素:" << it->first << " -> " << it->second << std::endl;

    } else {

        std::cout << "未找到元素" << std::endl;

    }

    return 0;

}

3.4 map使用示例

cpp

#include <map>

#include <string>

#include <iostream>



void TestMap() {

    std::map<std::string, std::string> m;

    // 向map中插入元素的方式

    // 将键值对<"peach","桃子">插入map中,用pair直接来构造键值对

    m.insert(std::pair<std::string, std::string>("peach", "桃子"));

    // 将键值对<"peach","桃子">插入map中,用make_pair函数来构造键值对

    m.insert(std::make_pair("banana", "香蕉"));

    // 借用operator[]向map中插入元素

    m["apple"] = "苹果";



    std::cout << "map的大小为:" << m.size() << std::endl;



    // 用迭代器去遍历map中的元素,可以得到一个按照key排序的序列

    std::cout << "遍历map元素:" << std::endl;

    for (const auto& e : m) {

        std::cout << e.first << " ---> " << e.second << std::endl;

    }



    // map中的键值对key一定是唯一的,如果key存在将插入失败

    auto ret = m.insert(std::make_pair("peach", "桃色"));

    if (ret.second) {

        std::cout << "peach,桃色不在map中,已经插入" << std::endl;

    } else {

        std::cout << "键值为peach的元素已经存在:" << ret.first->first << " ---> " << ret.first->second << " 插入失败" << std::endl;

    }



    // 删除key为"apple"的元素

    m.erase("apple");

    if (1 == m.count("apple")) {

        std::cout << "apple还在" << std::endl;

    } else {

        std::cout << "apple被吃了" << std::endl;

    }

}



int main() {

    TestMap();

    return 0;

}

四、multiset容器详解multiset介绍
 

4.1 multiset的特性
 


 multiset  是按照特定顺序存储元素的容器,其中元素是可以重复的。元素的  value  也会标识它(因为  multiset  中本身存储的就是  <value, value>  组成的键值对),元素的值不能在容器中进行修改(元素总是  const  ),但可以从容器中插入或删除。其内部元素默认按照小于来比较排序。
 


4.2 multiset的模板参数
 

cpp
  
template <
    class T,
    class Compare = less<T>,
    class Allocator = allocator<T>
> class multiset;


 
 
与  set  的模板参数类似, T  为存储元素的类型, Compare  是比较器, Allocator  是空间配置器 。
 


4.3 multiset的常用接口
 


1. 插入元素
 

cpp
  
#include <multiset>
#include <iostream>

int main() {
    std::multiset<int> ms;
    ms.insert(3);
    ms.insert(3);
    ms.insert(5);
    for (auto e : ms) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
    return 0;
}


 
 
1. 删除元素
 

cpp
  
#include <multiset>
#include <iostream>

int main() {
    std::multiset<int> ms = {1, 3, 3, 5};
    ms.erase(ms.find(3)); // 删除一个值为3的元素
    for (auto e : ms) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
    return 0;
}


 
 
4.4 multiset使用示例
 

cpp
  
#include <set>
#include <iostream>

void TestMultiset() {
    int array[] = {2, 1, 3, 9, 6, 0, 5, 8, 4, 7};
    std::multiset<int> ms(array, array + sizeof(array) / sizeof(array[0]));
    for (auto& e : ms) {
        std::cout << e << " ";
    }
    std::cout << std::endl;
}

int main() {
    TestMultiset();
    return 0;
}

五、multimap容器详解multimap介绍
 


5.1 multimap的特性
 


 multimap  是关联式容器,它按照特定的顺序,存储由  key  和  value  映射成的键值对  <key, value>  ,其中多个键值对之间的  key  是可以重复的。通常按照  key  排序和唯一地标识元素, value  存储与  key  关联的内容。


5.2 multimap的模板参数
 

cpp
  
template <
    class Key,
    class T,
    class Compare = less<Key>,
    class Allocator = allocator<pair<const Key, T>>
> class multimap;


 
 
和  map  的模板参数类似, Key  是键的类型, T  是值的类型, Compare  是比较器, Allocator  是空间配置器。
 

5.3 multimap的常用接口
 


1. 插入元素
 

cpp
  
#include <multimap>
#include <string>
#include <iostream>

int main() {
    std::multimap<std::string, std::string> mm;
    mm.insert(std::make_pair("fruit", "apple"));
    mm.insert(std::make_pair("fruit", "banana"));
    for (const auto& e : mm) {
        std::cout << e.first << " -> " << e.second << std::endl;
    }
    return 0;
}
 
 


1. 删除元素
 

cpp
  
#include <multimap>
#include <string>
#include <iostream>

int main() {
    std::multimap<std::string, std::string> mm = {{"fruit", "apple"}, {"fruit", "banana"}};
    mm.erase(mm.find("fruit")); // 删除一个key为"fruit"的键值对
    for (const auto& e : mm) {
        std::cout << e.first << " -> " << e.second << std::endl;
    }
    return 0;
}
 


 
5.4 multimap使用示例
 

cpp
  
#include <multimap>
#include <string>
#include <iostream>

void TestMultimap() {
    std::multimap<std::string, std::string> mm;
    mm.insert(std::make_pair("person", "Alice"));
    mm.insert(std::make_pair("person", "Bob"));
    mm.insert(std::make_pair("animal", "cat"));
    mm.insert(std::make_pair("animal", "dog"));

    std::cout << "遍历multimap元素:" << std::endl;
    for (const auto& e : mm) {
        std::cout << e.first << " ---> " << e.second << std::endl;
    }
}

int main() {
    TestMultimap();
    return 0;
}
表格
容器 元素唯一性 元素修改 底层结构 应用场景举例
set 唯一 不可修改 红黑树 红黑树|存储不重复的整数集合,如学生学号集合
map key唯一 value可修改 红黑树 红黑树|存储学生学号与成绩的映射关系
multiset 可重复 不可修改 红黑树 统计单词在文本中出现的所有位置(位置可重复)
multimap key可重复 value可修改 红黑树 |红黑树|存储一个班级中所有学生的成绩(可能有重名学生)

六、总结

 set  和  map  作为C++ STL中重要的关联式容器,有着广泛的应用场景。 set  适用于需要存储唯一元素并进行快速查找、排序的场景; map  则适用于需要建立键值对映射关系,通过  key  高效查找  value  的场景。理解它们的特性、接口和底层实现,能帮助我们在实际编程中更高效地使用它们,优化代码性能。希望通过这篇博客,大家能对  set  和  map  有更深入的认识。


网站公告

今日签到

点亮在社区的每一天
去签到