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

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

我还是曾经的那个少年


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.xdnf.cn/news/763399.html

相关文章:

  • #14 【Kaggle】 Drawing with LLMs 金牌方案赏析
  • 简析PointNet++
  • leetcode0404. 左叶子之和-easy
  • 对选择基于模型编程(MBD)的工作对职业发展影响的讨论 (2025)
  • 【Bluedroid】蓝牙启动之 l2c_init 源码解析
  • 字符函数和字符串函数(1)
  • 上位机知识篇---直接无线数据通信
  • 线程与进程
  • 【Dv3Admin】系统视图用户管理API文件解析
  • Redis 架构设计
  • Kali Linux从入门到实战:系统详解与工具指南
  • Fréchet Inception Distance(FID)
  • ubuntu系统更换镜像源
  • [GESP202412 五级] 奇妙数字
  • java 多线程中的volatile关键字作用
  • 【JavaScript-Day 28】告别繁琐循环:`forEach`, `map`, `filter` 数组遍历三剑客详解
  • c++之循环
  • java CountDownLatch‌
  • 题海拾贝:压缩字符串
  • 详解鸿蒙开发如何上传三方库到ohpm仓库
  • 【Dv3Admin】系统视图系统配置API文件解析
  • 017搜索之深度优先DFS——算法备赛
  • java ExecutorService线程池使用(ExecutorService/Completable异步+ExecutorService线程池)
  • Office安装包2024版
  • ck-editor5的研究 (4):初步使用 CKEditor5 的插件功能
  • 72.编辑用户消息功能之前端实现
  • PCB制作入门
  • 开始通信之旅-----话题通信
  • 关于 java:4. 异常处理与调试
  • C#数字图像处理(二)