面试官:在Go中如何实现一个有序map

228 阅读2分钟

最近在面试时被问到了在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。