返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++哈希表之闭散列方法的模拟实现详解
  • 262
分享到

C++哈希表之闭散列方法的模拟实现详解

C++哈希表实现闭散列C++ 闭散列C++哈希表 2022-11-13 19:11:16 262人浏览 独家记忆
摘要

目录哈希概念冲突闭散列线性探测哈希表闭散列的模拟实现模拟实现的闭散列中的问题与改进哈希 概念 可以不经过任何比较,直接从表中得到要搜索的元素。 关键在于通过某种函数,使元素的存储位置

哈希

概念

可以不经过任何比较,直接从表中得到要搜索的元素。 关键在于通过某种函数,使元素的存储位置与它的关键码之间能够建立 一一映射的关系。这样就可以通过o(1)的时间复杂度来寻找到元素。

例如数据集合{1,7,4,5,9,6},哈希函数hash(key)=key&capacity 

冲突

hash(7)=7 hash(17)=7,两个不同的数通过哈希函数映射到了一个位置,产生了冲突。哈希函数设计的越精妙,产生冲突的可能性就越低,但无法避免。

解决方法:

  • 闭散列(开放定址法)
  • 开散列(拉链法)

闭散列

闭散列,(开放定址法)发生冲突时,如果哈希表没有被填满,则表内一定还有其他空闲位置,可以把冲突值放到下一个没有被占用的空余位置上。

如何找到下一个没有被占用的空位?答:采用线性探测方法。从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

线性探测

线性探测的插入

如:在上述的哈希表中插入元素44,由于下标为4的位置放入了元素4,于是从该位置往后++,找到第一个不为空的位置,将44放入。

线性探测的删除

在寻找要删除的元素时,依然会根据存放在哈希表的下标开始寻找,比如在上述哈希表中寻找4,在4下标位置直接就可以找到该元素。但如果直接将其删除,那后续寻找元素44时,就会因为4下标没有元素,而认为元素44不存在于这张哈希表。所以我们需要设置一个状态来表示删除。

哈希表闭散列的模拟实现

我们写在一个自定义类域 Closehash 里面

准备工作

哈希表中元素状态

namespace Closehash
{
    //哈希表中元素的状态
    enum State
    {
        EMPTY,
        EXIT,
        DELETE
    };    
}

存储类型用pair即可,但是数据中要包含状态,我们进行一次封装

//由于数据需要一个状态,所以需要将pair<K,V>封装一层
    template<class K,class V>
    struct HashDate
    {
        pair<K, V>_kv;
        State _state;
    };

开始(画饼)构建哈希表的内容

template<class K,class V>
    class HashTable
    {
    public:
        bool Insert(const pair<K,V>& kv);
        HashDate<K, V>* find(const K& key);
        bool Erase(const K& key);
    private:
        vector<HashDate<K,V>> _tables;
        size_t _size = 0;
    };

闭散列的插入

        bool Insert(const pair<K, V>& kv)
        {
            //if (Find(kv.first)) return false; 
            //Find实现了再去掉注释
 
            if (_tables.size() == 0 
                || 10 * _size / _tables.size() >= 7)//相当于存了70%
            {
                //开始扩容
                size_t newsize = _tables.size()== 0 ? 10 : _tables.size() * 2;
                HashTable<K, V> newHash;
                newHash._tables.resize(newsize);
                for (auto e: _tables)//注意_tables是HashDate类型 里面有_kv 和_state
                {
                    if (e._state == EXIST)
                    {
                        newHash.Insert(e._kv);
                    }
                }
                //资本家拷贝方法
                _tables.swap(newHash._tables);
            }
            //走到这里扩容完成 或者空间足够大
            size_t hashi = kv.first % _tables.size();//寻找在表中对应的下标是什么
            while (_tables[hashi]._state==EXIST)
            {
                hashi++;
                //走到头了得回来
                hashi%=_tables.size();
            }
            _tables[hashi]._kv = kv;
            _tables[hashi]._state = EXIST;
            _size++;
            return true;
        }

测试用例

void TestHT1()
    {
        int a[] = { 1, 11, 4, 15, 26, 7, 44 };
        HashTable<int, int> ht;
        for (auto e : a)
        {
            ht.Insert(make_pair(e, e));
        }
 
        ht.Print();
    }

添加个99以验证扩容功能

闭散列的查找

HashDate<K, V>* Find(const K& key)
        {
            if (_tables.size() == 0) return nullptr;
            size_t hashi = key % _tables.size();
            while (_tables[hashi]._state != EMPTY)
            {
                if (_tables[hashi]._state != DELETE 
                    && _tables[hashi]._kv.first == key)
                {
                    return &_tables[hashi];
                }
                hashi++;
                hashi% _tables.size();
            }
            return nullptr;
        }

测试用例

    cout << ht.Find(4)->_kv.first << endl; 

闭散列的删除

bool Erase(const K& key)
        {
            HashDate<K,V>* ret = Find(key);
            if (ret)
            {
                ret->_state = DELETE;
                --_size;
                return true;
            }
            else
            {
                return false;
            }
        }

模拟实现的闭散列中的问题与改进

上述测试用例中使用的是pair<int,int>那我要是用pair<string,int>呢?我的key还可以直接对数组长度取模吗?

文档中对这一问题采用了仿函数的解决方法,我们这里也按照该方法模拟一个。

    template<class K>
    struct HashFunc
    {
        size_t operator()(const K& key)
        {
            return (size_t)key;
        }
    };
 
    // 特化  
    template<>
    struct HashFunc<string>
    {
        // BKDR
        size_t operator()(const string& key)
        {
            size_t val = 0;
            for (auto ch : key)
            {
                val *= 131;
                val += ch;
            }
 
            return val;
        }
    };
 
    template<class K,class V,class Hash=HashFunc<K>>
    class HashTable
    {
    public:
        bool Insert(const pair<K,V>& kv);
        HashDate<K, V>* find(const K& key);
        bool Erase(const K& key);
    private:
        vector<HashDate<K,V>> _tables;
        size_t _size = 0;
    };

在每次求 在哈希表中位置的前面添加

Hash hash;
size_t hashi = hash(kv.first) % _tables.size()

测试用例

void TestHT2()
    {
        string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
 
        //HashTable<string, int, HashFuncString> countHT;
        HashTable<string, int> countHT;
        for (auto& str : arr)
        {
            auto ptr = countHT.Find(str);
            if (ptr)
            {
                ptr->_kv.second++;
            }
            else
            {
                countHT.Insert(make_pair(str, 1));
            }
        }
    }

测试用例没加打印...让我来回看了好几遍代码...蠢到无语

到此这篇关于c++哈希表之闭散列方法的模拟实现详解的文章就介绍到这了,更多相关C++哈希表实现闭散列内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++哈希表之闭散列方法的模拟实现详解

本文链接: https://lsjlt.com/news/171205.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C++哈希表之闭散列方法的模拟实现详解
    目录哈希概念冲突闭散列线性探测哈希表闭散列的模拟实现模拟实现的闭散列中的问题与改进哈希 概念 可以不经过任何比较,直接从表中得到要搜索的元素。 关键在于通过某种函数,使元素的存储位置...
    99+
    2022-11-13
    C++哈希表实现闭散列 C++ 闭散列 C++哈希表
  • C++实现哈希散列表的示例
    散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这...
    99+
    2024-04-02
  • C++哈希表之线性探测法实现详解
    目录1、哈希表-线性探测法理论1.1、哈希表的增加元素1.2、哈希表的查询操作1.3、哈希表的删除操作2、哈希表-线性探测法代码实现2.1、素数表中的素数1、哈希表-线性探测法理论 ...
    99+
    2024-04-02
  • JavaScript实现哈希表的方法
    本篇内容主要讲解“JavaScript实现哈希表的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript实现哈希表的方法”吧!哈希表通常是基于数...
    99+
    2024-04-02
  • C++数据结构之哈希表的实现
    目录哈希表概念散列函数直接定址法除留余数法平方取中法哈希冲突线性探测二次探测链地址法哈希表的实现闭散列开散列哈希表概念 二叉搜索树具有对数时间的表现,但这样的表现建立在一个假设上:输...
    99+
    2023-03-11
    C++数据结构 哈希表 C++哈希表 C++数据结构
  • 数据结构Typescript之哈希表实现详解
    目录哈希表的结构特点面向对象方法封装哈希表哈希冲突构造函数基本单元:键值对主体:哈希表增加键值对获取键值删除键值对哈希表的结构特点 相比链表繁杂的遍历处理,哈希表的作用是存储无固定...
    99+
    2023-01-30
    Typescript数据结构哈希表 Typescript数据结构
  • C++哈希表之线性探测法怎么实现
    今天小编给大家分享一下C++哈希表之线性探测法怎么实现的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、哈希表-线性探测法理...
    99+
    2023-06-30
  • C++模拟实现string的方法详解
    目录1.string 成员变量2.构造函数3.拷贝构造、赋值重载和析构函数1.拷贝构造2.赋值重载3.析构函数4.访问成员变量5.遍历1.下标+【】2.迭代器(iterator)3....
    99+
    2022-11-13
    C++实现string C++ string
  • Java数据结构之实现哈希表的分离链接法
    哈希表的分离链接法 原理 Hash Table可以看作是一种特殊的数组。他的原理基本上跟数组相同,给他一个数据,经过自己设置的哈希函数变换得到一个位置,并在这个位置当中放置该数据。哦...
    99+
    2024-04-02
  • vue长列表优化之虚拟列表实现过程详解
    目录前言实现原理实现代码总结 前言 应用场景:后台一次性发送上千条或更多数据给前台 场景模拟:用户发起一个请求,后台发送了10w条数据 使用虚拟列表之前:前台需要生成10w...
    99+
    2024-04-02
  • C++初阶之list的模拟实现过程详解
    list的介绍 list的优点: list头部、中间插入不再需要挪动数据,O(1)效率高 list插入数据是新增节点,不需要增容 list的缺点: ...
    99+
    2024-04-02
  • C++模拟实现vector的方法
    今天小编给大家分享一下C++模拟实现vector的方法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1. 模拟实现vecto...
    99+
    2023-07-02
  • React虚拟列表的实现方法
    这篇文章给大家分享的是有关React虚拟列表的实现方法的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1.背景在开发过程中,总是遇到很多列表的显示。当上数量级别的列表渲染于浏览器,终会导致浏览器的性能下降。如果数据...
    99+
    2023-06-15
  • Golang哈希算法实现配置文件的监控功能详解
    目录Golang hash256实现包使用sha256.New()使用sha256.Sum256()函数监控配置文件变化获取配置hash值总结SHA(secure hashing a...
    99+
    2023-03-08
    Go哈希算法监控配置文件 Go哈希算法
  • C语言用栈模拟实现队列问题详解
    目录题目描述题目链接思路分析代码实现题目描述 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)。 你只能使用标准的栈操作...
    99+
    2024-04-02
  • C++ vector类的模拟实现方法
    vector和string虽然底层都是通过顺序表来实现的,但是他们利用顺序表的方式不同,string是指定好了类型,通过使用顺序表来存储并对数据进行操作,而vector是利用了C++...
    99+
    2024-04-02
  • C++中vector的模拟实现实例详解
    目录vector接口总览 默认成员函数 构造函数 拷贝构造 赋值重载 析构函数 迭代器相关函数 begin和end 容量相关函数 size和capacity reserve resi...
    99+
    2024-04-02
  • C++数组模拟之单链表与双链表和栈和队列的实现过程
    目录前引一、数组模拟实现单链表1.1 数组模拟的单链表解析1.2 数组模拟实现单链表例题二、数组模拟实现双链表2.1 数组模拟实现双链表解析2.2 数组模拟实现双链表例题三、数组模拟...
    99+
    2023-02-13
    C++数组模拟单链表 C++数组模拟双链表 C++数组模拟队列
  • C语言 数据结构之数组模拟实现顺序表流程详解
    目录线性表和顺序表线性表顺序表静态顺序表动态顺序表代码已经放在Gitee上,需要可以小伙伴可以去看看 用C语言数组模拟实现顺序表 Gitee 线性表和顺序表 线性表 线性表(line...
    99+
    2024-04-02
  • C++ STL容器详解之红黑树部分模拟实现
    目录一、红黑树的概念二、红黑树的性质三、红黑树节点的定义四、红黑树结构 五、 红黑树的插入操作六、代码总结一、红黑树的概念 红黑树(Red Black Tree),是在计算机科学中用...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作