Go语言数据结构与算法—哈希表
Posted 小圣.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言数据结构与算法—哈希表相关的知识,希望对你有一定的参考价值。
1. 概述
哈希表(Hash table),也称为散列表。是根据关键码值而直接进行访问的数据结构。也就是说,它通过关键码值映射到表中一个位置来访问记录,以加快查找的速度。
可以用取快递做一个例子:哈希表相当于快递柜,而关键码值就相当于取件码。通过取件码可以很快的找到自己的快递。
1.1 术语
- 散列方法:选取某个函数,以该函数按关键字计算元素的存储位置,并按此存放。
- 散列函数(哈希函数):散列方法中使用的转换函数。
- 散列表:按散列方法构造的表就是散列表。
- 冲突:不同关键码映射到同一个散列地址。
- 同义词:具有相同函数值的多个关键字。
1.2 散列函数的构造
1.2.1 散列函数的特性
- 压缩性
- 单向性
- 确定性
- 分散性
1.2.2 可选择的方法
- 直接定址法
- 数字分析法
- 平分取中法
- 折叠法
- 除留余数法:求关键码key对一个整数的余数,把这个余数当作存储位置
- 随机数法
1.3 解决冲突问题
1.3.1 可选的方法
- 开放定址法
- 链地址法
- 再散列法
- 建立一个公共溢出区
1.4 应用场景
- Java中的Object类
- 文件秒传
- HashMap、HashTable
- Redis集群
2. 雇员信息管理案例
需求:有一个公司,当有新的员工来报道时,要求将该员工的信息加入信息管理系统中,并且当输入该员工的id时,要求查找该员工的所有信息。要求:不使用数据库,尽量节省内存,速度越快越好。
// 员工节点
type Emp struct {
Id int
Name string
Next *Emp
}
// 展示员工信息的方法
func (e *Emp) ShowMe() {
fmt.Printf("链表%d 找到了雇员%d\\n", e.Id%7, e.Id)
}
// 定义员工链表,这里的员工链表不带表头,即第一个节点就存放雇员
type EmpLink struct {
Head *Emp
}
// 添加员工,添加时从小到大
func (el *EmpLink) Insert(emp *Emp) {
// 循环找到合适的位置,进行添加
temp := el.Head
if temp == nil {
el.Head = emp
return
}
for {
if temp.Next == nil {
break
}
if temp.Next.Id > emp.Id {
break
}
temp = temp.Next
}
emp.Next = temp.Next
temp.Next = emp
}
// 通过员工ID查找员工
func (el *EmpLink) FindById(id int) (emp *Emp) {
temp := el.Head
flag := false
if temp == nil {
fmt.Println("the empLink is empty")
return
}
for {
// 找到了员工
if temp.Id == id {
flag = true
break
}
// 没找到员工
if temp.Next == nil {
break
}
temp = temp.Next
}
// 找到员工就返回
if flag {
return temp
} else {
fmt.Println("can`t find the employee")
}
return
}
// 显示链表的信息
func (el *EmpLink) ShowLink(no int) {
if el.Head == nil {
fmt.Printf("链表%d为空\\n", no)
return
}
// 遍历当前的链表,并显示数据
temp := el.Head
for {
if temp != nil {
fmt.Printf("链表%d, 雇员id: %d, 名字: %s", no, temp.Id, temp.Name)
temp = temp.Next
} else {
break
}
}
// 换行处理
fmt.Println()
}
// 定义hashtable,含有链表数组,数组每个位置存放一条链上的员工信息
type HashTbale struct {
LinkArr [7]EmpLink
}
// 添加员工的方法
func (ht *HashTbale) Insert(emp *Emp) {
// 使用散列函数,确定将该员工添加到哪个链表
linkNo := ht.HashFunc(emp.Id)
// 使用对应的链表添加
ht.LinkArr[linkNo].Insert(emp)
}
// 显示hashTable的所有员工
func (ht *HashTbale) ShowAll() {
for i := 0; i < len(ht.LinkArr); i++ {
ht.LinkArr[i].ShowLink(i)
}
}
// 通过员工ID查询
func (ht *HashTbale) FindById(id int) *Emp {
// 确定该雇员所在的链表
linkNo := ht.HashFunc(id)
return ht.LinkArr[linkNo].FindById(id)
}
// 编写一个散列方法
func (ht *HashTbale) HashFunc(id int) int {
// 得到的值就是对应链表的下标
return id % 7
}
//---------------测试---------------
func main() {
key := ""
id := 0
name := ""
var hashTable HashTbale
for {
fmt.Println("===========================")
fmt.Println("1. 添加员工")
fmt.Println("2. 显示员工")
fmt.Println("3. 查找员工")
fmt.Println("4. 退出系统")
fmt.Println("请输入你的选择")
fmt.Scanln(&key)
switch key {
case "1":
fmt.Println("请输入员工id: ")
fmt.Scanln(&id)
fmt.Println("请输入员工名字: ")
fmt.Scanln(&name)
emp := &Emp{
Id: id,
Name: name,
}
hashTable.Insert(emp)
case "2":
hashTable.ShowAll()
case "3":
fmt.Println("请输入要查找的ID号:")
fmt.Scanln(&id)
emp := hashTable.FindById(id)
if emp != nil {
emp.ShowMe()
}
case "4":
os.Exit(0)
}
}
}
代码来自尚硅谷的Go语言教程,但是我修改了一些代码,测试的时候也没有发现问题,但是不知道是否完全正确。如果哪位大佬发现了错误,欢迎指出。
以上是关于Go语言数据结构与算法—哈希表的主要内容,如果未能解决你的问题,请参考以下文章