C++实现哈希散列表的示例

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

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。

  • 若关键字为k,则其值存放在f(k)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f为散列函数,按这个思想建立的表为散列表。
  • 对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)==f(k2),这种现象称为冲突(英语:Collision)。具有相同函数值的关键字对该散列函数来说称做同义词。综上所述,根据散列函数f(k)和处理冲突的方法将一组关键字映射到一个有限的连续的地址集(区间)上,并以关键字在地址集中的“像”作为记录在表中的存储位置,这种表便称为散列表,这一映射过程称为散列造表或散列,所得的存储位置称散列地址。
  • 若对于关键字集合中的任一个关键字,经散列函数映象到地址集合中任何一个地址的概率是相等的,则称此类散列函数为均匀散列函数(Uniform Hash function),这就是使关键字经过散列函数得到一个“随机的地址”,从而减少冲突

sample_hashmap.h:

// 创建日期:2022-07-13
// 作者:YZM
// 参考:https://github1s.com/ACking-you/my_tiny_stl/blob/HEAD/src/Data_struct_tool/HashTable/sample_HashMap.h
#pragma once
#ifndef SAMPLE_HASHMAP_H
#define SAMPLE_HASHMAP_H
 
#include<iostream>
#include<vector>
using namespace std;
 
template<typename T>
struct Node {
    Node* next;
    T val;
    Node() :next(nullptr), val(0) {};
    Node(T _val) :next(nullptr), val(_val) {};
    Node(T _val, Node* nxt) :next(nxt), val(_val) {};
};
 
template<typename T>
class HashTable {
private:
    const static int init_buckets_size = 49; // 桶的初始数量
    int buckets_size; // 桶的数量
    int keys_count; // key的数量
    vector<Node<T>>buckets; // 不定义成指针类型,免去初始化的步骤
    int hashfun(T val); // 哈希函数
public:
    HashTable();
    ~HashTable();
    int& operator[](int index) const; // 重载[]运算符,哈希表暂时用不到
    void insert(T val); // 插入
    void erase(T val); // 删除
    bool find(T val); // 寻找
    void expand(); // 扩容
    void clear(); // 清空并释放资源
    void print(); // 打印检查
};
#endif 

sample_hashmap.cpp:

#include "sample_hashmap.h"
using namespace std;

template<typename T>
HashTable<T>::HashTable():buckets_size(init_buckets_size), keys_count(0), buckets(vector<Node<T>>(init_buckets_size)){}

template<typename T>
HashTable<T>::~HashTable() {
    clear();
}

template<typename T>
int HashTable<T>::hashfun(T val) {
    return val % buckets_size;
}

template<typename T>
void HashTable<T>::insert(T val) {
    int key = hashfun(val);
    Node<T>* newNode = new Node<T>(key);
    newNode->next = buckets[key].next;
    buckets[key].next = newNode;
    ++keys_count;
    expand();
}

template<typename T>
void HashTable<T>::erase(T val) {
    int key = hashfun(val);
    Node<T>* cur = buckets[key].next; // 数组元素是结构体对象,.next调出结构体成员.
    Node<T>* pre = nullptr;
    while (cur) {
        if (cur->val == val) {
            if (pre == nullptr) {
                buckets[key].next = cur->next;
                delete cur;
            }
            else {
                pre->next = cur->next;
                delete cur;
            }
            return;
        }
        pre = cur;
        cur = cur->next;
    }
    --keys_count;
}

template<typename T>
bool HashTable<T>::find(T val) {
    int key = hashfun(val);
    Node<T>* cur = buckets[key].next;
    while (cur) {
        if (cur->val == val) return true;
        cur = cur->next;
    }
    return false;
}

template<typename T>
void HashTable<T>::clear() {
    for (int i = 0; i < buckets_size; ++i) {
        Node<T>* cur = buckets[i].next;
        while (cur) {
            Node<T>* pre = cur;
            cur = cur->next;
            delete pre;
        }
        buckets[i].next = nullptr;
    }
}

template<typename T>
void HashTable<T>::expand() {
    if (keys_count > buckets_size) {
        buckets_size <<= 1;
        buckets.resize(buckets_size);
    }
}

template<typename T>
void HashTable<T>::print() {
    for (int i = 0; i < buckets_size; ++i) {
        Node<T>* cur = buckets[i].next;
        while (cur) {
            cout << cur->val << ' ';
            cur = cur->next;
        }
    }
    cout << endl;
}

int main() {
    HashTable<int>hash;
    hash.insert(4);
    hash.print();
    hash.clear();
    hash.print();
    hash.insert(4);
    hash.print();
    hash.erase(4);
    hash.print();
    return 0;
}

到此这篇关于C++实现哈希散列表的示例的文章就介绍到这了,更多相关C++ 哈希散列表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++获取文件哈希值(hash)和获取torrent(bt种子)磁力链接哈希值

    复制代码 代码如下: // CHash.h : header file #pragma once#include "sha1.h" #define        SIZE_OF_BUFFER         16000 class CHash{// Constructionpublic:    CString SHA1Hash(CString strHashFile);}; 复制代码 代码如下: // CHash.cpp : implementation file//#include

  • C++ 实现哈希表的实例

    C++ 实现哈希表的实例 该散列表的散列函数采用了除法散列函数.乘法散列函数.全域散列函数,每一个槽都是使用有序单向链表实现. 实现代码: LinkNode.h #include<iostream> using namespace std; class Link; class LinkNode { private: int key; LinkNode* next; friend Link; public: LinkNode():key(-1),next(NULL){} LinkNode(int

  • C++深入探究哈希表如何封装出unordered_set和unordered_map

    目录 封装前的哈希代码 泛型 获取key 自定义哈希规则 哈希表模板参数解释 迭代器 结构 operator++() 构造函数 重载运算符 小问题 代码汇总 Hash.h MyUnordered_map.h MyUnordered_set.h 默认你已经实现了哈希表(开散列) 封装前的哈希代码 namespace HashBucket { template<class K,class V> struct HashNode { pair<K, V> _kv; HashNode* _n

  • C++哈希表之线性探测法实现详解

    目录 1.哈希表-线性探测法理论 1.1.哈希表的增加元素 1.2.哈希表的查询操作 1.3.哈希表的删除操作 2.哈希表-线性探测法代码实现 2.1.素数表中的素数 1.哈希表-线性探测法理论 线性探测法的理论我们在上一篇博客已经阐述了. 现在我们来看看线性探测法的增删查的代码思想: 1.1.哈希表的增加元素 注意: 往后遍历寻找空闲位置的时候,要注意是环形遍历哦!不然访问数组就越界了. 在添加元素,发生位置被占用,即发生哈希冲突后,在向后遍历寻找空闲位置的时候,我们要知道,这个空闲的位置是有

  • C++哈希应用的位图和布隆过滤器

    目录 C++哈希应用的位图和布隆过滤器 一.位图 1.位图的概念 2.位图的面试题 3.位图的实现 4.位图的应用 二.布隆过滤器 1.布隆过滤器的提出 2.布隆过滤器的概念 3.布隆过滤器的插入 4.布隆过滤器的查找 5.布隆过滤器的删除 6.布隆过滤器的优点和缺点 三.海量数据面试题 1.哈希切割 2.位图应用 3.布隆过滤器 C++哈希应用的位图和布隆过滤器 一.位图 1.位图的概念 所谓位图,就是用每一位来存放某种状态,适用于海量数据,数据无重复的场景.通常是用来判断某个数据存不存在的.

  • C++中的哈希容器unordered_map使用示例

    随着C++0x标准的确立,C++的标准库中也终于有了hash table这个东西. 很久以来,STL中都只提供<map>作为存放对应关系的容器,内部通常用红黑树实现,据说原因是二叉平衡树(如红黑树)的各种操作,插入.删除.查找等,都是稳定的时间复杂度,即O(log n):但是对于hash表来说,由于无法避免re-hash所带来的性能问题,即使大多数情况下hash表的性能非常好,但是re-hash所带来的不稳定性在当时是不能容忍的. 不过由于hash表的性能优势,它的使用面还是很广的,于是第三方

  • C++中使用哈希表(unordered_map)的一些常用操作方法

    目录 1.建立基本数据类型的哈希表 2.向哈希表中添加元素 1).insert函数 2).用数组方法直接添加 3.成员函数 begin(),end()函数 find()查找函数 count()查找函数 size()函数 empty()函数 clear()函数 swap()函数 哈希表的遍历 第一种遍历 第二种遍历 补充:实际应用 总结 1.建立基本数据类型的哈希表 unordered_map<int,int> m; //<string,string>,<char,char&g

  • C++基础算法基于哈希表的索引堆变形

    目录 问题来源 问题简述 问题分析 代码展示 问题来源 此题来自于Hackerrank中的QHEAP1问题,考查了对堆结构的充分理解.成功完成此题,对最大堆或者最小堆的基本操作实现就没什么太大问题了. 问题简述 实现一个最小堆,对3种类型的输入能给出正确的操作: "1 v" - 表示往堆中增加一个值为v的元素 "2 v" - 表示删去堆中值为v的元素 "3" - 表示打印出堆中最小的那个元素 注意:题目保证了要删的元素必然是在堆中的,并且在任何时

  • C++实现哈希散列表的示例

    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度.这个映射函数叫做散列函数,存放记录的数组叫做散列表. 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数. 若关键字为k,则其值存放在f(k)的存储位置上.由此,不需比较便可直接取得所查记录

  • C语言实现散列表(哈希Hash表)实例详解

    C语言实现散列表(哈希Hash表) 实例代码: //散列表查找算法(Hash) #include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define SUCCESS 1 #define UNSUCCESS 0 #define HASHSIZE 7 #define NULLKEY -32768 typedef int Status; type

  • JS散列表碰撞处理、开链法、HashTable散列示例

    本文实例讲述了JS散列表碰撞处理.开链法.HashTable散列.分享给大家供大家参考,具体如下: /** * 散列表碰撞处理.开链法.HashTable散列. * 将数组里的元素位置,也设置为数组,当两个数据的散列在同一个位置时, * 就可以放在这个位置的二维数组里,解决了散列函数的碰撞处理问题 */ function HashTable() { this.table = new Array(137); this.betterHash = betterHash;//散列函数 this.show

  • 如何在Java中实现一个散列表

    目录 前言: 优化1 优化2 优化3 如何实现 总结 前言: 假设现在有一篇很长的文档,如果希望统计文档中每个单词在文档中出现了多少次,应该怎么做呢? 很简单! 我们可以建一个HashMap,以String类型为Key,Int类型为Value: 遍历文档中的每个单词 word ,找到键值对中key为 word 的项,并对相关的value进行自增操作. 如果该key= word 的项在 HashMap中不存在,我们就插入一个(word,1)的项表示新增. 这样每组键值对表示的就是某个单词对应的数量

  • Java数据结构之散列表(动力节点Java学院整理)

    基本概念 散列表(Hash table,也叫哈希表),是根据关键字(key value)而直接进行访问的数据结构. 说的具体点就是它通过吧key值映射到表中的一个位置来访问记录,从而加快查找的速度. 实现key值映射的函数就叫做散列函数 存放记录的数组就就叫做散列表 实现散列表的过程通常就称为散列(hashing),也就是常说的hash 散列 这里的散列的概念不仅限于数据结构了,在计算机科学领域中,散列-哈希是一种对信息的处理方法,通过某种特定的函数/算法(散列函数/hash()方法)将要检索的

  • java面试散列表及树所对应容器类及HashMap冲突解决全面分析

    目录 性能分析 HashMap 产生冲突原因及解决方法 HashMap 解决冲突方法 jdk7 与 jdk8 中HashMap的区别 发生冲突 扩容 使用建议 散列表 Hashmap.hashtable.concurrentHashMap.hashset: 树: treemap.treeset.hashset treeset 继承自 treemap,hashset 继承自 hashmap : 性能分析 Map 是 Java 中的接口,Map.Entry 是 Map 的一个内部接口 Map 提供了

  • java教程散列表和树所对应容器类及HashMap解决冲突学习

    目录 java中散列表.树所对应的的容器类 jdk7与jdk8中HashMap的区别 HashMap如何解决冲突 HashMap的工作原理 java中散列表.树所对应的的容器类 散列表:hashmap,hashtable,concurrentHashmap 树:hashset,treemap,treeset jdk7与jdk8中HashMap的区别 jdk7中hashMap采用数组+链表,如果过多的节点在hash时发生碰撞,如果要查找其中一个节点,需要O(n)的查找时间. jdk7中hashMa

  • Java数据结构之散列表详解

    目录 介绍 1 散列表概述 1.1 散列表概述 1.2 散列冲突(hash collision) 2 散列函数的选择 2.1 散列函数的要求 2.2 散列函数构造方法 3 散列冲突的解决 3.1 分离链接法 3.2 开放定址法 3.3 再散列法 4 散列表的简单实现 4.1 测试 介绍 本文详细介绍了散列表的概念.散列函数的选择.散列冲突的解决办法,并且最后提供了一种散列表的Java代码实现. 数组的特点是寻址容易,插入和删除困难:而链表的特点是寻址困难,插入和删除容易.而对于tree结构,它们

  • C#算法之散列表

    目录 1.散列函数 正整数 浮点数 字符串 组合键 将 HashCode() 的返回值转化为一个数组索引 自定义的 HashCode 软缓存 2.基于拉链法的散列表 散列表的大小 删除操作 有序性相关的操作 3.基于线性探测法的散列表 删除操作 键簇 线性探测法的性能分析 调整数组大小 拉链法 均摊分析 4.内存的使用 如果所有的键都是小整数,我们可以使用一个数组来实现无序的符号表,将键作为数组的索引而数组中键 i 处存储的就是它对应的值.散列表就是用来处理这种情况,它是简易方法的扩展并能够处理

  •  JavaScript 数据结构之散列表的创建

    目录 一.什么是散列表 二.创建散列表 1.创建散列函数 2.put 方法 3.get 方法 4.delete 方法 三.使用散列表 四.总结 散列表与字典基本一致,区别是字典存储的 key 是字符串,而散列表是一个数值(哈希值). 到底如何理解散列表呢?下面进入正题. 一.什么是散列表 散列表,也叫做哈希表,可以根据键(Key)直接访问数据在内存中存储的位置. 简单来说,散列表就是字典的另一种实现,它的优势是比字典能更快地找到一个值.在常规的字典操作中,使用get()方法获得一个值,需要遍历整

随机推荐