实现栈结构的常规思路是采用链式结构,用过指针和栈有关的属性值实现、控制栈的接口和规范。另外一种思路是采用数据组,把栈操作的数据保存在数组中。但采用数据的一个特点是,数组的大小是确定的,当需要改变数据的存储容量时需要重新分配内存和拷贝数据。
基于go内置的数据结构slice,可以实现灵活的栈结构。类实地,实现队列、堆、优先队列都可以使用Slice结构存储元素。下面给出栈的实现。
定义栈结构
1 2 3 4 5
| type Stack struct { s []int top int length int }
|
初始化栈结构
1 2 3 4 5 6
| func NewStack() *Stack { stack := &Stack{ s: make([]int, 0, 10), } return stack }
|
栈操作
为了简洁,如果遇到空栈,Pop和Top默认返回0值,改为弹出异常也不难。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| func (s *Stack) Push(item int) { s.s = append(s.s, item) s.top = item s.length += 1 }
func (s *Stack) Empty() bool { return s.length == 0 }
func (s *Stack) Pop() int { if s.Empty() { return 0 } item := s.s[s.length-1] s.s = s.s[:s.length-1] s.length -= 1 return item }
func (s *Stack) Len() int { return s.length }
func (s *Stack) Top() int { if s.Empty() { return 0 } else { return s.top } }
|
测试栈
1 2 3 4 5 6 7 8 9 10
| func TestStack() { stack := NewStack() for i := 0; i <= 10; i++ { stack.Push(i) }
for !stack.Empty() { fmt.Println(stack.Pop()) } }
|
结语
实现栈结构确实不难,但需要分析使用场景和实现的储存结构。这里采用了Slice实现,本质上就是数组,一篇连续的内存空间,在存储上更紧凑。关于栈的链式结构实现见栈的链式结构实现(Go语言版)。