GO语言-数据结构-栈

目录

1.栈的顺序存储实现

1.1结构体定义

1.2 初始化栈

1.3入栈

1.4出栈

1.5完整代码

1.6拓展-一个数组实现两个栈

2.栈的链式存储实现

2.1链栈的结构体定义

2.2链栈的初始化

2.3链栈的入栈

2.4链栈的出栈

2.5链栈实现的完整代码


栈(stack),是具有一定操作约束的线性表。其只能在一端(栈顶,Top)做插入、删除操作。

  • 插入数据:入栈(Push)
  • 删除数据:出栈(Pop)
  • 先入后出:Last In First Out(LIFO)

GO语言-数据结构-栈_第1张图片

栈的抽象数据类型描述

数据对象集:一个有0或多个元素的线性表。

操作集:

  1. 生成空栈,其最大长度为MaxSize
  2. 判断栈是否已满
  3. 判断栈是否为空
  4. 将元素压入栈
  5. 将栈顶元素返回并删除

1.栈的顺序存储实现

栈的顺序存储结构体,通常由一个数组一个记录栈顶元素位置的变量组成。

1.1结构体定义

type Stack struct {
	MaxSize int
	Top     int
	arr     [10]int
}

1.2 初始化栈

func initStack() (stack *Stack) {
	stack = &Stack{
		MaxSize: 10,
		Top:     -1,
		arr:     [10]int{},
	}
	return stack
}

1.3入栈

GO语言-数据结构-栈_第2张图片

func (s *Stack) push(v int) error {
	//判断栈是否满
	if s.MaxSize-1 == s.Top {
		return errors.New("栈已满,无法插入数据")
	}

	s.Top++          //栈顶+1
	s.arr[s.Top] = v //入栈

	return nil
}

1.4出栈

GO语言-数据结构-栈_第3张图片

func (s *Stack) pop() (int, error) {
	//判断栈是否为空
	if s.Top == -1 {
		return 0, errors.New("error: 栈为空")
	}

	v := s.arr[s.Top] //出栈
	s.Top--           //栈顶-1

	return v, nil
}

1.5完整代码

package main

import (
	"errors"
	"fmt"
)

type Stack struct {
	MaxSize int
	Top     int
	arr     [10]int
}

func main() {
	//初始化一个栈
	stack1 := initStack()

	//验证空栈pop报错
	fmt.Println("---空栈pop报错---")
	_, err := stack1.pop()
	if err != nil {
		fmt.Println(err)
	}

	//入栈
	fmt.Println("---栈满push报错---")
	for i := 1; 1 <= 20; i++ {
		err := stack1.push(i)
		if err != nil {
			fmt.Println(err)
			break
		}
	}

	//出栈
	v, _ := stack1.pop()
	fmt.Println("---pop出栈---:", v)
}

func initStack() (stack *Stack) {
	stack = &Stack{
		MaxSize: 10,
		Top:     -1,
		arr:     [10]int{},
	}
	return stack
}

func (s *Stack) push(v int) error {
	//判断栈是否满
	if s.MaxSize-1 == s.Top {
		return errors.New("栈已满,无法插入数据")
	}

	s.Top++          //栈顶+1
	s.arr[s.Top] = v //入栈

	return nil
}

func (s *Stack) pop() (int, error) {
	//判断栈是否为空
	if s.Top == -1 {
		return 0, errors.New("error: 栈为空")
	}

	v := s.arr[s.Top] //出栈
	s.Top--           //栈顶-1

	return v, nil
}

GO语言-数据结构-栈_第4张图片  

1.6拓展-一个数组实现两个栈

使用一个数组实现两个堆栈,要求最大地利用数组空间。使数组只要有空间,入栈操作就可以成功。

GO语言-数据结构-栈_第5张图片

package main

import (
	"errors"
	"fmt"
)

type Stack struct {
	Top1 int
	Top2 int
	arr  [10]int
}

func main() {
	//初始化一个栈
	stack1 := initStack()
	fmt.Println(stack1.arr)

	//验证空栈pop报错
	fmt.Println("---空栈pop报错---")
	_, err := stack1.pop(1)
	if err != nil {
		fmt.Println(err)
	}
	_, err = stack1.pop(2)
	if err != nil {
		fmt.Println(err)
	}

	//入栈
	fmt.Println("---栈满push报错---")
	for i := 1; i <= 5; i++ {
		err := stack1.push(i, 1)
		if err != nil {
			fmt.Println(err)
			break
		}
	}
	for i := 1; i <= 6; i++ {
		err := stack1.push(i, 2)
		if err != nil {
			fmt.Println(err)
			break
		}
	}
	fmt.Println(stack1.arr)

	//出栈
	v, _ := stack1.pop(1)
	fmt.Println("---pop出栈---:", v)
	v, _ = stack1.pop(2)
	fmt.Println("---pop出栈---:", v)
}

func initStack() (stack *Stack) {
	stack = &Stack{
		Top1: -1,
		Top2: 10,
		arr:  [10]int{},
	}
	return stack
}

//通过tag区分插入哪个队列
func (s *Stack) push(v int, tag int) error {
	//判断栈是否满
	if s.Top2-s.Top1 == 1 {
		return errors.New("栈已满,无法插入数据")
	}

	if tag == 1 {
		s.Top1++          //栈A,栈顶+1
		s.arr[s.Top1] = v //入栈
	} else if tag == 2 {
		s.Top2--          //栈B,栈顶-1
		s.arr[s.Top2] = v //入栈
	} else {
		return errors.New("tag参数不合法, 需要传入1或2")
	}

	return nil
}

func (s *Stack) pop(tag int) (int, error) {
	var v int
	//判断栈是否为空
	if tag == 1 {
		if s.Top1 == -1 {
			return 0, errors.New("error: 栈A为空")
		}
		v = s.arr[s.Top1] //出栈
		s.Top1--          //栈A,栈顶-1
	} else if tag == 2 {
		if s.Top2 == 10 {
			return 0, errors.New("error: 栈B为空")
		}
		v = s.arr[s.Top2] //出栈
		s.Top2++          //栈B,栈顶+1
	}

	return v, nil
}

GO语言-数据结构-栈_第6张图片

2.栈的链式存储实现

链栈

GO语言-数据结构-栈_第7张图片

2.1链栈的结构体定义

type LinkStack struct {
	data int
	next *LinkStack
}

2.2链栈的初始化

func initLinkStack() (linkStack *LinkStack) {
	//初始化链栈,新建链栈头节点
	linkStack = &LinkStack{
		data: -1,
		next: nil,
	}
	return linkStack
}

2.3链栈的入栈

GO语言-数据结构-栈_第8张图片

func (s *LinkStack) push(v int) {
	//链栈可先不考虑栈满,因为目前没有对栈做限制

	pushNode := &LinkStack{
		data: v,
		next: nil,
	}

	pushNode.next = s.next //入栈节点的next指向头节点的next节点
	s.next = pushNode      //头节点指向入栈节点
}

2.4链栈的出栈

GO语言-数据结构-栈_第9张图片

func (s *LinkStack) pop() (int, error) {
	var v int
	//判断栈是否为空
	if s.next == nil {
		return 0, errors.New("error: 栈为空")
	}

	tmpTop := s.next
	v = tmpTop.data //出栈,获取节点的元素值

	s.next = tmpTop.next //头节点指向原栈顶节点的下一个节点
	tmpTop.next = nil    //原栈顶节点指向nil

	return v, nil
}

2.5链栈实现的完整代码

package main

import (
	"errors"
	"fmt"
)

type LinkStack struct {
	data int
	next *LinkStack
}

func main() {
	//初始化一个链栈
	fmt.Println("---初始化链栈---")
	linkStack1 := initLinkStack()

	//入栈
	fmt.Println("---入栈---")
	for i := 1; i <= 5; i++ {
		linkStack1.push(i)
		fmt.Printf("第%v次出栈, 值为:%v\n", i, i)
	}

	//出栈
	fmt.Println("---出栈---")
	for i := 1; i <= 6; i++ {
		v, err := linkStack1.pop()
		if err != nil {
			fmt.Println(err)
			break
		}
		fmt.Printf("第%v次出栈, 值为:%v\n", i, v)
	}
}

func initLinkStack() (linkStack *LinkStack) {
	//初始化链栈,新建链栈头节点
	linkStack = &LinkStack{
		data: -1,
		next: nil,
	}
	return linkStack
}

func (s *LinkStack) push(v int) {
	//链栈可先不考虑栈满,因为目前没有对栈做限制

	pushNode := &LinkStack{
		data: v,
		next: nil,
	}

	pushNode.next = s.next //入栈节点的next指向头节点的next节点
	s.next = pushNode      //头节点指向入栈节点
}

func (s *LinkStack) pop() (int, error) {
	var v int
	//判断栈是否为空
	if s.next == nil {
		return 0, errors.New("error: 栈为空")
	}

	tmpTop := s.next
	v = tmpTop.data //出栈,获取节点的元素值

	s.next = tmpTop.next //头节点指向原栈顶节点的下一个节点
	tmpTop.next = nil    //原栈顶节点指向nil

	return v, nil
}

GO语言-数据结构-栈_第10张图片

你可能感兴趣的:(数据结构与算法,Golang,数据结构,go)