(1)栈的定义
栈是一种只能在一端进行插入或删除操作的线性表,其中允许进行插入或删除操作的一端称为栈顶(Top),栈的插入和删除操作一般称为入栈和出栈。
栈的底端称为栈底,栈底是固定不变的,栈顶由一个称为栈顶指针的位置指示器(一个变量)来指示,对于顺序栈,是记录栈顶元素所在数组位置标号的一个整型变量;对于链式栈,是记录栈顶元素所在结点地址的指针,它是动态变化的。
(2)栈的特征
栈的主要特点是先进后出( FILO )。
(3)栈的存储结构
栈按照存储结构分为两种:顺序栈和链式栈。栈本质上是线性表,而线性表有两种主要的存储结构——顺序表和链表,因此栈也同样有对应的两种存储结构。
(4)栈的数学性质
当 n 个元素以某种顺序进栈,并且可在任意时刻出栈(在满足先进后出的前提下)时,所获得的元素排列的数目 N 恰好满足 Catalan 函数的计算。
(1)顺序栈的结构体定义如下:
// Arrary
type ArrayStack struct {
Data [MaxSize]interface{}
Top int
}
// Slice
type SliceStack struct {
Data []interface{}
Top int
}
(2) 链栈的结构体定义如下:
type StackNode struct {
Value interface{}
Next *StackNode
}
type LinkStack struct {
Top *StackNode
Length int
}
(1)数组栈的基本操作如下代码所示。
type Operate interface {
// 初始化栈
InitSeqStack()
// 判断栈是否为空
IsEmpty() bool
// 获取栈的长度
Len() int
// 输出栈
DisplayStack()
// 获取栈顶元素
Peek() interface{}
// 元素进栈
Push(v interface{}) error
// 元素出栈
Pop() (v interface{}, err error)
}
(2)在任意目录下创建项目,编写一个名为 seqstack.go
的程序实现以上的操作,该程序的代码如下所示。
package SeqStack
import (
"errors"
"fmt"
)
const MaxSize = 20
type SeqStack struct {
Data [MaxSize]interface{}
Top int
}
func NewSeqStack() *SeqStack {
return new(SeqStack)
}
// 相关操作的接口定义
type Operate interface {
InitSeqStack()
IsEmpty() bool
Len() int
DisplayStack()
Peek() interface{}
Push(v interface{})
Pop() (v interface{})
}
// 初始化顺序栈
func (s *SeqStack) InitSeqStack() {
s.Top = -1
}
// 获取栈的长度
func (s *SeqStack) Len() int {
return s.Top + 1
}
// 判断栈是否为空
func (s *SeqStack) IsEmpty() bool {
return s.Top == -1
}
// 获取栈顶元素
func (s *SeqStack) Peek() interface{} {
if s.IsEmpty() {
panic(errors.New(("The SeqStack is empty!"))
} else {
return s.Data[s.Top]
}
}
// 输出栈中的元素
func (s *SeqStack) DisplayStack() {
if s.IsEmpty() {
fmt.Printf("The SeqStack is empty!\n")
} else {
i := 0
fmt.Printf("栈中的元素为: ")
for i < s.Len() {
fmt.Printf("%d ", s.Data[i])
i++
}
fmt.Println()
}
}
// 进栈操作
func (s *SeqStack) Push(v interface{}) {
if s.Top == MaxSize-1 {
panic(errors.New("The SeqStack is full!\n"))
} else {
s.Top++
s.Data[s.Top] = v
fmt.Printf("Elem %d is pushed into the SeqStack!\n", v)
}
}
// 出栈操作
func (s *SeqStack) Pop() (v interface{}) {
if s.IsEmpty() {
panic(errors.New("The SeqStack is full!\n"))
} else {
v = s.Data[s.Top]
s.Top--
fmt.Printf("Elem %d is poped from the SeqSatck!\n", v)
return v
}
}
(3)在该项目的目录下编写一个名为 seqstack_test.go
程序测试以上的功能逻辑是否正确,该程序的具体代码如下所示。
package SeqStack
import (
"fmt"
"testing"
)
func TestSeqStack(t *testing.T) {
var s Operate
s = NewSeqStack()
s.InitSeqStack()
s.Push(3)
s.Push(2)
s.Push(1)
s.DisplayStack()
fmt.Printf("The SeqStack's top elem is %d\n", s.Peek())
s.Pop()
s.DisplayStack()
fmt.Printf("The SeqStack's length is %d\n", s.Len())
}
(4)在该项目的目录下执行 go test
命令进行验证测试,程序运行的结果如下所示。
Elem 3 is pushed into the SeqStack!
Elem 2 is pushed into the SeqStack!
Elem 1 is pushed into the SeqStack!
栈中的元素为: 3 2 1
The SeqStack's top elem is 1
Elem 1 is poped from the SeqSatck!
3 2
The SeqStack's length is 2
(1)切片栈的基本操作如下代码所示。
type Operate interface {
// 初始化栈
InitSliceStack()
// 判断栈是否为空
IsEmpty() bool
// 获取栈的长度
Len() int
// 输出栈
DisplayStack()
// 获取栈顶元素
Peek() interface{}
// 元素进栈
Push(v interface{})
// 元素出栈
Pop() (v interface{})
}
(2)在任意目录下创建项目,编写一个名为 slicestack.go
的程序实现以上的功能,该程序的代码如下所示。
package SliceStack
import (
"errors"
"fmt"
)
type SliceStack struct {
Data []interface{}
Top int
}
// 相应操作的接口
type Operate interface {
InitSliceStack()
IsEmpty() bool
Len() int
DisplayStack()
Peek() interface{}
Push(v interface{})
Pop() interface{}
}
func NewSliceStack() *SliceStack {
return new(SliceStack)
}
// 初始化栈
func (s *SliceStack) InitSliceStack() {
s.Top = -1
}
// 判断栈是否为空
func (s *SliceStack) IsEmpty() bool {
return s.Top == -1
}
// 获取栈的长度
func (s *SliceStack) Len() int {
return s.Top + 1
}
// 输出栈中的元素
func (s *SliceStack) DisplayStack() {
if s.IsEmpty() {
fmt.Printf("The SliceStack is empty!\n")
} else {
fmt.Printf("栈中的元素为: ")
for _, value := range s.Data {
fmt.Printf("%d ", value)
}
fmt.Println()
}
}
// 获取栈顶的元素
func (s *SliceStack) Peek() interface{} {
if s.IsEmpty() {
panic(errors.New("The SliceStack is empty!\n"))
}
return s.Data[s.Top-1]
}
// 进栈操作
func (s *SliceStack) Push(v interface{}) {
s.Data = append(s.Data, v)
s.Top++
fmt.Printf("Elem %d is pushed into the SliceSatck!\n", v)
}
// 出栈操作
func (s *SliceStack) Pop() interface{} {
if s.IsEmpty() {
panic(errors.New("The SliceStack is Empty!\n"))
}
v := s.Data[s.Top]
s.Top--
s.Data = append(s.Data[:s.Top+1])
fmt.Printf("Elem %d is poped from the SliceStack!\n", v)
return v
}
(3)在该项目的目录下编写一个名为 slicestack_test.go
程序测试以上的的功能逻辑是否正确,该程序的具体代码如下所示。
package SliceStack
import (
"fmt"
"testing"
)
func TestSliceStack(t *testing.T) {
var s Operate
s = NewSliceStack()
s.InitSliceStack()
s.Push(2)
s.Push(5)
s.Push(7)
s.Push(0)
s.Push(3)
s.DisplayStack()
fmt.Printf("The SliceStack's length is %d\n", s.Len())
s.Pop()
fmt.Printf("The SliceStack top elem is %d\n", s.Peek())
s.DisplayStack()
}
(4)在该项目的目录下执行 go test
命令进行测试验证,程序运行的结果如下所示。
The SliceStack is empty!
Elem 2 is pushed into the SliceSatck!
Elem 5 is pushed into the SliceSatck!
Elem 7 is pushed into the SliceSatck!
Elem 0 is pushed into the SliceSatck!
Elem 3 is pushed into the SliceSatck!
栈中的元素为: 2 5 7 0 3
The SliceStack's length is 5
Elem 3 is poped from the SliceStack!
The SliceStack top elem is 7
栈中的元素为: 2 5 7 0
(1)链表栈的基本操作如下代码所示。
type Operate interface {
// 初始化链表栈
InitStack()
// 判断链表栈是否为空
IsEmpty() bool
// 获取链表栈的长度
Len() int
// 输出栈中元素
DisplayStack()
// 获取链表栈栈顶元素
Peek() interface{}
// 元素进栈
Push(v interface{})
// 元素出栈
Pop() interface{}
}
(2)在任意目录下创建项目,编写一个名为 linkedstack.go
的程序实现以上的操作,该程序的代码如下所示。
package LinkedStack
import (
"errors"
"fmt"
)
type LinkedStackNode struct {
Value interface{}
Next *LinkedStackNode
}
type LinkedStack struct {
Top *LinkedStackNode
Length int
}
func NewLinkedStackNode() *LinkedStackNode {
return new(LinkedStackNode)
}
func NewLinkedStack() *LinkedStack {
return &LinkedStack{NewLinkedStackNode(), 0}
}
// 相应的操作接口
type Operate interface {
InitStack()
IsEmpty() bool
Len() int
DisplayStack()
Peek() interface{}
Push(v interface{})
Pop() interface{}
}
// 初始化链表栈
func (s *LinkedStack) InitStack() {
// 带头结点
s.Top.Next = nil
}
// 判断栈是否为空
func (s *LinkedStack) IsEmpty() bool {
return s.Top.Next == nil
}
// 获取栈的长度
func (s *LinkedStack) Len() int {
return s.Length
}
// 输出栈中元素(从栈顶到栈底)
func (s *LinkedStack) DisplayStack() {
if s.IsEmpty() {
fmt.Printf("The LinkedStack is empty!\n")
} else {
tail := s.Top
fmt.Printf("栈中元素(从栈顶到栈底)为: ")
for i := 0; i < s.Len(); i++ {
fmt.Printf("%d ", tail.Value)
tail = tail.Next
}
fmt.Println()
}
}
// 获取栈顶元素
func (s *LinkedStack) Peek() interface{} {
if s.IsEmpty() {
panic(errors.New("The LinkedStack is empty!"))
} else {
return s.Top.Value
}
}
// 进栈操作
func (s *LinkedStack) Push(v interface{}) {
tmp := &LinkedStackNode{0, s.Top}
tmp.Value = v
s.Top = tmp
fmt.Printf("Elem %d is pushed into the LinkedStack!\n", v)
s.Length++
}
// 出栈操作
func (s *LinkedStack) Pop() interface{} {
if s.IsEmpty() {
panic(errors.New("The LinkedStack is empty!\n"))
} else {
v := s.Top.Value
s.Top = s.Top.Next
s.Length--
fmt.Printf("Elem %d is poped from the LinkedStack!\n", v)
return v
}
}
(3)在该项目的目录下编写一个名为 linkedstack_test.go
程序测试以上的的功能逻辑是否正确,该程序的具体代码如下所示。
package LinkedStack
import (
"fmt"
"testing"
)
func TestLinkedStack(t *testing.T) {
var s Operate
s = NewLinkedStack()
s.InitStack()
s.DisplayStack()
s.Push(3)
s.Push(2)
s.Push(1)
s.DisplayStack()
s.Pop()
s.Pop()
s.Push(6)
s.Pop()
fmt.Printf("The LinkedStack's length is %d\n", s.Len())
fmt.Printf("The LinkedStack top elem is %d\n", s.Peek())
s.Push(9)
s.DisplayStack()
}
(4)在该项目的目录下执行 go test
命令进行测试验证,程序运行的结果如下所示。
The LinkedStack is empty!
Elem 3 is pushed into the LinkedStack!
Elem 2 is pushed into the LinkedStack!
Elem 1 is pushed into the LinkedStack!
栈中元素为: 1 2 3
Elem 1 is poped from the LinkedStack!
Elem 2 is poped from the LinkedStack!
Elem 6 is pushed into the LinkedStack!
Elem 6 is poped from the LinkedStack!
The LinkedStack's length is 1
The LinkedStack top elem is 3
Elem 9 is pushed into the LinkedStack!
栈中元素为: 9 3
参考书籍:《数据结构教程 第6版》(李春葆 主编)
参考书籍:《数据结构 C语言版》(严蔚敏、李冬梅、吴伟民著)