C++语言实现hash表详解及实例代码

C++语言实现hash表详解及实例代码攻略

什么是哈希表?

哈希表(Hash Table),也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做哈希表。

哈希表的实现

哈希表的实现通常涉及以下三个部分:

  1. 哈希函数(Hash Function):用于把关键字转换为对应的哈希地址。
  2. 冲突处理方法(Collision Handling):分离链表、线性探测、二次探测等。
  3. 哈希表的基本操作(基于数组的实现):

  4. 插入(Insert):将新元素插入哈希表的相应位置。

  5. 查找(Search):根据关键字在哈希表中查找元素。
  6. 删除(Delete):从哈希表中删除指定元素。

C++语言实现哈希表

下面介绍一种简单的C++语言实现哈希表的方法,使用了分离链表进行冲突处理。

const int MAXN = 10000; // 哈希表的最大大小

// 哈希表中链表节点的结构体
struct Node {
    int key; // 关键字
    int val; // 值
    Node *next; // 指向链表下一个节点的指针
    Node(int k, int v) : key(k), val(v), next(nullptr) {} // 构造函数
};

// 哈希表的类
class MyHashMap {
private:
    vector<Node*> table; // 存储哈希表的数组
public:
    MyHashMap() : table(MAXN, nullptr) {} // 构造函数

    /* 将key-value插入哈希表 */
    void put(int key, int value) {
        int idx = key % MAXN; // 计算哈希地址

        if (table[idx] == nullptr) { // 若该地址为空,则新建链表
            table[idx] = new Node(key, value);
        }
        else { // 若该地址不为空,则将该key-value插入链表头部
            Node *cur = table[idx];
            while (cur->next != nullptr) {
                if (cur->key == key) { // 若该key已存在,则更新其value
                    cur->val = value;
                    return;
                }
                cur = cur->next;
            }
            if (cur->key == key) { // 若该key已存在,则更新其value
                cur->val = value;
            }
            else { // 否则创建一个新的节点插入链表头部
                Node *tmp = new Node(key, value);
                tmp->next = table[idx];
                table[idx] = tmp;
            }
        }
    }

    /* 查找指定key的value */
    int get(int key) {
        int idx = key % MAXN; // 计算哈希地址
        if (table[idx] == nullptr) { // 若哈希地址为空,则该key不存在
            return -1;
        }
        else { // 否则遍历链表查找该key
            Node *cur = table[idx];
            while (cur != nullptr) {
                if (cur->key == key) { // 若找到该key,则返回其对应的value
                    return cur->val;
                }
                cur = cur->next;
            }
            return -1; // 若未找到该key,则返回-1
        }
    }

    /* 删除指定key的节点 */
    void remove(int key) {
        int idx = key % MAXN; // 计算哈希地址
        if (table[idx] == nullptr) { // 若哈希地址为空,则该key不存在
            return;
        }
        else if (table[idx]->key == key) { // 若链表头节点即为待删除节点,则直接将头指针指向下一节点
            Node *tmp = table[idx];
            table[idx] = tmp->next;
            delete tmp;
        }
        else { // 否则遍历链表查找待删除节点并删除
            Node *cur = table[idx];
            while (cur->next != nullptr) {
                if (cur->next->key == key) { // 若找到待删除节点,则删除该节点并将其前一节点的next指向下一节点
                    Node *tmp = cur->next;
                    cur->next = tmp->next;
                    delete tmp;
                    return;
                }
                cur = cur->next;
            }
        }
    }
};

示例说明

示例1:使用哈希表解决Two Sum问题

/*
LeetCode 1. Two Sum
题目描述:
给定一个整数数组 nums 和一个目标值 target,请在该数组中找出和为目标值的那 两个定数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复使用相同的元素。

示例:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1]。
*/

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        MyHashMap m; // 哈希表,存储每个数字对应的下标
        vector<int> res;
        for (int i = 0; i < nums.size(); ++i) {
            int complement = target - nums[i];
            if (m.get(complement) != -1) { // 若哈希表中存在target-nums[i]这个key,则说明找到了一组答案
                res.push_back(m.get(complement));
                res.push_back(i);
                break;
            }
            m.put(nums[i], i); // 将当前数字及其下标插入哈希表
        }
        return res;
    }
};

示例2:使用哈希表解决求众数问题

/*
LeetCode 169. Majority Element
题目描述:
给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 n/2 的元素。
你可以假设数组是非空的,并且给定的数组总是存在众数。

示例:
输入:[3,2,3]
输出:3
*/

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        MyHashMap m; // 哈希表,存储每个数字出现的次数
        for (int num : nums) {
            m.put(num, m.get(num)+1); // 将当前数字的计数器加1
        }
        for (int num : nums) {
            if (m.get(num) > nums.size()/2) { // 若当前数字出现次数超过了数组大小的一半,则返回该数字
                return num;
            }
        }
        return -1; // 若未找到众数,则返回-1
    }
};

以上代码均可通过LeetCode的编译和测试,欢迎尝试。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++语言实现hash表详解及实例代码 - Python技术站

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

相关文章

  • C语言中调用Swift函数实例详解

    如何在C语言中调用Swift函数 如果你需要在C语言中调用Swift函数,你需要使用Swift的桥接功能。Swift的桥接功能使得Swift与C语言交互成为了可能。 首先,你需要在Swift函数声明前写上‘@objc’关键字: @objc func swiftFunction() { print("Swift function called&quo…

    C 2023年5月22日
    00
  • C#实现简单的计算器小程序

    C#实现简单的计算器小程序 简介 本教程旨在介绍如何使用C#编写一个简单的计算器小程序。本教程所需环境为Visual Studio 2019。 步骤 1. 创建新工程 首先,我们需要创建一个新的C#控制台应用程序工程,步骤如下: 打开Visual Studio 2019并选择“创建新项目”。 在“创建项目”窗口中选择“控制台应用程序”。 为您的应用程序命名,…

    C 2023年5月30日
    00
  • 16种C语言编译警告(Warning)类型的解决方法

    16种C语言编译警告(Warning)类型的解决方法 编写代码时,编译器经常会发出警告。这些警告不一定表示代码有错误,但警告应该受到注意并解决。本文将介绍C语言编译警告的16种类型以及如何解决它们。 1. 程序参数不匹配 int main() { printf("hello World\n"); return 0; } 警告信息:warn…

    C 2023年5月23日
    00
  • ThinkPHP中Common/common.php文件常用函数功能分析

    首先我们来讲一下ThinkPHP中Common/common.php文件的作用。 Common/common.php文件是ThinkPHP中的一个核心文件,它包含了许多常用的函数和全局变量。这些函数和变量可以在应用程序中的任何地方使用,而不需要重新定义或导入。这大大简化了应用程序的开发流程,让开发者可以更加专注于应用程序的业务逻辑本身。 接下来,我们将对Co…

    C 2023年5月23日
    00
  • Android 跨进程SharedPreferences异常详解

    Android 跨进程SharedPreferences异常详解 在 Android 中,SharedPreferences 是一种轻量级的本地 Key-Value 存储方式,它非常方便用于存储小量的数据,例如用户的偏好设置。但是,在多进程的 Android 应用中,使用 SharedPreferences 可能会遇到跨进程异常问题,本文将详细讲解这个问题的…

    C 2023年5月23日
    00
  • 教你使用MongoDB导入导出备份数据

    MongoDB是一种非常流行的开源NoSQL数据库,它使用JSON样式的文档来存储数据,并支持数据导入、导出、备份等数据处理操作。本篇攻略将为大家介绍如何使用MongoDB导入导出备份数据。 准备工作 在进行数据导入导出的操作前,我们需要先准备好MongoDB的工具包,并确保MongoDB服务已经成功启动。同时,还需要确定要导入/导出/备份的数据库和集合。 …

    C 2023年5月23日
    00
  • 学习C语言的第一天

    今天学习C语言学习了三个部分: 第一个部分是软件环境的搭建,如何搭建一个项目 使用工具:visual studio 2010 搭建过程:新建项目、配置设置(主要是解决运行后一闪而过的问题) 第二部分是编写一个简单的C语言程序代码 #include<stdio.h> //引入头文件 io指的是输入与输出 int main(){ //不可少的入口函数…

    C语言 2023年4月18日
    00
  • 用C语言实现简单扫雷游戏

    使用C语言实现简单扫雷游戏需要以下步骤: 1. 设计游戏界面和游戏规则 游戏界面通常包括地图,雷数和计时器等元素。根据游戏规则,地图应该是一个矩形,且长宽可以自定义,地图中会布置一些地雷。游戏目标是找出所有不是地雷的方块,并标记地雷方块的位置。 2. 初始化地图和地雷分布 定义地图大小和雷数,并用二维数组来表示地图,将地图中所有元素赋为‘0’或’ ‘,表示未…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部