美文网首页
【算法笔记】散列表(哈希表 Hash table)的简单实践

【算法笔记】散列表(哈希表 Hash table)的简单实践

作者: 李明燮 | 来源:发表于2022-02-22 10:28 被阅读0次

    今天用go语言简单的写了一下散列表(Hash table)的方法。
    为了以后方便查看,当做笔记整理了一下~~

    1.散列表(Hash table)

    我们先看看维基百科里是怎么解释的。

    根据键(Key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算出一个键值的函数,将所需查询的数据映射到表中一个位置来让人访问,这加快了查找速度。
    这个映射函数称做散列函数,存放记录的数组称做散列表。

    看看下图:

    图片备用地址

    linked_list

    存储: 哈希表使用哈希函数(Hash Function) 将键(key)转换成一个哈希值
    然后在数组中获取对应的值,如果有值就会用链表的形式存储。
    查询: 存储的过程理解了,查询看着下面流程也应该能理解。
    key->f(key)->index->list[index]->linked_list。
    删除: 省略... 需要注意的是删除链表的第一条数据和,链表中的数据需要额外的逻辑判断。

    2.简单代码实现

    struct

    type HashMap struct {
        BucketMap []HashNode
        Size      int
    }
    
    type HashNode struct {
        Key   string
        Value int
        Next  *HashNode
    }
    
    //简单的模仿了哈希函数(Hash Function)
    func GetHashCodeIndex(key string) int {
        return len(key) % 10
    }
    

    Get

    func (h *HashMap) Get(key string) int {
        bucketIndex := GetHashCodeIndex(key)
        hashNode := &h.BucketMap[bucketIndex]
        if len(hashNode.Key) == 0 && hashNode.Value == 0 && hashNode.Next == nil {
            return -1
        } else {
            for strings.Compare(hashNode.Key, key) != 0 {
                hashNode = hashNode.Next
            }
            if hashNode == nil {
                return -1
            } else {
                return hashNode.Value
            }
        }
    }
    

    Add

    func (h *HashMap) Add(key string, value int) {
        bucketIndex := GetHashCodeIndex(key)
        hashNode := &h.BucketMap[bucketIndex]
    
        if len(hashNode.Key) == 0 && hashNode.Value == 0 && hashNode.Next == nil {
            h.BucketMap[bucketIndex] = HashNode{Key: key, Value: value}
            h.Size++
        } else {
            for hashNode.Next != nil {
                hashNode = hashNode.Next
            }
            hashNode.Next = &HashNode{Key: key, Value: value}
            h.Size++
        }
        //这里可以添加数据量太多,查询速度慢的时候增加数组空间逻辑的方法
    }
    

    Remove

    func (h *HashMap) Remove(key string) {
        bucketIndex := GetHashCodeIndex(key)
        hashNode := &h.BucketMap[bucketIndex]
    
        if len(hashNode.Key) == 0 && hashNode.Value == 0 && hashNode.Next == nil {
            return
        } else {
            parentNode := hashNode
            for strings.Compare(hashNode.Key, key) != 0 {
                parentNode = hashNode
                hashNode = hashNode.Next
            }
            if hashNode == nil {
                return
            } else if parentNode == hashNode {
                h.BucketMap[bucketIndex] = *hashNode.Next
                h.Size--
            } else {
                parentNode.Next = hashNode.Next
                h.Size--
            }
        }
        //这里可以添加数据量删减到一定程度后,减少数据空间的逻辑,一般不加。
    }
    

    IsEmpty,Print

    func (h *HashMap) IsEmpty() bool {
        return h.Size == 0
    }
    
    func (h *HashNode) Print() {
        if h == nil || h.Value == 0 {
            return
        } else {
            fmt.Print(h.Value, " ")
            h.Next.Print()
        }
    }
    

    执行结果

    func main() {
        bucketMap := make([]HashNode, 10)
        hashMap := HashMap{BucketMap: bucketMap}
        hashMap.Add("a", 1)
        hashMap.Add("ab", 2)
        hashMap.Add("abc", 3)
        hashMap.Add("abcd", 4)
        hashMap.Add("abcde", 5)
        hashMap.Add("1234567890ab", 12)
        hashMap.Add("1234567890abc", 13)
        hashMap.Add("12345678901234567890abc", 113)
        hashMap.Add("1234567890xabcde", 15)
    
        fmt.Println("-------------Size--------------")
        fmt.Println("Size:", hashMap.Size)
    
        fmt.Println("-------------Get--------------")
        fmt.Println(hashMap.Get("1234567890abc"))
    
        fmt.Println("-------------Add--------------")
        fmt.Print("Bucket[3]: ")
        hashMap.BucketMap[3].Print()
        fmt.Println("")
    
        hashMap.Add("123456789012345678901234567890abc", 1113)
        fmt.Print("Bucket[3]: ")
        hashMap.BucketMap[3].Print()
        fmt.Println("")
        fmt.Println("Size:", hashMap.Size)
    
        fmt.Println("-------------Remove--------------")
        hashMap.Remove("abc")
        fmt.Print("Bucket[3]: ")
        hashMap.BucketMap[3].Print()
        fmt.Println("")
        fmt.Println("Size:", hashMap.Size)
    }
    

    执行结果为:

    $ go run main.go
    -------------Size--------------
    Size: 9
    -------------Get--------------
    13
    -------------Add--------------
    Bucket[3]: 3 13 113
    Bucket[3]: 3 13 113 1113
    Size: 10
    -------------Remove--------------
    Bucket[3]: 13 113 1113
    Size: 9
    

    后续思考

    这样结构的HashTable遇到多线程的编程方式,会遇到什么问题?


    欢迎大家的意见和交流

    email: li_mingxie@163.com

    相关文章

      网友评论

          本文标题:【算法笔记】散列表(哈希表 Hash table)的简单实践

          本文链接:https://www.haomeiwen.com/subject/nhfglrtx.html