分离链接的散列

散列

散列为一种用于以常数平均时间执行插入,删除和查找的技术。一般的实现方法是使通过数据的关键字可以计算出该数据所在散列中的位置,类似于Python中的字典。关于散列需要解决以下问题:

  • 散列的关键字如何映射为一个数(索引)——散列函数
  • 当两个关键字的散列函数结果相同时,如何解决——冲突

散列函数

散列函数为关键字->索引的函数,常用的关键字为字符串,则需要一个字符串->整数的映射关系,常见的三种散列函数为:

  • ASCII码累加(简单)
  • 计算前三个字符的加权和$\sum key[i] * 27^{i}$ (不太好,3个字母的常用组合远远小于可能组合)
  • 计算所有字符加权和并对散列长度取余$(\sum key[i] * 32^{i}) % tablesize$(较好)
// 累加
func (n *node) hashSum() int {
    hash := 0
    for i := range n.key {
        hash += int(n.key[i])
    }
    return hash
}
// 前三个字符和
func (n *node) hashTop3() int {
    hash := 0
    time := utf8.RuneCountInString(n.key)
    if time > 3 {
        time = 3
    }
    for i := 0; i < time; i++ {
        hash += int(n.key[i])
    }
    return hash
}
// 所有字符和取余
func (n *node) hashMod(lenght int) int {
    hash := 0
    for i := range n.key {
        hash += int(n.key[i]) * 32
    }
    return hash % lenght
}

冲突

当不同关键字计算出的散列值相同时,发生冲突,本次使用分离链接法解决:

  • 每个散列中的数据结构有一个指针可以指向下一个数据,因此散列表可以看成链表头的集合
  • 当插入时,将数据插入在对应散列值的链表中
  • 访问时,遍历对应散列值的链表,直到找到关键字

代码实现

散列节点

结构体

type nodeData struct {
    data int
}

type node struct {
    key  string
    hash int
    data nodeData
    next *node
}

散列值计算(使用第三种)

func (n *node) HashCompute(lenght int) {
    n.hash = n.hashMod(lenght)
    // fmt.Println("key:", n.key, "hash:", n.hash)
}

构造函数

func newNode(data nodeData, key string) *node {
    temp := &node{key, 0, data, nil}
    return temp
}

散列表

结构体

type hashTable struct {
    table [17]node
}

插入方法

func (h *hashTable) insert(data nodeData, key string) {
    temp := newNode(data, key)
    temp.HashCompute(len(h.table))
    temp.next = h.table[temp.hash].next
    h.table[temp.hash].next = temp
}

访问方法

func (h *hashTable) visit(key string) (nodeData, error) {
    temp := newNode(nodeData{}, key)
    temp.HashCompute(len(h.table))
    //设计失误,仅有节点有计算散列值的方法,因此需要定义一个散列节点用于计算散列值
    point := h.table[temp.hash].next
    for point != nil {
        if point.key == key {
            return point.data, nil
        }
        point = point.next
    } //遍历链表,搜索关键字
    return temp.data, errors.New("not exsist")
    // 失败退出
}

构造函数

func newHashTable() *hashTable {
    temp := &hashTable{}
    for i := range temp.table {
        temp.table[i] = *newNode(nodeData{}, "")
    }
    return temp
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容