上一章,我们讲了hash表的数据结构,并简单实现了hash表的初始化与删除操作,这一章我们会讲解Hash函数和实现算法,并手动实现一个Hash函数。

Hash函数

本教程中我们实现的Hash函数将会实现如下操作:

  • 输入一个字符串,然后返回一个0m(Hash表的大小)的数字
  • 为一组平常的输入返回均匀的bucket索引。如果Hash函数不是均匀分布的,就会将多个记录插入到相同的bucket中,这就回提高冲突的几率,而这个冲突就会影响到我们的Hash表的效率。

Hash算法

我们将会设计一个普通的字符串Hash函数,在伪代码中表示如下:

function hash(string, a, num_buckets):
hash = 0
string_len = length(string)
for i = 0, 1, ..., string_len:
hash += (a ** (string_len - (i+1))) * char_code(string[I])
hash = hash % num_buckets
return hash

这个Hash函数主要分为两步:

  1. 将字符串转为大整型
  2. 通过取余数mod m将整数的大小减小到固定范围

变量a是一个素数,并且要大于英文字母,我们正在散列ASCII字符串,其字母大小为128,因此我们应该选择大于此的素数。

char_code这个函数会返回字母对应的整数,使用的是ASCII中的字母。

如下使用这个Hash函数

hash("cat", 151, 53)

// 函数拆解
hash = (151**2 * 99 + 151**1 * 97 + 151**0 * 116) % 53
hash = (2257299 + 14647 + 116) % 53
hash = (2272062) % 53
hash = 5

如果改变a我们会得到不同的结果:

hash("cat", 163, 53) = 3

代码实现

// hash_table.c
static int ht_hash(const char* s, const int a, const int m) {
long hash = 0;
const int len_s = strlen(s);
for (int i = 0; i < len_s; i++) {
hash += (long)pow(a, len_s - (i+1)) * s[i];
hash = hash % m;
}
return (int)hash;
}

什么是冲突?

理想中的散列函数返回的结果都是均匀分布的,但是,对于任意一个散列函数,总会有一些输入经过散列后,得到相同的值。如果要找到这组输入,我们就需要测试大量的输入数据。

因为上面提到的有不好的输入存在,意味着所有输入都没有完美的散列函数。所以在设计散列函数时,针对预期输入,我们的散列函数需要表现最好。

不好的输入也存在安全问题,如果某个恶意用户向哈希表提供了一组冲突密钥,那么搜索这些密钥将比正常情况(O(1))花费更长时间(O(n))。这可以用作针对以哈希表为基础的系统(例如DNS和某些Web服务)的拒绝服务攻击。

上一章:Hash table数据结构

下一章:冲突处理


原文地址:https://github.com/jamesroutley/write-a-hash-table/tree/master/03-hashing

[译]C语言实现一个简易的Hash table(3)的更多相关文章

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

    上一章我们解释了Hash table中最重要的hash函数,并用伪代码和C语言实现了一个我们自己的hash函数,hash函数中碰撞是无法避免的,当发生碰撞时我们改如何有效的处理呢?这章我们就来讲解下. ...

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

    说明 Hash table翻译过来就是Hash表,是一种提供了类似于关联数组的数据结构,可以通过key执行搜索.插入和删除操作.Hash表由一些列桶(buckets)组成,而每一个bucket都是由k ...

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

    上一章,简单介绍了Hash Table,并提出了本教程中要实现的几个Hash Table的方法,有search(a, k).insert(a, k, v)和delete(a, k),本章将介绍Hash ...

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

    上一章中,我们使用了双重Hash的技术来处理碰撞,并用了C语言实现,贲张我们将实现Hash表中的插入.搜索和删除接口. 实现接口 我们的hash函数将会实现如下的接口: // hash_table.h ...

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

    上一章我们讲了如何根据需要动态设置hash表的大小,在第四章中,我们使用了双重哈希来解决hash表的碰撞,其实解决方法有很多,这一章我们来介绍下其他方法. 本章将介绍两种解决hash表碰撞的方法: 拉 ...

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

    上一章中,我们实现了Hash表中的插入.搜索和删除接口,我们在初始化hash表时固定了大小为53,为了方便扩展,本章将介绍如何修改hash表的大小. 设置Hash表大小 现在,我们的hash表是固定大 ...

  7. 用Java语言编写一个简易画板

    讲了三篇概博客的概念,今天,我们来一点实际的东西.我们来探讨一下如何用Java语言,编写一块简易的画图板. 一.需求分析 无论我们使用什么语言,去编写一个什么样的项目,我们的第一步,总是去分析这个项目 ...

  8. 用java语言写一个简易版本的登录页面,包含用户注册、用户登录、用户注销、修改密码等功能

    package com.Summer_0421.cn; import java.util.Arrays; import java.util.Scanner; /** * @author Summer ...

  9. PHP内核探索之变量(3)- hash table

    在PHP中,除了zval, 另一个比较重要的数据结构非hash table莫属,例如我们最常见的数组,在底层便是hash table.除了数组,在线程安全(TSRM).GC.资源管理.Global变量 ...

随机推荐

  1. 京东原来你运用的这玩意,不错,我也要!! ContainerDNS

    转自社区 ContainerDNS 本文介绍的 DNS 命名为 ContainerDNS,作为京东商城软件定义数据中心的关键基础服务之一,具有以下特点: 分布式,高可用 自动发现服务域名 后端探活 易 ...

  2. 创建基于 AFS 的 Docker 容器卷

    标准的 Docker 容器卷一般是位于 Docker 主机上的一个本地目录.在这样的配置下,容器必须依赖于一台特定的主机,因此使得容器的迁移和扩展变得困难.通过使用容器卷插件,能让容器访问独立于主机的 ...

  3. POP动画[2]

    POP动画[2] 1:定制控制器间的转场动画. 源码有点多-_-!! // // RootViewController.h // Animation // // Copyright (c) 2014年 ...

  4. Azure之旅

    http://www.microsoft.com/web/downloads/platform.aspx http://www.microsoft.com/en-us/download/details ...

  5. August 13th 2017 Week 33rd Sunday

    The best accessory a girl can own is confidence. 女生最好的饰品就是自信. Only when we have our own ideas and on ...

  6. 【转】iphone 输入/输出流异步读写数据

    原文:iphone 输入/输出流异步读写数据 分类: iphone2012-05-30 14:50 2484人阅读 评论(1) 收藏 举报 iphoneattributesinterfacepaths ...

  7. echarts柱状图,改变柱状颜色

    在使用echarts产生的柱状图中,有时候自动产生的颜色大不如人意,可以通过以下参数进行修改. series : [ { name:'天数', type:'bar', stack: '天', data ...

  8. Codeforces Round #440 (Div. 2)【A、B、C、E】

    Codeforces Round #440 (Div. 2) codeforces 870 A. Search for Pretty Integers(水题) 题意:给两个数组,求一个最小的数包含两个 ...

  9. 对json的理解?

    回答一: a.JSON对象:以 ”{“ 开始,以 ”}” 结束,里面则是一系列的键(key)值(value)对,键和值用 ”:” 分开,每对键值对之间用 ”,” 分开.参考以下语法: {key1:va ...

  10. Spring(十一)之AOP

    Spring 框架的一个关键组件是面向方面的编程(AOP)框架.面向方面的编程需要把程序逻辑分解成不同的部分称为所谓的关注点.跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于 ...