// 哈希结值存放的对象
type HashObj interface{}

// 哈希驻足中链表结点
type IntHashNode struct {
	Key   int
	Value HashObj

	Prov *IntHashNode // 上一个结点
	Next *IntHashNode // 下一个结点
}

// int 哈希
type IntHash struct {
	// TODO 如果读写操作是多线程操作的,那么就需要加锁了
	Count   int            // 当前哈希存放数量
	ArrCap  int            // 创建哈希时数组的容量
	NodeArr []*IntHashNode // 存放结点的数组
	// TODO 如果需要通过一个首结点遍历所有结点的,需要在链表结点再加一组指针,然后当前结构加一个首位指针
}

// 初始化哈希
func (Self *IntHash) Init(aArrCap int) {
	Self.Count = 0
	Self.ArrCap = aArrCap
	Self.NodeArr = make([]*IntHashNode, aArrCap)
}

// 添加哈希键值
func (Self *IntHash) Add(aKey int, aValue HashObj) {
	if aKey < 0 {
		aKey *= -1
	}

	// 加入哈希先弄一份数据
	mHashNode := &IntHashNode{
		Key:   aKey,
		Value: aValue,
		Prov:  nil,
		Next:  nil,
	}

	// 取余法得到这个数据存数组的位置
	mIndex := aKey % Self.ArrCap
	// 如果这个数组的里面还没存数据
	if Self.NodeArr[mIndex] == nil {
		// 当前插入的数据就可以作为当前位置链表的首个结点
		Self.NodeArr[mIndex] = mHashNode
	} else {
		// 如果这个数组里面已经有了结点数据,进行插入
		mTempNode := Self.NodeArr[mIndex]
		mTempNode.Prov = mHashNode
		mHashNode.Next = mTempNode
		Self.NodeArr[mIndex] = mHashNode
	}

	Self.Count++
}

// 删除哈希
func (Self *IntHash) Del(aKey int) {
	if aKey < 0 {
		aKey *= -1
	}

	mIndex := aKey % Self.ArrCap
	mHashNode := Self.NodeArr[mIndex]
	for mHashNode != nil {
		if mHashNode.Key == aKey {
			break
		}

		mHashNode = mHashNode.Next
	}

	if mHashNode != nil {
		if mHashNode.Prov != nil {
			// 如果指向上个结点的指针不是nil,需要将指针重新指向
			mHashNode.Prov.Next = mHashNode.Next
		} else {
			// 如果上个指针的指向是nil,就需要将数组当前下标下的数据进行修改
			Self.NodeArr[mIndex] = mHashNode.Next
		}

		if mHashNode.Next != nil {
			// 如果哈希的下个指针不是nil的,需要将指针重新指向
			mHashNode.Next.Prov = mHashNode.Prov
		} else {
			// 如果哈希的下个指针是nil,那么无须有其他改动
		}

		Self.Count--
	}
}

// 查找结点
func (Self *IntHash) find(aKey int) *IntHashNode {
	if aKey < 0 {
		aKey *= -1
	}

	mIndex := aKey % Self.ArrCap
	mHashNode := Self.NodeArr[mIndex]
	for mHashNode != nil {
		if mHashNode.Key == aKey {
			return mHashNode
		}

		mHashNode = mHashNode.Next
	}

	return nil
}

// 通过Key获取Value
func (Self *IntHash) GetValue(aKey int) HashObj {
	mHashNode := Self.find(aKey)
	if mHashNode != nil {
		return mHashNode.Value
	}

	return nil
}

// 打印哈希
func (Self IntHash) printHash() {
	fmt.Println("------------- 哈希总内容数量=", Self.Count)

	for i, mNode := range Self.NodeArr {
		fmt.Println("=====数组下标=", i)
		for mNode != nil {
			fmt.Println("当前下标中的内容=", mNode.Value, "Key=", mNode.Key)
			mNode = mNode.Next
		}
	}
}

简单的使用:

func TestHash(t *testing.T) {
	// 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。
	// 也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
	// 这个映射函数叫做散列函数,存放记录的数组叫做散列表。

	// 当前方法使用 取余法
	// 处理冲突使用 拉链法

	mHash := IntHash{}
	mHash.Init(10)

	for i := 0; i < 20; i++ {
		mHash.Add(i, i+20)
	}

	mHash.printHash()
	fmt.Println("=========================================")
	mHash.Del(5)
	mHash.Del(10)
	mHash.printHash()
	fmt.Println("=========================================")
	fmt.Println(mHash.GetValue(10))
	fmt.Println(mHash.GetValue(15))
}

一点点笔记,以便以后翻阅。