当前位置: 首页 > article >正文

哈希:闭散列的开放定址法

我还是曾经的那个少年


1.概念

通过其要存储的值与存储的位置建立映射关系。

如:基数排序也是运用了哈希开放定址法的的思想。

弊端:仅适用于数据集中的情况

 2.开放定址法

 问题:按照上述哈希的方式,向集合插入数据为44,会出现什么问题呢?

哈希冲突。

即:不同关键字通过相同的哈希方式计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

3.哈希冲突的解决方式

闭散列和开散列。(这次主要讲闭散列)

3.1闭散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去那如何寻找下一个空位置呢?

 1.线性探测

比如上面的场景中,现在需要插入元素44,先通过哈希函数计算哈希地址,hashAddr4,因此44理论上应该插在该位置,但是该位置已经放了值为4的元素,即发生哈希冲突。

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止
  • 插入
    • 通过哈希函数获取待插入元素在哈希表中的位置
    • 如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突, 使用线性探测找到下一个空位置,插入新元素

  • 删除

        采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影

        响其他元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。

        因此线性探测采用标记的伪删除法来删除一个元素

通过添加枚举常量,来标记相应位置上是否存在或为空等状态。

enum STASTE
{EXIST,EMPTY,DELETE
};
template<class K, class V>
struct HashData
{pair<K, V> _kv;STASTE _state = EMPTY;
};

线性探测:找到空(状态为:EMPTY),没找到才返回

3.1.1扩容问题  

4.插入的key值为字符串

我们需要将该字符串转换成相应的整数再进行映射。字符哈希算法。

 5.模拟实现

//整型(同时还解决了负数和浮点数的问题)
template<class K>
struct DefaultHashFunc
{size_t operator()(const K& key){return (size_t)key;}
};//模板特化
template<>
struct DefaultHashFunc<string>
{size_t operator()(const string& str){// BKDRsize_t hash = 0;for (auto ch : str){hash *= 131;hash += ch;}return hash;}
};
namespace open_address
{enum STASTE{EXIST,EMPTY,DELETE};template<class K, class V>struct HashData{pair<K, V> _kv;STASTE _state = EMPTY;};template<class K, class V, class HashFunc = DefaultHashFunc<K>>class HashTable{public:HashTable(){_table.resize(10);}bool insert(const pair<K, V>& kv){//是否存在if (find(kv.first))return false;//扩容if (_n * 10 / _table.capacity() >= 7){//类似现代写法HashTable<K, V, HashFunc> tmp;tmp.getTable().resize(_table.capacity() * 2);//遍历旧数据,重新映射到新空间for (size_t i = 0; i < _table.size(); i++){if (_table[i]._state == EXIST)tmp.insert(_table[i]._kv);}_table.swap(tmp.getTable());}//线性探索HashFunc hf;size_t hashi = hf(kv.first) % _table.size();while (_table[hashi]._state == EXIST){++hashi;hashi %= _table.size();}_table[hashi]._kv = kv;_table[hashi]._state = EXIST;++_n;return true;}HashData<const K, V>* find(const K& key){HashFunc hf;//先找到相应的映射位置,是则返回,否则继续往后查找到空为止size_t hashi = hf(key) % _table.size();while (_table[hashi]._state != EMPTY){if (hf(_table[hashi]._kv.first) == hf(key))return (HashData<const K, V>*) & _table[hashi];++hashi;hashi %= _table.size();}return nullptr;}bool erase(const K& key){HashData<const K, V>* ret = find(key);if (ret == nullptr || ret->_state == DELETE)return false;ret->_state = DELETE;--_n;return true;}vector<HashData<K, V>>& getTable(){return _table;}private:vector<HashData<K, V>> _table;size_t _n = 0;	//记录存储有效数据个数};
}

感觉不错的可以点赞+收藏咯!!

谢谢大家

http://www.lryc.cn/news/2396020.html

相关文章:

  • Unity-QFramework框架学习-MVC、Command、Event、Utility、System、BindableProperty
  • FPGA实现CNN卷积层:高效窗口生成模块设计与验证
  • LeetCode 3068.最大节点价值之和:脑筋急转弯+动态规划(O(1)空间)
  • 2.2HarmonyOS NEXT高性能开发技术:编译优化、内存管理与并发编程实践
  • BLIP-2
  • 【Go-6】数据结构与集合
  • 支持向量机(SVM)例题
  • SQL中各个子句的执行顺序
  • PHP下实现RSA的加密,解密,加签和验签
  • 本地部署消息代理软件 RabbitMQ 并实现外部访问( Windows 版本 )
  • 每日c/c++题 备战蓝桥杯(P2240 【深基12.例1】部分背包问题)
  • Java异步编程:CompletionStage接口详解
  • Java后端接受前端数据的几种方法
  • Oracle OCP认证的技术定位怎么样?
  • powershell7.5@.net环境@pwsh7.5在部分windows10系统下的运行问题
  • 基于微信小程序的垃圾分类系统
  • CSS3 渐变、阴影和遮罩的使用
  • Spring Boot 全局配置文件优先级
  • 流媒体基础解析:视频清晰度的关键因素
  • grid网格布局
  • C#数字金额转中文大写金额:代码解析
  • Vehicle HAL(2)--Vehicle HAL 的启动
  • JS中的函数防抖和节流:提升性能的关键技术
  • Android Compose开发架构选择指南:单Activity vs 多Activity
  • 【Netty系列】Reactor 模式 1
  • vue3 el-input type=“textarea“ 字体样式 及高度设置
  • 并发解析hea,转为pdf格式
  • 【C语言】详解 指针
  • RabbitMQ仲裁队列高可用架构解析
  • 刚出炉热乎的。UniApp X 封装 uni.request