[译]C语言实现一个简易的Hash table(7)

上一章我们讲了如何根据需要动态设置hash表的大小,在第四章中,我们使用了双重哈希来解决hash表的碰撞,其实解决方法有很多,这一章我们来介绍下其他方法。
本章将介绍两种解决hash表碰撞的方法:
- 拉链法
- 开放地址法
拉链法
使用拉链法,每一个bucket都会包含一个链接表,当发生碰撞时,就会将该记录插入在该位置的链接表后面,步骤如下:
插入时:通过
hash函数获取到要插入的位置,如果该位置是空的,就直接插入,如果该位置不是空的,就插入在链接表的后面搜索时:通过
hash函数获取到key对应的位置,遍历链接表,判断key是不是搜索的key,如果是,则返回value,否则返回NULL删除时:通过
hash函数获取到key对应的位置,遍历链接表,找到需要删除的key,如果找到,则将该key对应的记录从链接表中删除,如果链接表中只有一条记录,则将该位置置为NULL
拉链法的优点是实现起来简单,但是空间利用率低。每个记录必须存储指向链接表中下一个记录的指针,如果没有记录,则指向NULL,这种方法会浪费一些空间来存储额外的指针。
开放地址法
开放地址法能解决拉链法空间利用率低的问题,发生碰撞时,碰撞的记录将放置在hash表中的其他bucket中,存放的位置是根据预先确定的规则选择的,以便在搜索记录时可以重复该规则,有如下几种规则:
线性探查
当发生碰撞时,就会递增索引,将记录插入在下一个可用的索引中,方法如下:
插入时:通过
hash函数找到插入的位置的索引,如果这个位置是空的,直接插入,如果不为空,就递增索引,直到找到索引指向的位置是空的为止,然后执行插入搜索时:通过
hash函数找到搜索的记录的索引,每次递增索引,并比较索引指向的值是否是要搜索的值,如果索引指向的是空,则返回NULL删除时:通过
hash函数找到删除的记录的索引,每次递增索引,直到找到要删除的那个key后执行删除
线性探测提供了良好的缓存性能,但是存在碰撞后遍历次数多的问题。将发生碰撞的key放入下一个可用的bucket中可能导致后面插入记录也要往后插,就需要多次迭代。
二次探查
二次探查法和先行探查类似,不同的是,发生碰撞后,我们会将记录插入在如下的序列中:i, i + 1, i + 4, i + 9, i + 16, ...,i代表通过hash函数获取到的索引,具体步骤如下:
插入时:通过
hash函数找到插入的索引,通过遍历上面的序列直到找到一个空的或已被删除的索引位置,执行插入搜索时:通过
hash函数找到key的索引,遍历上面的序列,将序列上的key与搜索的key对比,如果相等,则返回value,否则返回NULL删除时:因为我们无法判断要删除的项是不是
碰撞链上的,所以我们不能直接删除该条记录,只能把它标记为已删除
二次探查法减少发生碰撞后遍历的次数,并且仍然提供了不错的缓存性能。
双重hash
双重hash旨在解决碰撞后遍历次数多的问题。使用两次hash函数为插入的记录选择新的索引,这个索引会均匀的分布在整个表中,该方法虽然解决了上述问题,但也失去了缓存特性,双重hash是实际项目中常见的冲突管理方法,也是我们在本教程中实现的方法。
上一章:设置hash表大小
原文地址:https://github.com/jamesroutley/write-a-hash-table/tree/master/07-appendix
[译]C语言实现一个简易的Hash table(7)的更多相关文章
- [译]C语言实现一个简易的Hash table(4)
上一章我们解释了Hash table中最重要的hash函数,并用伪代码和C语言实现了一个我们自己的hash函数,hash函数中碰撞是无法避免的,当发生碰撞时我们改如何有效的处理呢?这章我们就来讲解下. ...
- [译]C语言实现一个简易的Hash table(1)
说明 Hash table翻译过来就是Hash表,是一种提供了类似于关联数组的数据结构,可以通过key执行搜索.插入和删除操作.Hash表由一些列桶(buckets)组成,而每一个bucket都是由k ...
- [译]C语言实现一个简易的Hash table(3)
上一章,我们讲了hash表的数据结构,并简单实现了hash表的初始化与删除操作,这一章我们会讲解Hash函数和实现算法,并手动实现一个Hash函数. Hash函数 本教程中我们实现的Hash函数将会实 ...
- [译]C语言实现一个简易的Hash table(2)
上一章,简单介绍了Hash Table,并提出了本教程中要实现的几个Hash Table的方法,有search(a, k).insert(a, k, v)和delete(a, k),本章将介绍Hash ...
- [译]C语言实现一个简易的Hash table(5)
上一章中,我们使用了双重Hash的技术来处理碰撞,并用了C语言实现,贲张我们将实现Hash表中的插入.搜索和删除接口. 实现接口 我们的hash函数将会实现如下的接口: // hash_table.h ...
- [译]C语言实现一个简易的Hash table(6)
上一章中,我们实现了Hash表中的插入.搜索和删除接口,我们在初始化hash表时固定了大小为53,为了方便扩展,本章将介绍如何修改hash表的大小. 设置Hash表大小 现在,我们的hash表是固定大 ...
- 用Java语言编写一个简易画板
讲了三篇概博客的概念,今天,我们来一点实际的东西.我们来探讨一下如何用Java语言,编写一块简易的画图板. 一.需求分析 无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目 ...
- 用java语言写一个简易版本的登录页面,包含用户注册、用户登录、用户注销、修改密码等功能
package com.Summer_0421.cn; import java.util.Arrays; import java.util.Scanner; /** * @author Summer ...
- PHP内核探索之变量(3)- hash table
在PHP中,除了zval, 另一个比较重要的数据结构非hash table莫属,例如我们最常见的数组,在底层便是hash table.除了数组,在线程安全(TSRM).GC.资源管理.Global变量 ...
随机推荐
- MyBatis基本配置和实践(五)
第一步:创建一个Maven工程 第二步:编辑Maven工程的pom.xml,引入mybatis-generator-maven-plugin <?xml version="1.0&qu ...
- Attribute+Reflection,提高代码重用
这篇文章两个目的,一是开阔设计的思路,二是实例代码可以拿来就用. 设计的思路来源于<Effective c#>第一版Item 24: 优先使用声明式编程而不是命令式编程.特别的地方是,希望 ...
- DockerFile简介以及使用
DockerFile是用来构建docker镜像的构建文件,是有一系列命令和参数构成的脚本 构建的三步骤:编写dockerfile文件→build构建→docker run dockerfile保留字指 ...
- CentOS随笔 - 修改CentOS7的IP
前言 转帖请注明出处: http://www.cnblogs.com/Troy-Lv5/ 在使用CentOS时经常我们需要固定一个IP, 因为服务器嘛,不固定IP. 难道每次都要配置开发环境的地址.? ...
- CSS加载性能优化
将首屏页面要用到的CSS文件,放在页面头部加载,其他模块的CSS可以使用异步加载:loadCSS 和 Preload. 关于preload,推进2篇文章给大家看下: 1.通过rel="pre ...
- jq实现拖拽
$("body").delegate( ".msg-layer",{ mousedown: function (e) { var el = $(".m ...
- Eclipse 连接真实机器调试
一.手机开启调试模式 二.安装adb.exe 1.确信 \android-sdk-windows\tools\下有 adb.exe AdbWinApi.dll AdbWinUsbApi ...
- CF219D Choosing Capital for Treeland
嘟嘟嘟 树形dp. 首先一个很常规的想法就是如果u到v有一条边,那么建立cost(u, v) = 0, cost(v, u) = 1的两条边. 可以两遍dfs. 先任选一个点作为根节点,第一遍从下往上 ...
- 23、springboot与缓存(1)
一.JSR107 Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry. 1.CachingPro ...
- php编译安装报错
Cannot find OpenSSL's <evp.h> 解决方法: 下载openssl-1.1.0h.tar 包 [root@localhost ~]# cd openssl-1.1 ...