C++数据结构之哈希算法详解

C++数据结构之哈希算法详解

概述

哈希算法是一种常用于对数据进行快速检索的算法,它通常将数据映射为一个较短的指纹码,并将这个指纹码作为数据的索引值,这样可以快速地根据索引值找到对应的数据。

本文将详细讲解哈希算法的实现原理、常见应用场景以及在 C++ 语言中如何实现一个简单的哈希表。

哈希算法的实现原理

哈希算法的核心思想是将输入数据通过一个哈希函数进行映射,将其转换为一个固定长度的指纹码,从而实现快速检索。

常用的哈希函数有以下几种:

  • 直接寻址法
  • 数字分析法
  • 平方取中法
  • 折叠法
  • 随机数法
  • 数字转化为字符串法

其中,直接寻址法最为简单,它将输入数据直接作为指纹码的位置,比如输入数据为 x,则它的指纹码为 x。但显然这种写法适用性较差,如果输入数据的取值很大,在散列表中就会产生许多空洞,造成空间的浪费。因此,我们一般使用其他哈希函数来实现哈希算法。

比较常用的是平方取中法,这种算法将输入数据的平方值的中间 n 位作为指纹码的值,其中 n 是指纹码的长度。这种算法的好处在于可以避免输入数据较小的情况下产生的空洞问题,但在输入数据非常大的情况下,还是会产生空洞。

其他的哈希函数,如折叠法、随机数法等,都有其具体的实现细节,需要根据具体的应用场景进行选择。

哈希算法的应用场景

哈希算法广泛应用于大规模数据的快速检索中,例如:

  • 基于关键字的搜索引擎
  • 负载均衡
  • 数据库索引
  • 缓存实现

在这些应用场景下,哈希算法能够通过将输入数据进行快速映射,快速地定位到对应的数据,大大提升了系统的查询速度和响应速度。

在 C++ 语言中实现哈希表

在 C++ 语言中,可以使用 STL 中提供的 unordered_map 来实现哈希表的功能。unordered_map 可以接收一个哈希函数,将输入数据映射为一个指纹码,并将指纹码作为 key,对应的值存储在哈希表中。

#include <iostream>
#include <unordered_map>

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

    // 插入数据
    hash_map[1] = "one";
    hash_map[2] = "two";
    hash_map[3] = "three";

    // 查询数据
    std::cout << hash_map[1] << std::endl;

    // 遍历哈希表
    for (auto& iter : hash_map)
    {
        std::cout << "Key = " << iter.first << ", Value = " << iter.second << std::endl;
    }

    return 0;
}

在上述代码中,我们创建了一个 unordered_map 对象 hash_map,将一些数据插入到哈希表中,并通过 key 查询对应的 value。同时,我们也演示了如何遍历哈希表中的所有数据,可以看到,查询和遍历操作都非常快速。

此外,C++ 11 中还提供了一些哈希函数,如 std::hash 和 std::hash_combine 等,可以方便地自定义哈希函数,从而实现更加灵活的哈希算法。

示例说明

示例一:基于哈希表实现电话簿

下面我们来通过一个例子,更深入地了解哈希算法的实际应用。我们将使用哈希表来实现一个简单的电话簿程序,从而更好地理解哈希算法的实现过程。

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

// 定义联系人结构体
struct Contact {
    std::string name;
    std::string phone_number;
};

int main()
{
    // 定义哈希表对象
    std::unordered_map<std::string, Contact> phone_book;

    // 插入联系人信息
    phone_book["Tom"] = { "Tom", "123456" };
    phone_book["Jerry"] = { "Jerry", "111111" };
    phone_book["Alice"] = { "Alice", "222222" };

    // 查询联系人信息
    std::string name = "Alice";
    if (phone_book.count(name)) {
        Contact contact = phone_book[name];
        std::cout << "Name: " << contact.name << ", Phone: " << contact.phone_number << std::endl;
    }
    else {
        std::cout << "Contact not found." << std::endl;
    }

    return 0;
}

在上述代码中,我们定义了一个名为 Contact 的结构体,用于存储每个联系人的姓名和电话号码。通过使用哈希表,我们可以将每个联系人的姓名作为 key,对应的 Contact 对象作为 value,来进行快速的查找。

在程序中,我们首先插入了一些联系人信息,然后查询了一个名为 Alice 的联系人,并输出了其姓名和电话号码。可以看到,使用哈希表实现电话簿程序非常简单且高效。

示例二:基于哈希表实现缓存

另一个应用哈希表的实际例子是实现一个缓存程序。缓存程序通常需要快速读取和写入数据,并且可以限制存储数据的大小,当缓存已达到上限时自动删除最旧的数据。

下面是一个示例代码,用于演示如何使用哈希表来实现一个 LRU 缓存。

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

// 定义缓存对象结构体
struct CacheEntry {
    std::string key;
    std::string value;
    CacheEntry(const std::string& k, const std::string& v) : key(k), value(v) {}
};

class LRUCache {
public:
    LRUCache(int capacity) : m_capacity(capacity) {}

    std::string get(const std::string& key) {
        auto iter = m_cache_map.find(key);
        if (iter == m_cache_map.end()) {
            return "";
        }
        m_key_list.splice(m_key_list.begin(), m_key_list, iter->second);
        return iter->second->value;
    }

    void put(const std::string& key, const std::string& value) {
        auto iter = m_cache_map.find(key);
        if (iter != m_cache_map.end()) {
            m_key_list.splice(m_key_list.begin(), m_key_list, iter->second);
            iter->second->value = value;
            return;
        }
        if (m_cache_map.size() == m_capacity) {
            auto last_node = m_key_list.end();
            last_node--;
            m_cache_map.erase(last_node->key);
            m_key_list.pop_back();
        }
        m_key_list.emplace_front(key, value);
        m_cache_map[key] = m_key_list.begin();
    }

private:
    std::unordered_map<std::string, std::list<CacheEntry>::iterator> m_cache_map;
    std::list<CacheEntry> m_key_list;
    int m_capacity;
};

int main()
{
    LRUCache cache(2);

    cache.put("key1", "value1");
    cache.put("key2", "value2");
    std::cout << cache.get("key1") << std::endl; // Expected output: "value1"
    cache.put("key3", "value3");
    std::cout << cache.get("key2") << std::endl; // Expected output: ""

    return 0;
}

在上述代码中,我们使用了一个哈希表来缓存数据,并使用一个双向链表来记录数据的访问顺序。其中,双向链表头结点表示最近访问的数据,链表尾结点表示最近最少访问的数据。当程序需要插入新数据时,如果缓存已满,则删除最近最少访问的数据;如果需要访问数据时,将其移动到链表头结点,表示最近访问过。通过这种方式,我们可以在满足空间限制的情况下,实现快速地访问和插入数据。

总结

哈希算法是一种常用于数据快速检索的算法,它通过将输入数据映射为一个指纹码,并将指纹码作为数据的索引值,实现了快速检索的功能。在实际应用中,哈希算法可以应用于搜索引擎、负载均衡、数据库索引和缓存等方面。在 C++ 语言中,可以使用 STL 中提供的 unordered_map 来实现简单的哈希表,也可以使用 std::hash 和 std::hash_combine 等函数自定义哈希函数,实现更加灵活的哈希算法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++数据结构之哈希算法详解 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • C++ 数据结构二叉树(前序/中序/后序递归、非递归遍历)

    下面是关于C++二叉树数据结构的详细攻略。 什么是二叉树 二叉树是一种树形数据结构,每个节点最多有两个子节点:左节点和右节点。一个节点没有左节点或右节点则分别为左子树和右子树为空。 递归遍历二叉树 前序遍历 前序遍历是指对于一棵二叉树,在访问右子树之前,先访问根节点,然后访问左子树。 下面是C++递归遍历二叉树的前序遍历示例代码: template <…

    数据结构 2023年5月17日
    00
  • Halcon软件安装与界面简介

      1. 下载Halcon17版本到到本地 2. 双击安装包后 3. 步骤如下     界面分为四大块 1.    Halcon的五个助手 1)    图像采集助手:与相机连接,设定相机参数,采集图像 2)    标定助手:九点标定或是其它的标定,生成标定文件及内参外参,可以将像素单位转换为长度单位 3)    模板匹配助手:画取你想寻找的图像,设定参数,可…

    算法与数据结构 2023年4月19日
    00
  • 【ACM算法竞赛日常训练】DAY5题解与分析【储物点的距离】【糖糖别胡说,我真的不是签到题目】| 前缀和 | 思维

    DAY5共2题: 储物点的距离(前缀和) 糖糖别胡说,我真的不是签到题目(multiset,思维) ? 作者:Eriktse? 简介:19岁,211计算机在读,现役ACM银牌选手?力争以通俗易懂的方式讲解算法!❤️欢迎关注我,一起交流C++/Python算法。(优质好文持续更新中……)?? 原文链接(阅读原文获得更好阅读体验):https://www.eri…

    算法与数据结构 2023年4月18日
    00
  • C语言创建和操作单链表数据结构的实例教程

    C语言创建和操作单链表数据结构的实例教程 什么是单链表 单链表是一种常见的动态数据结构,它由一个个节点组成,每个节点包含范围内的数据和指向下一个节点的指针。单链表通常用于需要频繁插入删除节点的情况。 单链表的创建和操作步骤 创建单链表 定义一个链表节点结构体,结构体中包含要存储的数据和指向下一个节点的指针。 定义一个指向链表头部的指针,如果链表为空,则指针为…

    数据结构 2023年5月17日
    00
  • C语言数据结构之顺序数组的实现

    C语言数据结构之顺序数组的实现 前言 顺序数组是数据结构的一个重要部分,它代表着一种基本的数据结构,能够在数据存储与访问方面发挥极大的作用。本文将详细讲解如何在C语言中实现顺序数组。 简介 顺序数组是在物理内存中顺序存储的一组元素数据,可以通过下标访问任意一个元素。通常情况下,顺序数组的数据类型是相同的,而且每一个元素的大小也是相同的。 实现 实现顺序数组主…

    数据结构 2023年5月17日
    00
  • 如何配置git环境

    首先我们新建一个文件夹;    然后我们右键git Bash Here一下;在里面输入: cd ssh-keygen cd.ssh ls (注意,我们要是之前就生成过密钥,直接输入ls就好了) 输入ls之后,会显示出来我们的公钥,我们输入: cat id_rsa.pub 然后密钥就出来了,密钥出来之后,我们把密钥复制一下,打开github 选择设置; 中会有…

    算法与数据结构 2023年4月18日
    00
  • GPS北斗卫星时间同步系统助力电力自动化网络系统

    GPS北斗卫星时间同步系统助力电力自动化网络系统 GPS北斗卫星时间同步系统助力电力自动化网络系统 京准电子官微——ahjzsz 前言 近几年来,随着电力自动化水平的提高,在电力中计算机监控系统、微机保护装置、微机故障录波装置以及各类数据管理机得到了广泛的应用,而这些自动装置的配合工作需要有一个精确统一的时间。当电力系统发生故障时,既可实现全站各系统在统一时…

    算法与数据结构 2023年5月8日
    00
  • MySQL高级篇之索引的数据结构详解

    MySQL高级篇之索引的数据结构详解 索引的作用 索引是一种数据结构,用于快速地定位和访问数据表中的指定行。MySQL中索引通常以B-tree(B树)或哈希表的形式来实现,通过将索引存储在内存中,可以提高系统的查询效率。 常用的索引分为主键索引、唯一索引和普通索引。其作用分别为: 主键索引:保证表中每一行数据的唯一性,便于快速查询和修改数据。 唯一索引:保证…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部