最近在面试时被问到了在Go中如何实现有序的map,众所周知,在Go的标准库中是没有有序map的,所以想要使map有序,只能自己实现,或者使用开源的第三方库。面试时只是口述了一下如何实现,没有实际动手写,感觉还是有些没讲清楚的地方,于是面试结束后按照当时的思路,用代码简单实现了一把,只当巩固一下了。基本思路是双向链表+原生map,话不多说,直接上代码。
// 双向链表节点的基本结构
type BidirectionalList struct {
pre *BidirectionalList
next *BidirectionalList
key string
value interface{}
}
// OrderMap 有序map
type OrderMap struct {
capacity int // 容量
head *BidirectionalList // 双向链表的头部
tail *BidirectionalList // 双向链表的尾部
m map[string]*BidirectionalList // map
}
func NewOrderMap(cap int) *OrderMap {
head := &BidirectionalList{}
tail := &BidirectionalList{}
head.next = tail
tail.pre = head
return &OrderMap{
capacity: cap,
head: head,
tail: tail,
m: make(map[string]*BidirectionalList, cap),
}
}
// Put 添加一个key,存在则新增
func (o *OrderMap) Put(node *BidirectionalList) {
v, ok := o.m[node.key]
// 新增逻辑
if !ok {
// TODO 如果容量已满则需要先扩容再添加
next := o.head.next
o.head.next = node
node.next = next
node.pre = o.head
next.pre = node
o.m[node.key] = node
return
}
// 更新逻辑
v.value = node.value
return
}
// Remove 删除一个key
func (o *OrderMap) Remove(key string) {
v, ok := o.m[key]
if !ok {
return
}
pre := v.pre
next := v.next
pre.next = next
next.pre = pre
delete(o.m, key)
}
// Get 获取一个key
func (o *OrderMap) Get(key string) interface{} {
if v, ok := o.m[key]; ok {
return v
}
return nil
}
以上代码只是一个简单的时候,而且只实现了最基本的Put,Remove和Get方法,并且在通用性上也不太好,缺少封装,不支持并发。一些细节点也没有处理到,比如Put时,容量满了应该扩容,key重复了是更新还是追加等等。不过用来应付面试应该也够了,在实际工作中,推荐优先使用知名的或者引用量高的第三方的开源库,尽量避免重复造轮子,如果开源库满足不了需求再去考虑自己实现一个,比如支持并发的有序map等,如果想要做到更完善也可以参考Java的LinkedHashMap的基本实现。
如果有更好的实现,欢迎评论留言讨论,show me your code。