使用分离链接法实现哈希表的Go语言程序


在计算机科学中,哈希表是一种用于快速数据检索的关键数据结构。它也称为哈希映射,它基于键值对存储和检索数据。在本文中,我们将使用独立链接法在Go语言中实现一个哈希表。在下面演示的示例中,我们将执行初始化、插入以及显示哈希表等操作。

解释

作为一种数据结构,哈希表中的每个槽都包含一个散列到同一索引的项的链表,这使得分离链接成为一种冲突解决策略。在这种方法中,许多项可能共享相同的索引,并且通过使用链表来避免冲突。

这里我们有一个哈希表,以及对应的数组索引以便理解。

Array Index:   0     1     2     3     4
Hash Table:  |     |     |     |     |     |
  • 现在,如果我们想使用键来查找一个值,我们需要将键传递给哈希函数,它将生成一个存储值的索引,让我们假设索引是2。

  • 要检索值,直接使用哈希函数查找索引并访问该索引处的数值。

Array Index:   0     1     2     3     4
Hash Table: |     |     |fruit|     |     |
                            ^ key
                            value: "apple"

	Retrieve("fruit"):
Array Index:   0     1     2     3     4
Hash Table: |     |     |fruit|     |     |
                            ^ key
                            value: "apple"

这是一个使用简单的哈希函数模拟哈希表操作的例子。最初,我们有一个基于数组的哈希表,其中槽为空。然后,我们使用一个根据键确定其索引的哈希函数,将键值对“apple”添加到哈希表中。要检索键为“fruit”的值,请使用哈希函数查找存储该值的索引,你就能找到该值。

语法

func Initialize(size int) *HashTable

该语法定义了一个名为`Initialize`的函数,该函数为哈希表分配内存,设置其大小,并通过接受一个整数大小作为输入并返回指向`HashTable`结构的指针来初始化用于分离链接的内部映射。

func (ht *HashTable) HashCode(key int) int

该语法定义了一个名为`HashCode`的函数,该函数接受一个整数键作为输入,并使用哈希表大小的模运算返回键值对应该放置的索引。

算法

  • 首先,我们将使用链表数组填充哈希表。

  • 要计算哈希码,请提供一个键。

  • 要将哈希码映射到数组中的索引,请使用模运算。

  • 将元素插入到链表中计算出的索引处。

  • 在检索过程中,计算哈希码,查找索引处的链表,然后搜索元素。

示例1

在这个示例中,为了在Go语言中实现哈希表,我们构建了一个使用分离链接法解决冲突的哈希表。它使用一个`HashTable`结构,该结构包含一个链表节点数组,这些节点用于存储键值对。`Initialize`函数初始化哈希表,`HashCode`方法使用模运算计算索引,而`Insert`函数添加元素,通过链接节点处理冲突。在`main`函数中,创建一个哈希表,插入元素,并显示生成的哈希表,演示了使用分离链接法的冲突解决机制。

package main
import "fmt"
type KeyValuePair struct{ Key, Value int }
type Node struct{ Data KeyValuePair; Next *Node }
type HashTable struct{ Size int; Table []*Node }
func Initialize(size int) *HashTable { return &HashTable{size, make([]*Node, size)} }
func (ht *HashTable) HashCode(key int) int { return key % ht.Size }
func (ht *HashTable) Insert(key, value int) {
	index := ht.HashCode(key)
	node := &Node{Data: KeyValuePair{key, value}}
    if ht.Table[index] == nil { ht.Table[index] = node } else { current := ht.Table[index]; for current.Next != nil { current = current.Next }; current.Next = node }
}
func DisplayHashTable(ht *HashTable) {
	for index, node := range ht.Table {
    	fmt.Printf("Index %d:", index)
        for current := node; current != nil; current = current.Next {
            fmt.Printf(" -> (%d, %d)", current.Data.Key, current.Data.Value)
    	}
        fmt.Println()
    }
}
func main() {
	hashTable := Initialize(10)
	hashTable.Insert(5, 42)
	hashTable.Insert(13, 78)
	hashTable.Insert(26, 91)
	hashTable.Insert(39, 104)
	hashTable.Insert(42, 117)
	fmt.Println("Hash Table after insertions:")
	DisplayHashTable(hashTable)
}

输出

Hash Table after insertions:
Index 0:
Index 1:
Index 2: -> (42, 117)
Index 3: -> (13, 78)
Index 4:
Index 5: -> (5, 42)
Index 6: -> (26, 91)
Index 7:
Index 8:
Index 9: -> (39, 104)

示例2

在这个示例中,为了在Go语言中实现哈希表,我们使用的`HashTable`结构用于创建具有分离链接的哈希表,它包含一个整数键到整数数值切片的映射。`Initialize`函数创建一个具有给定大小的哈希表,`HashCode`方法使用模运算计算索引,而`Insert`方法将值插入哈希表,通过将值附加到现有索引来处理冲突。在`main`函数中,创建哈希表,插入值,并显示哈希表的最终状态,其中考虑了分离链接。

package main
import (
	"fmt"
)
type HashTable struct {
  	Size  int
	Table map[int][]int
}
func Initialize(size int) *HashTable {
	table := make(map[int][]int)
	return &HashTable{Size: size, Table: table}
}
func (ht *HashTable) HashCode(key int) int {
	return key % ht.Size
}
func (ht *HashTable) Insert(key int, value int) {
	index := ht.HashCode(key)
	if ht.Table[index] == nil {
    	ht.Table[index] = []int{value}
	} else {
        ht.Table[index] = append(ht.Table[index], value)
	}
}
func DisplayHashTable(ht *HashTable) {
	for index, values := range ht.Table {
    	fmt.Printf("Index %d: %v\n", index, values)
    }
}
func main() {
	hashTable := Initialize(10)
    hashTable.Insert(5, 42)
	hashTable.Insert(13, 78)
	hashTable.Insert(26, 91)
	hashTable.Insert(39, 104)
	hashTable.Insert(42, 117)
	fmt.Println("Hash Table after insertions:")
	DisplayHashTable(hashTable)
}

输出

Hash Table after insertions:
Index 5: [42]
Index 3: [78]
Index 6: [91]
Index 9: [104]
Index 2: [117]

现实生活中的应用

  • 图书馆目录:图书馆经常使用带有独立链接的哈希表来处理这些记录。每本书的唯一标识符(例如ISBN)都可以由哈希表分配一个索引。当在哈希过程中许多卷被分配相同的索引时,图书馆使用分离链接来正确处理这些情况。这种方法确保书籍得到有效地组织和检索。

  • Web应用程序中的用户会话:Web应用程序中的用户会话通常使用带有分离链接的哈希表来管理。为了有效地获取他们自己的会话数据,每个用户的会话ID都可以进行哈希处理。即使用户的ID在哈希过程中导致相同的索引,分离链接也能确保多个用户的会话得到正确存储和检索。

结论

哈希表是用于高效数据检索和存储的重要数据结构,它通过将键映射到数组中的索引来实现,从而允许快速访问值。分离链接是用于处理哈希表中冲突的常用技术之一。在本文中,我们看到了在Go语言中实现哈希表的两种方法。第一种方法使用链表数组,在数组中组织元素,直接寻址索引进行检索。第二种方法使用映射,提供动态的键值对,适应不同的冲突,可能减少内存使用,同时保持有效的数据访问。

更新于:2023年10月18日

226 次浏览

开启您的职业生涯

完成课程获得认证

开始学习
广告
© . All rights reserved.