上一章,我们讲了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. spring boot(3)-Rest风格接口

    Rest接口 虽然现在还有很多人在用jsp,但是其实这种动态页面早已过时,现在前端流行的是静态HTML+ rest接口(json格式).当然,如果是单台服务器,用动态还是静态页面可能没什么很大区别,但 ...

  2. google学习

    https://developers.google.com/machine-learning/crash-course/ https://developers.google.com/machine-l ...

  3. Software Testing Techniques LAB 01: test Junit and Eclemma

    1. Installing  1. Install Junit and hamcrest First, I download the Junit-4.12.jar and hamcrest-core- ...

  4. Software Testing Techniques Homework 2

    Problem 1 1. The fault is i > 0, it should be  i >= 0, because if the case is x = [0], y= 0, w ...

  5. Python学习---Django的request扩展[获取用户设备信息]

    关于Django的request扩展[获取用户设备信息] settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] STATICFILES_DIRS ...

  6. August 06th 2017 Week 32nd Sunday

    No words are necessary between two loving hearts. 两颗相爱的心之间不需要言语. No, I don't think so. Words may be ...

  7. c++计算器后续(4)

    自娱自乐: 大概是终于做到没做完的部分了,第三步助教学长的评论还没去改,感觉那个把读取文件放到Scan里面比较麻烦,其他大概还好.以上. 文件读写: 先是原来的残留问题,都是和fstream :: o ...

  8. 021.6 IO流 练习

    #######################################################################################获取指定目录下所有的.ja ...

  9. 5、Python,enumerate用法

    1.enumerate()是python的内置函数 2.对于一个可迭代(iterable)/可遍历的对象(如列表,字符串),enumerate将其组成一个索引序列,利用它可以同时获得索引和值 3.多用 ...

  10. MySQL ENCODE和DECODE加密列

    用法: ENCODE(str,passwd) DECODE(str,passwd) INSERT INTO test_log_1 VALUES (30,ENCODE("30",&q ...