5.4. 数据结构-散列法

168 阅读2分钟

散列法

散列法是一种搜索算法,它可以根据各元素的值来确定存储位置,然后将位置保管在散裂表中,从而实现数据的高速搜索.

高效的

  1. 插入
  2. 搜索
  3. 删除

数据结构

由容纳m个元素的数组T组成,理论上能够存储m个不同的元素,不过一般容量达到0.75m时,就会对数组进行扩容.因为此时hash函数的冲突概率会变大.

注意事项

  1. 哈希函数 h(k)=k mod mh(k) = k\ mod\ m
  2. 哈希冲突的解决办法有多种,常见的有
    1. 开放地址法,双散列结构中使用的开放地址法.
    2. 链地址法

在双散列结构中一旦出现冲突 , 程序会调用第二个散列闲数来求散 列值 。

H(k)=h(k,i)=h1(k)+ih2(k)) mod mH(k)= h(k,i) = h_1(k)+i * h_2(k))\ mod \ m

散列函数 h(k,i)h(k,i) 有k和i两个参数.这里的i是发生冲突后计算下一个散列值的次数.只要散列函数H(k)H(k)起了冲突 , 就会依次调用h(k,0)h(k,0),h(k,1)h(k,1),h(k,2)h(k,2),h(k,3)h(k,3),...直到不发生冲突为止,然后返回这个h(k,i)的值作为散列值。

  1. 因为下标每次移动h(k)h(k)个位置,所以必须保证 T的 数组的长度m 与 h2(k)h2(k)互质,否则会出来无法生成下标的情况.
    1. 可以特意让m为质数,然后取一个小于m的值为h2(k)h2(k),从而避免上述情况的发生.

题目

请实现一个能执行以下命令的简易 “ 字典 ” 。

  • ► insert s t r : 向字典中添加字符串价
  • ► find str : 当前字典中包含幻 〃 时输出 yes , 不包含时输出 no

5.4.hash.go 此处用法像set

package ch5

//insert str: 向字典中添加字符串str
//find str: 当前字典中是否包含str,包含返回true,不包含返回false

import (
	"strings"
)

const M = uint64(1046527)

var H [M]string

func getChar(ch byte) uint64 {
	switch ch {
	case 'A':
		return 1
	case 'C':
		return 2
	case 'G':
		return 3
	case 'T':
		return 4
	}
	return 0
}

func getKey(s string) uint64 {
	sum := uint64(0)
	p := uint64(1)
	i := 0
	for i = 0; i < len(s); i++ {
		sum += p * getChar(s[i])
		p *= 5
	}
	return sum
}

func h1(key uint64) uint64 {
	return key % M
}

func h2(key uint64) uint64 {
	return 1 + (key % (M - 1))
}

func find(s string) bool {
	key := getKey(s)
	i := uint64(0)
	for i = 0; ; i++ {
		h := (h1(key) + i*h2(key)) % M //此处可以将h1提到循环外,进行优化,为了方便理解没有提出
		if strings.Compare(H[h], s) == 0 {
			return true
		} else if len(H[h]) == 0 {
			return false
		}
	}
	return false
}

//插入成功返回true
func insert(s string) bool {
	key := getKey(s)
	i := uint64(0)
	for i = 0; ; i++ {
		h := (h1(key) + i*h2(key)) % M //此处可以将h1提到循环外,进行优化,为了方便理解没有提出
		if strings.Compare(H[h], s) == 0 {
			return false
		} else if len(H[h]) == 0 {
			H[h] = s
			return true
		}
	}
	return false
}