首页 > 其他分享 >std::map和std::unordered_map

std::map和std::unordered_map

时间:2023-10-29 13:07:24浏览次数:33  
标签:std map 查找 键值 哈希 unordered


区别

std::map 和 std::unordered_map 是 C++ 标准库中的两个容器,用于实现键值对的关联。它们之间的主要区别在于底层实现和性能特征。

底层实现:std::map 是基于红黑树(一种平衡二叉搜索树)实现的有序映射容器,而 std::unordered_map 是基于哈希表实现的无序映射容器。

排序:std::map 中的元素是按照键的排序顺序进行存储的,因此在遍历时会按照键的升序输出。而 std::unordered_map 中的元素是根据哈希函数计算的哈希值存储的,没有固定的顺序。

查找效率:在平均情况下,std::map 的查找操作的时间复杂度为 O(log n),其中 n 是元素的数量。而 std::unordered_map 的查找操作的平均时间复杂度为 O(1),即常数时间。这是因为哈希表可以通过哈希函数直接计算出元素所在的位置,而不需要进行比较操作。

内存占用:由于 std::map 使用红黑树存储元素,并且需要维护树的平衡性,因此它通常占用的内存比 std::unordered_map 多。而 std::unordered_map 使用哈希表存储元素,其内存占用相对较少。

对于存储大量数据并需要快速查找的场景,std::unordered_map 通常具有更好的性能,因为它的查找操作更快速。但是,如果你需要按照键的顺序进行遍历或者需要有序的存储,那么 std::map 是更合适的选择。

需要注意的是,由于哈希表的实现依赖于哈希函数,因此 std::unordered_map 在某些情况下可能会出现哈希冲突,导致性能下降。另外,std::map 支持自定义的比较函数来定义键的排序方式,而 std::unordered_map 则需要提供自定义的哈希函数。

根据具体的使用场景和需求,你可以选择适合的容器来实现键值对的关联。

std::unordered_map使用示例

在 C++ 中,你可以使用标准库中的 std::unordered_map 类来创建一个哈希表(无序映射)。std::unordered_map 提供了一种将键和值关联起来的方式,并使用哈希函数来快速查找和访问元素。

以下是一个示例代码,演示如何创建和使用 std::unordered_map:

#include <iostream>
#include <unordered_map>
#include <string>

int main()
{
    std::unordered_map<std::string, int> hashTable;

    // 向哈希表中插入键值对
    hashTable["apple"] = 1;
    hashTable["banana"] = 2;
    hashTable["orange"] = 3;

    // 访问哈希表中的元素
    std::cout << "apple 的值为:" << hashTable["apple"] << std::endl;

    // 检查哈希表中是否存在某个键
    if (hashTable.count("banana") > 0)
    {
        std::cout << "哈希表中存在 banana 键" << std::endl;
    }

    // 遍历哈希表中的所有键值对
    for (const auto& pair : hashTable)
    {
        std::cout << "键:" << pair.first << ",值:" << pair.second << std::endl;
    }

    return 0;
}

在上述代码中,我们首先包含了 <unordered_map> 头文件,并使用 std::unordered_map<std::string, int> 定义了一个哈希表,其中键的类型是 std::string,值的类型是 int。

然后,我们使用插入操作 hashTable[“key”] = value 向哈希表中插入键值对。我们可以使用方括号操作符来访问哈希表中的元素,例如 hashTable[“apple”]。

我们还可以使用 count() 函数来检查哈希表中是否存在某个键。如果 count(“key”) 的返回值大于 0,则表示哈希表中存在该键。

最后,我们使用范围循环遍历哈希表中的所有键值对,并输出它们的键和值。

运行上述代码将输出以下结果:

apple 的值为:1
哈希表中存在 banana 键
键:banana,值:2
键:orange,值:3
键:apple,值:1

为什么 查找哈希表的时候,要判断.end(),如下代码:

auto it = myHashMap.find(key);
if (it != myHashMap.end())

在 C++ 的 std::unordered_map 中,find 函数在找到指定键的情况下会返回一个指向该键的迭代器,如果没有找到指定键,则返回一个指向容器末尾的迭代器,即 end()。因此,我们可以通过判断迭代器是否等于 end() 来确定是否找到了指定的键。

当 find 函数没有找到指定键时,它会返回一个指向容器末尾的迭代器,这是一个特殊的迭代器,表示查找失败。通过判断迭代器是否等于 end(),我们可以确定是否找到了指定的键。

在你提供的代码中,auto it = myHashMap.find(key); 将查找结果赋值给 it,然后通过 it != myHashMap.end() 来判断是否找到了指定键。如果 it 等于 myHashMap.end(),则说明没有找到指定键;否则,说明找到了指定键。

这种判断方式可以避免在未找到键的情况下访问不存在的迭代器或者无效的值,从而防止程序运行时出现错误或异常情况。因此,在使用 find 函数进行哈希表的查找时,通常会结合判断迭代器是否等于 end() 来确保查找的安全性。

std::map 的简单示例

下面是一个使用 std::map 的简单示例:

#include <iostream>
#include <map>

int main() {
    // 创建一个 std::map 容器,键的类型为 int,值的类型为 std::string
    std::map<int, std::string> myMap;

    // 向 map 中插入键值对
    myMap.insert(std::make_pair(1, "apple"));
    myMap.insert(std::make_pair(2, "banana"));
    myMap.insert(std::make_pair(3, "orange"));

    // 使用下标操作符访问键值对
    std::cout << "Value at key 2: " << myMap[2] << std::endl;

    // 使用迭代器遍历 map
    std::cout << "All key-value pairs in the map:" << std::endl;
    for (auto it = myMap.begin(); it != myMap.end(); ++it) {
        std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl;
    }

    // 查找特定的键
    int key = 3;
    auto it = myMap.find(key);
    if (it != myMap.end()) {
        std::cout << "Value found at key " << key << ": " << it->second << std::endl;
    } else {
        std::cout << "Key " << key << " not found in the map." << std::endl;
    }

    // 删除特定的键值对
    myMap.erase(2);

    // 检查键是否存在
    if (myMap.count(2) > 0) {
        std::cout << "Key 2 exists in the map." << std::endl;
    } else {
        std::cout << "Key 2 does not exist in the map." << std::endl;
    }

    return 0;
}

这个示例展示了如何使用 std::map 创建、插入、访问、遍历、查找和删除键值对。你可以根据自己的需求修改和扩展这个示例。


标签:std,map,查找,键值,哈希,unordered
From: https://blog.51cto.com/u_15316847/8079852

相关文章

  • HashMap集合遍历随机性问题分析
    一、原因分析1.1HashMap对象的遍历HashMap的遍历是通过此类中字段table数组进行顺序遍历,原因如下所示:1#HashMap迭代遍历源码2publicfinalbooleanhasNext(){3returnnext!=null;4}56finalNode<K,V>nextNode(){7Node<K,V>[]t;......
  • 无涯教程-Clojure - struct-map函数
    通过显式定义将哪些值分配给结构中的哪些键,此函数用于将值专门分配给键值。struct-map-语法(struct-mapstructnamekeynvaluen….)参数   - "structname"是要赋予结构的名称,"keyn和valuen"是需要分配给该结构的键值。返回值 - 返回一个结构对象,其值映射......
  • C#详解-Contains、StartsWith、EndsWith、Indexof、lastdexof 怎样性能最优
    简介:在C#中Contains、StarsWith和EndWith、IndexOf都是字符串函数。1.Contains函数用于判断一个字符串是否包含指定的子字符串,返回一个布尔值(True或False)。2.StartsWith函数用于判断一个字符串是否以指定的子字符串开头,返回一个布尔值(True或False)。3.EndsWith函数用于判断一个字......
  • 用HashMap创建jString,ArrayList的键值对用entrySet遍历
    用HashMap创建jString,ArrayList的键值对用entrySet遍历package随机点名器;importjava.util.*;publicclassTest1{publicstaticvoidmain(String[]args){HashMap<String,ArrayList<String>>m=newHashMap<>();ArrayList<String>......
  • ArcMap属性表出现乱码情况的解决
      本文介绍ArcMap软件打开图层的属性表后,出现字段中汉字乱码情况的解决方法。  有时在使用ArcMap软件时,会发现一些图层的属性表中,原本应该是中文的字段却出现乱码的情况;如下图所示,其中NAME99一栏应该是图层中各个要素对应的汉语名称,但却出现了数字、符号等乱码。  针对这......
  • colmap 初体验
    安装:Installation—COLMAP3.9-devdocumentation使用:Tutorial—COLMAP3.9-devdocumentation准备数据集下载一个小猫的RGB数据集THU-MVS:Multi-View3DReconstructionDatasets创建project_cat文件夹,把图片放project_cat/images下启动程序运行COLMAP.bat启动......
  • MapillaryVistas数据集入门
    MapillaryVistas数据集入门在计算机视觉领域,数据集是进行算法研究和模型训练的重要基础。本文将介绍MapillaryVistas数据集,该数据集是一个大规模的街景图像数据集,可以用于场景理解、语义分割等任务。什么是MapillaryVistas数据集?MapillaryVistas数据集由Mapillary公司收集和发布,是......
  • C++从std::vector<int>类型数据创建二叉树
    背景在和chatGPT的日常代码交流中,这位“老师”总能给出不不少好代码,以下就是C++从std::vector类型数据创建二叉树的完整代码段:TreeNode*createBinaryTree(conststd::vector<int>&nodes,intindex){if(index>=nodes.size()||nodes[index]==-1){retu......
  • Spring @ConfigurationProperties Yaml语法配置List和Map:List<String>、List<Obj>、L
    yaml语法数据结构可以用类似大纲的缩排方式呈现,结构通过缩进来表示,连续的项目通过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔。例子:配置类YmalConfig:importcn.hutool.json.JSONUtil;importlombok.Data;importorg.springframework.boot.context.properti......
  • C++的std::move与std::forward原理总结
    目录0、左值与右值的理解左值和右值的概念左值引用和右值引用1.std::move1.1函数原型1.2参数讨论1.3通用引用1.4返回值1.5std::move的常用例子1.5.1用于vector添加值1.5.2用于unique_ptr传递1.6再说转移对象控制权2.std::foward参考阅读大型的C++开源项目代码,基本......