Implementation of Some Commonly Used Data Structures in Go

Some data structures are commonly used in our development, such as stack, queue, map, etc.. However, (I think) the philosophy of Go is as simple as possible. Go doesn't provide some data structures that I think it should have. Of course I know Go has slice and map but it's the unbox-and-use thing that makes our life simpler, isn't it?

Sometimes I am super disappointed that the lack of stack, queue, set and sorted map in Go so here I am. I try to implement the four data structures I just mention.

If there is something wrong, feel free to point it out and I, a newbie of Go, will be very thankful. :smiley:

Stack

// A simple implementation of stack.
type Stack struct {
    // the data stored in stack
    elements []interface{}
}

// Construct a new stack.
func NewStack() *Stack {
    return &Stack{make([]interface{}, 0)}
}

// Test if the stack is empty.
func (s *Stack) Empty() bool {
    return len(s.elements) == 0
}

// Return the size of stack.
func (s *Stack) Size() int {
    return len(s.elements)
}

// Push an item into the top of stack.
func (s *Stack) Push(e interface{}) interface{} {
    s.elements = append(s.elements, e)
    return e
}

// Remove the top of stack and return it.
func (s *Stack) Pop() interface{} {
    if s.Empty() {
        return nil
    }
    v := s.elements[len(s.elements)-1]
    s.elements = s.elements[:len(s.elements)-1]
    return v
}

// Retrieve the top of stack.
func (s *Stack) Peek() interface{} {
    if s.Empty() {
        return nil
    }
    return s.elements[len(s.elements)-1]
}

Example

func main() {
    s := NewStack()
    for i := 0; i < 10; i++ {
        s.Push(i)
    }
    fmt.Println(s.Size()) // output: 10
    top := s.Peek()
    fmt.Println(top)  // output: 9
    for !s.Empty() {
        fmt.Println(s.Pop())  // output: 9 8 7 6 5 4 3 2 1 0
    }
}

Notice that in the Popmethod, I use s.elements = s.elements[:len(s.elements)-1]to remove the last element from slice. Actually it's a trick as mentioned in this article.

Queue

// A simple implementation of Queue.
type Queue struct {
    // the data stored in queue
    elements []interface{}
}

// Construct a new queue.
func NewQueue() *Queue {
    return &Queue{make([]interface{}, 0)}
}

// Test if the queue is empty.
func (q *Queue) Empty() bool {
    return len(q.elements) == 0
}

// Return the size of queue.
func (q *Queue) Size() int {
    return len(q.elements)
}

// Add an item to the tail of queue.
func (q *Queue) Add(e interface{}) interface{} {
    q.elements = append(q.elements, e)
    return e
}

// Remove the head of queue and return it.
func (q *Queue) Poll() interface{} {
    if q.Empty() {
        return nil
    }
    v := q.elements[0]
    q.elements = q.elements[1:]
    return v
}

// Retrieve the head of queue and return it.
func (q *Queue) Peek() interface{} {
    if q.Empty() {
        return nil
    }
    return q.elements[0]
}

Example

func main() {
    q := NewQueue()
    for i:= 0; i < 10; i++ {
        q.Add(i)
    }    
    fmt.Println(q.Size()) // output: 10
    head := q.Peek()
    fmt.Println(head) // output: 0
    for !q.Empty() {
        fmt.Println(q.Poll()) // output: 0 1 2 3 4 5 6 7 8 9
    }
}

Set

// A simple implementation of set.
type Set struct {
    // key: data stored in set
    // value: whether data exists in set
    elements map[interface{}]bool
}

// Construct a new set.
func NewSet() *Set {
    return &Set{make(map[interface{}]bool)}
}

// Return the size of set.
func (s *Set) Size() int {
    return len(s.elements)
}

// Test if the set is empty.
func (s *Set) Empty() bool {
    return len(s.elements) == 0
}

// Add an item that doesn't exist into set. 
// If the set didn't contain the item, return true, 
func (s *Set) Add(e interface{}) bool {
    if ok := s.elements[e]; !ok {
        s.elements[e] = true
        return true
    } else {
        return false
    }
}

// Remove the specific item if it exists in the set.
// Return true if the set contained the specified item
func (s *Set) Remove(e interface{}) bool {
    if ok := s.elements[e]; !ok {
        return false
    } else {
        delete(s.elements, e)
        return true
    }
}

// Test if a specific item exists in the set.
func (s *Set) Contains(e interface{}) bool {
    return  s.elements[e]
}

// Return all items in the set.
func (s *Set) Values() []interface{} {
    vals := make([]interface{}, 0, len(s.elements))
    for v, ok := range s.elements {
        if ok {
            vals = append(vals, v)
        }
    }
    return vals
}

Example

func main() {
    set := NewSet()
    set.Add(1)
    set.Add(2)
    set.Add(3)
    set.Add(3)
    fmt.Println(set.Contains(1)) // output: true
    set.Remove(2)
    for e := set.values() {
        fmt.Println(e) // output: 1 3
    } 
}

I want to point out that the idea of implementing a set based on a map whose value type is boolis mentioned in Effective Go.

Sorted Map

I have to admit that one of the biggest disadvantage of Go is the lack of generics (another one may be the lack of a mature dependency management tool). I can't generalize the solution because I have to specify a sortable type as key type. Here I just implement the sorted map of intkey.

// A simple implementation of sorted map.
type SortedMapInt struct {
    // all key-value pairs
    pairs map[int]interface{}
    // keys in their natural order
    keys []int
}

// Construct a new sorted map.
func NewSortedMapInt() *SortedMapInt {
    return &SortedMapInt{make(map[int]interface{}), make([]int, 0)}
}

// Test if the map is empty.
func (m *SortedMapInt) Empty() bool {
    return len(m.pairs) == 0
}

// Put a new key-value pair into the map and return the old 
// associated value of this key or nil if there was no mapping for key.
func (m *SortedMapInt) Put(k int, v interface{}) interface{} {
    if _, ok := m.pairs[k]; !ok {
        m.keys = append(m.keys, k)
        sort.Ints(m.keys)
    }
    old := m.pairs[k]
    m.pairs[k] = v
    return old
}

// Return the associated value of a specific key if the key exists.
func (m *SortedMapInt) Get(k int) interface{} {
    if v, ok := m.pairs[k]; ok {
        return v
    } else {
        return nil
    }
}

// Remove the associated value of a specific key if the key exists.
func (m *SortedMapInt) Remove(k int) interface{} {
    if v, ok := m.pairs[k]; ok {
        delete(m.pairs, k)
        return v
    } else {
        return nil
    }
}

// Return the set of keys in their natural order.
func (m *SortedMapInt) Keys() []int {
    return m.keys
}

// Return the set of associated values of sorted keys.
func (m *SortedMapInt) Values() []interface{} {
    vals := make([]interface{}, 0)
    for _, k := range m.keys {
        if v, ok := m.pairs[k]; ok {
            vals = append(vals, v)
        }
    }
    return vals
}

Example

func main() {
    sMap := NewSortedMapInt()
    sMap.Put(1, "a")
    sMap.Put(2. "b")
    sMap.Put(3, "c")
    sMap.Put(1, "d")
    fmt.Println(sMap.Keys()) // output: [1 2 3]
    sMap.Remove(2)
    fmt.Println(sMap.Values()) // output: ["d" "c"]
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,992评论 0 10
  • The Inner Game of Tennis W Timothy Gallwey Jonathan Cape ...
    网事_79a3阅读 13,167评论 3 20
  • 这是发生在名为终焉的大陆上的故事,这是有关第三次诸神黄昏的故事,这是恶魔与人类的故事,这是少年与少女的故事。 ...
    药糖执笔阅读 305评论 0 0
  • (顾城) 我喜欢穿旧衣裳在默默展开的早晨里穿过广场一蓬蓬郊野的荒草从缝隙中无声地爆发起来我不能停留那些瘦小的黑蟋蟀...
    紫章阅读 671评论 0 4
  • 我本来是在微博发每日的!但是突然要验证手机,试了两天了收不到验证码!于是非常生气但是练习不能断呀!(不遮了反正看不...
    syeturing阅读 239评论 0 0

友情链接更多精彩内容