Golang 数据结构 —— 字典

本文介绍了一种在Golang中实现字典数据结构的方法,利用泛型和并发安全特性,提供了一系列操作字典的便捷方法,如Set, Delete, Has等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Golang 数据结构 —— 字典

字典存储[key,value]对,Go提供了非常方便的实现,内置的map类型。

本文增强内置的map类型,添加便捷的操作用于获取或改变其内容。创建ItemDictionary泛型、并发安全的,能够生成任何具体类型。

1. 目标

通过dict := ValueDictionary{}创建字典,提供一组暴露方法:

Set()
Delete()
Has()
Get()
Clear()
Size()
Keys()
Values()

2. 实现

package dict

import (
	"github.com/cheekybits/genny/generic"
	"sync"
)

type Key   generic.Type
type Value generic.Type

type ValueDictionary struct {
	data map[Key]Value
	mux sync.RWMutex
}

func (s *ValueDictionary)Set(key Key, value Value)  {
	if s.data == nil{
		s.data = map[Key]Value{}
	}
	s.mux.Lock()
	defer s.mux.Unlock()
	s.data[key] = value
}

func (s *ValueDictionary)Delete(key Key) bool{
	s.mux.Lock()
	defer s.mux.Unlock()

	_,ok := s.data[key]
	if ok {
		delete(s.data, key)
	}

	return ok
}

func (s *ValueDictionary)Has(key Key) bool{
	s.mux.RLock()
	s.mux.RUnlock()

	_,result := s.data[key]

	return result
}

func (s *ValueDictionary)Get(key Key) Value{
	s.mux.RLock()
	s.mux.RUnlock()

	result,_ := s.data[key]

	return result
}

func (s *ValueDictionary)Clear(){
	s.mux.Lock()
	defer s.mux.Unlock()
	s.data = map[Key]Value{}
}

func (s *ValueDictionary)Size() int{
	return len(s.data)
}

func (s *ValueDictionary)Keys() []Key{
	s.mux.RLock()
	s.mux.RUnlock()

	keys := make([] Key,len(s.data))
	for k := range s.data{
		keys = append(keys, k)
	}

	return keys
}

func (s *ValueDictionary)Values() []Value{
	s.mux.RLock()
	s.mux.RUnlock()

	values := make([] Value,len(s.data))
	for _, v := range s.data{
		values = append(values, v)
	}

	return values
}

3. 测试

测试代码描述如何使用上面定义的字典。我们不会直接和底层map进行交互,但如何Go没有提供map类型,需要另外的实现。

package dict

import (
	"fmt"
	"testing"
)

func TestValueDictionary_Set(t *testing.T) {
	dict := ValueDictionary{}
	dict.Set("1",1)
	dict.Set("2",2)
	dict.Set("3",3)
	dict.Set("4",4)

	fmt.Println("size:",dict.Size())
	fmt.Println("1:",dict.Get("1"))

	dict.Delete("1")
	fmt.Println("keys",dict.Keys())
	fmt.Println("values",dict.Values())
	fmt.Println("has 2",dict.Has("2"))
	fmt.Println("del 2",dict.Delete("2"))

	fmt.Println("size:",dict.Size())

	dict.Clear()
	fmt.Println("size:",dict.Size())
}

我们可以通过下面命令生成具体类型字典:

genny -in ItemDictionary.go -out dictionary-string-int.go gen "Key=string Value=int"

4. 总结

本文基于map实现了字典数据类型,采用泛型方式,支持并发安全。

### 哈希表底层数据结构实现原理 #### 数组加链表结构 哈希表是一种通过特定算法计算索引来访问元素的数据结构,其核心在于高效地完成查找操作。对于Golang中的哈希表而言,采用的是数组加上单链表的形式来构建[^1]。 ```go type hmap struct { count int flags uint8 B uint8 noverflow uint16 hash0 uint32 buckets unsafe.Pointer // []*_bucket } // _bucket represents a single bucket in the hash table. type _bucket struct { topbits [8]uint8 keys [8]uintptr vals [8]uintptr } ``` 上述代码展示了Go语言内部定义的一个`hmap`类型以及对应的桶(`_bucket`)结构体。每个桶可以容纳八个键值对,并且当发生碰撞时会创建新的节点链接到当前节点之后形成链表以处理冲突情况。 #### 链地址法解决冲突 在C++标准库中同样存在类似的机制用于管理哈希表内的元素分布问题。这里提到的方法被称为“链地址法”,即利用额外的空间——通常是动态分配的一系列结点构成一条或多条链路连接起来表示相同位置上的不同记录项[^2]。 #### Redis 中的字典入口设计 而在分布式缓存系统Redis里,则有着更为细致的设计模式。具体来说就是每一个词条都由一个名为`dictEntry`的小型对象所代表,它不仅保存着实际存储的信息(键和值),还维护了一个指针字段指向可能存在的后续同义词单元从而组成了一种开放寻址式的线性探测方案[^3]。 ```c typedef struct dictEntry { void *key; union{ void *val; uint64_t u64; int64_t s64; } v; struct dictEntry *next; } dictEntry; ``` 综上所述,在不同的编程环境和技术栈下虽然细节有所差异但是基本思路都是相同的:借助于某种形式的映射关系将输入转化为固定范围内的整数值作为定位依据并辅之有效的防撞策略确保整体性能表现良好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值