有趣的算法(三)——Hash算法
有趣的算法(三)——Hash算法
(原创内容,转载请注明来源,谢谢)
一、Hash算法
近期看到用hash实现基于hash的简单的小型数据库(传统大型数据库用的都是B+tree),感觉挺感兴趣,故先研究hash算法,近期会用hash实现一个小的数据库。
Hash表(Hash Table)又称为散列表,通过把关键字key映射到数组的一个位置,来访问记录。这个映射函数称为hash函数,存放记录的数组称为hash表。
1、hash函数
作用是把任意长度的输入,通过hash算法得到固定函数的输出,输出的内容就是hash值。这种映射是一种压缩映射,即输出的内容占用的存储空间可能会小于输入的内容。因此不同的key经过hash可能会得到同一个结果。
好的hash使每个关键字均匀分布到hash表的任一个位置,并于其他已被散列到hash表中的关键字不冲突。
根据关键字的不同,可能设计不同的hash算法。
2、直接取余法——适用整数
用关键字k除以hash表的大小m取余,得到的结果即为结果。
h(k) = k mod m。例如哈希表大小20,关键字是30,则h(20) = 10。
3、乘积取整法——适用小数
使用关键字k乘以一个常数A(0<A<1),取出kA的小数部分,乘以hash表的大小,向下取整即可。
hash(k)= floor(m*(kA mod 1)),kA mod 1表示kA的小数部分,floor是取整操作。
4、ASCII码处理法——适用字符串
字符串无法进行取余或者取整,则可以使用把每个字符取整求和,再按照上面的方法对结果进行处理。
5、经典hash算法:DJB hashfunction(俗称Times33)
该算法效率和随机性很高,运用广泛,包括Perl、Berkeley DB、Apache、MFC、STL、PHP等的Hash,都用的此算法。
该算法的核心是将每一位都乘以33,再加上原来的值。
代码实现方法(C语言)如下:
unsignedlong time33(char const *str, int len)
{
unsigned long hash = 0;
for (int i = 0; i < len; i++) {
hash = ((hash <<5) + hash) + (unsigned long) str[i];
}
return hash;
}
其中,采用<<方式,即将值乘以2的5次方(32)。
二、Hash表
1、算法
hash表的时间复杂的O(1),即key通过hash函数,找到值所在的地方。要构建hash表必须创建一个足够大的数组用于存放数据,另外还需要一个hash函数把关键字key映射到数组的某个位置。具体实现步骤如下:
1)创建一个固定大小的数组用于存放数据。
2)设计hash函数。
3)通过hash函数把关键字映射到数组的某个位置,并在此位置上进行数据存取。
2、用PHP实现hash表
1)定义hashtable类
<?php
classHashTable{
private $buckets;
private $size = 10;
public function __construct($size = 0){
if($size > 0){
$this->size =$size;
}
$this->buckets = new SplFixedArray($this->size);
}
}
hash表采用定长来保存数据,其中buckets是一个数组,其key是hash函数的结果,值用于存放原值。buckets的数组不采用array,而采用php的SPL中的SplFixedArray,该类要求初始化的时候需要一个定长,并且数组的key只能是整数。这个数组更接近原生的c语言,效率更高。
2)定义hash函数(Times33,字符串取ascii,结果和10)
private functionhashFunction($string){
$len = strlen($string);
$hash = 0;
for($i=0;$i<$len;$i++){
$hash += $hash<<5+ ord($key[$i]);
$hash %=$this->size;
}
return $hash;
}
3)增删改查
//新增,相同则覆盖
publicfunction insert($key, $val){
$key= $this->hashFunction($key);
$this->buckets[$key]= $val;
return$this->buckets;
}
//查找
publicfunction search($key){
$key= $this->hashFunction($key);
return$this->buckets[$key];
}
//删除
publicfunction delete($key){
$key= $this->hashFunction($key);
if(isset($this->buckets[$key])){
unset($this->buckets[$key]);
}
}
//修改,不存在则新增
publicfunction update($key, $val){
$key= $this->hashFunction($key);
$this->buckets[$key]= $val;
return$this->buckets;
}
3、Hash表冲突问题
因为key是通过一定的计算得到的结果,且通常传入的key和计算的key不是一一对应的,因此可能会存在冲突。要解决冲突,可以使用拉链法,即将所有相同的值放在一个链表中。此时,除了需存储value,还要存储key和下一个value的位置。
因此,需要引入一个新的类:
classHashNode{
public $key;
public $value;
public $next;
public function __construct($key,$value, HashNode $next = null){
$this->key = $key;
$this->value=$value;
$this->next =$next;
}
}
此时,相应的操作变化如下:
//新增,链表方式,重复则添加到相应的链表
publicfunction insert($key, $val){
$key= $this->hashFunction($key);
if(isset($this->buckets[$key])){
$node= new HashNode($key, $val, $this->buckets[$key]);
}else{
$node = new HashNode($key, $val);
}
unset($this->buckets[$key);
$this->buckets[$key]= $node;
return$this->buckets;
}
//查找
publicfunction search($key){
$key= $this->hashFunction($key);
if(!isset($this->buckets[$key])){
returnnull;
}
$current= $this->buckets[$key];
while(isset($current)){
if($current->key== $key){
return$current->value;
}
$current= $current->next;
}
returnnull;
}
//修改,不存在则返回false
publicfunction update($key, $val){
$key= $this->hashFunction($key);
if(!isset($this->buckets[$key])){
returnfalse;
}
$current= $this->buckets[$key];
$isSuccess= false;
while(isset($current)){
if($current->key== $key){
$current->value= $val;
$isSuccess= true;
break;
}
$current= $current->next;
}
return$isSuccess;
}
——written by linhxx 2017.08.18
- 了解ASP.NET MVC几种ActionResult的本质:JavaScriptResult & JsonResult
- 学习SVM(五)理解线性SVM的松弛因子
- 了解ASP.NET MVC几种ActionResult的本质:EmptyResult & ContentResult
- 可视化(番外篇)——SWT总结
- 新年必看!预测2018年将是区块链爆发的行情
- 探秘Tomcat(一)——Myeclipse中导入Tomcat源码
- 解决Myeclipse下Debug出现Source not found以及sql server中导入数据报错
- Hadoop阅读笔记(七)——代理模式
- 认识ASP.NET MVC的5种AuthorizationFilter
- 2017十大“最差”密码出炉
- SVG图形绘制入门第一弹
- 使用自定义标记来构建页面
- ASP.NET MVC集成EntLib实现“自动化”异常处理[实例篇]
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 贪心算法-分数背包问题(Python实现)
- 为什么GNE 不做全自动提取列表页的功能
- 百度地图开发如何自定义控件(无敌的解决办法)
- 百度地图如何创建一个属于自己的地图,附加到项目中?
- FreeRTOS系列第9篇---FreeRTOS任务概述基础篇
- 图书管理系统(四)图书管理系统实战(2)
- 源码分析之 FactoryBean接口不为人知的秘密
- 图书管理系统(三)图书管理系统实战(1)
- 图书管理系统(二)整合 SSM,你学会了么
- CellChat:细胞间相互作用分析利器
- 我对一类常考算法面试题的详细分析
- Python 面向对象编程(上篇)
- 基于TencentOS-tiny实现PM2.5传感器(攀藤PMSA003)数据解析思路及实现
- Centos7搭建SVN+Apache+iF.SVNAdmin实现web管理SVN
- 安卓最后一个大题复习