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 Pop
method, 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 bool
is 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 int
key.
// 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"]
}