引言
将任意长度的二进制字符串映射为定长二进制字符串的映射规则我们称为散列(hash)算法,又叫哈希(hash)算法,而通过原始数据映射之后得到的二进制值称为哈希值。哈希表(hash表)结构是哈希算法的一种应用,也叫散列表。用的是数组支持按照下标随机访问数据的特性扩展、演化而来。可以说没有数组就没有散列表。
哈希
哈希(Hash)也称为散列,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,这个输出值就是散列值。
哈希表
哈希表(Hash table,也叫散列表),根据关键码值(Key Value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录。以加快查找的速度。这个是映射函数叫做散列函数,存放记录的数组叫做散列表。
散列表是算法在时间和空间上作出权衡的经典例子
如果没有内存限制,我们可以直接将键作为(可能是一个超大的)数组的索引,那么所有查找操作只需要访问内存一次即可完成。但这种理想情况不会经常出现,因为当键很多时需要的内存太大。另一方面,如果没有时间限制,我们可以使用无序数组并进行顺序查找,这样就只需要很少的内存。而散列表则使用了适度的空间和时间并在这两个极端之间找到了一种平衡。事实上,我们不必重写代码,只需要调整散列算法的参数就可以在空间和时间之间作出取舍。我们会使用概率论的经典结论来帮组我们选择适当的参数。
使用Hash的查询算法分为两步
1、用Hash函数将被查找的键转化为数组的一个索引。 理想情况下,不同的键都能转化为不同的索引值。当然这个只是理想情况,所以我们需要面对两个或者多个键都会散列到相同的索引值的情况。
2、处理碰撞冲突
哈希算法主要特点
哈希算法的核心应用
构造哈希函数的常规方法:数据分析法、直接寻址法、除留取取余法、折叠法、随机法、平方取中法;
Go语言Hash算法
哈希表的基本介绍
散列表(Hash table,也叫哈希表),是根据关键值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置
来访问记录,以加快查找的速度。这个映射函数叫散列函数,存放记录的数组叫做散列表。
有一个公司,当有新的员工来报道时,要求将该员工的信息加入(ID、性别、年龄、住址…)当输入员工该员工的ID时,要求
查找到该员工的所有信息。
1)要求:
1、不使用数据库,尽量节省内存,速度越快越好===》哈希表(散列)
2、添加时,保证按照雇员的ID从低到高插入
package main
import (
"fmt"
)
//定义emp
type Emp struct {
Id int
Name string
Next *Emp
}
//方法待定
//定义EmpLink
//我们这里的Emplink不带表头,即第一个节点存放雇员
type EmpLink struct {
Head *Emp
}
//方法待定
//1、添加员工的方法,保证添加时,编号从小到大
func (this *EmpLink) Insert(emp *Emp) {
cur := this.Head //辅助指针
var pre *Emp = nil //这是一个辅助指针pre在cur 前面
//如果当前的EmpLink就是一个空链表
if cur == nil {
this.Head = emp //完成
return
}
//如果是一个空链表,给emp找到对应的位置并插入
//思路是让cur 和 emp 比较,然后让pre保持在cur 前面
for {
if cur != nil {
//比较
if cur.Id > emp.Id {
//找到位置
break
}
pre = cur //保证同步
cur = cur.Next
} else {
break
}
}
//退出时,我们看下是否将emp添加到链表最后
pre.Next = emp
emp.Next = cur
}
//显示链表的信息
func (this *EmpLink) ShowLink(no int) {
if this.Head == nil {
fmt.Printf("链表%d为空\n", no)
return
}
//变量当前的链表,并显示数据
cur := this.Head //辅助的指针
for {
if cur != nil {
fmt.Printf("链表%d 雇员id=%d 名字=%s->", no, cur.Id, cur.Name)
cur = cur.Next
} else {
break
}
}
fmt.Println() //行换处理
}
//定义hashtable,含有一个链表数组
type HashTable struct {
LinkArr [7]EmpLink
}
//给HashTable 编写Insert 雇员的方法
func (this *HashTable) Insert(emp *Emp) {
//使用散列函数,确定将该雇员添加到哪个链表
linkNo := this.HashFun(emp.Id)
//使用对应的链表添加
this.LinkArr[linkNo].Insert(emp)
}
//编写方法,显示hashtable的所有雇员
func (this *HashTable) ShowAll() {
for i := 0; i < len(this.LinkArr); i++ {
this.LinkArr[i].ShowLink(i)
}
}
//编写一个散列方法
func (this *HashTable) HashFun(id int) int {
return id % 7 //得到一个值,就是对于的链表下标
}
func main() {
key := ""
id := 0
name := ""
var hashTable HashTable
for {
fmt.Println("===========雇员系统菜单=========")
fmt.Println("input 表示添加雇员")
fmt.Println("show 表示显示雇员")
fmt.Println("find 表示查找雇员")
fmt.Println("exit 表示退出系统")
fmt.Println("请输入你的选择")
fmt.Scanln(&key)
switch key {
case "input":
fmt.Println("输入雇员 id")
fmt.Scanln(&id)
fmt.Println("输入雇员 Name")
fmt.Scanln(&name)
emp := &Emp{
Id: id,
Name: name,
}
hashTable.Insert(emp)
case "show":
hashTable.ShowAll()
case "exit":
default:
fmt.Println("输入错误")
}
}
}
输出结果:
===========雇员系统菜单=========
input 表示添加雇员
show 表示显示雇员
find 表示查找雇员
exit 表示退出系统
请输入你的选择
input
输入雇员 id
12
输入雇员 Name
Jack
===========雇员系统菜单=========
input 表示添加雇员
show 表示显示雇员
find 表示查找雇员
exit 表示退出系统
请输入你的选择
show
链表0为空
链表1为空
链表2为空
链表3为空
链表4为空
链表5 雇员id=12 名字=Jack->
链表6为空
===========雇员系统菜单=========
input 表示添加雇员
show 表示显示雇员
find 表示查找雇员
exit 表示退出系统
请输入你的选择