Go的数据结构与实现【Stack】

介绍

栈是存放值的一种特殊容器,在插入与删除值时,这种结构遵循后进先出(Last-in-first-out,LIFO)的原则,也就是说,值可以任意插入栈中,但每次取出的都是此前插入的最后一个值。

实现

栈必须支持以下方法:
在这里插入图片描述
此外,还可以定义如下的方法:
在这里插入图片描述
此外,还应该提供一个类似构造器的NewStack()方法,当我们开始使用它时,它会初始化一个栈。

基于数组的简单实现

为了实现栈接口,我们可以用一个数组来存放其中的元素。

type T inttype Stack struct {sync.RWMutexarray []T
}

构造器NewStack()方法如下:

func NewStack() *Stack {stack := &Stack{}stack.array = []T{}return stack
}

接下来,我们去实现之前提到的操作方法:

// Push adds t to the top of the stack
func (s *Stack) Push(t T) {s.Lock()s.array = append(s.array, t)s.Unlock()
}

对于Push()方法,只需要将值添加到数组中,Go的原生语法为我们解决了这一步骤。

// Pop removes the top element from the stack
func (s *Stack) Pop() (*T, error) {if s.IsEmpty() {return nil, fmt.Errorf("stack must not be empty")}s.Lock()item := s.array[len(s.array)-1]s.array = s.array[0 : len(s.array)-1]s.Unlock()return &item, nil
}

Pop()方法中,首先检查栈是否为空,如果栈空,则返回空值以及错误信息,否则,将数组第一位取出,整个数组右移一位。

// Size returns the size of the stack
func (s *Stack) Size() int {s.RLock()defer s.RUnlock()return len(s.array)
}func (s *Stack) IsEmpty() bool {s.RLock()defer s.RUnlock()return len(s.array) == 0
}

至于额外的两个方法,即检查栈结构体中成员变量即可。注意到,栈结构体在定义时加入了锁资源,因此以上所有方法都是并发安全的。

单元测试

我们对实现的方法进行单元测试:

package stackimport "testing"var (t1 T = 1t2 T = 2t3 T = 3
)func TestStack_Push(t *testing.T) {stack := NewStack()stack.Push(t1)stack.Push(t2)stack.Push(t3)first := stack.array[0]last := stack.array[len(stack.array)-1]if first != t1 || last != t3 {t.Errorf("wrong order, expected first 1 and last 3 but got %d and %d", t1, t3)}
}func TestStack_Pop(t *testing.T) {stack := NewStack()stack.Push(t1)stack.Push(t2)stack.Push(t3)_, _ = stack.Pop()if size := stack.Size(); size != 2 {t.Errorf("wrong count, expected 2 and got %d", size)}_, _ = stack.Pop()_, _ = stack.Pop()if size := stack.Size(); size != 0 {t.Errorf("wrong count, expected 0 and got %d", size)}_, err := stack.Pop()if err == nil {t.Errorf("stack must not be empty")}
}func TestStack_Size(t *testing.T) {stack := NewStack()stack.Push(t1)stack.Push(t2)stack.Push(t3)if size := stack.Size(); size != 3 {t.Errorf("wrong count, expected 3 and got %d", size)}
}func TestStack_IsEmpty(t *testing.T) {stack := NewStack()empty := stack.IsEmpty()if !empty {t.Errorf("wrong status, expected true and got %t", empty)}stack.Push(t1)empty = stack.IsEmpty()if empty {t.Errorf("wrong status, expected false and got %t", empty)}
}

至此,单元测试通过,我们就完成了栈数据结构的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2906482.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

STM32第十节(中级篇):EXTI(第一节)——EXTI功能框图及初始化结构体讲解(包括STM32中断应用总结)

目录 前言 STM32第十节(中级篇):EXTI(第一节)——EXTI功能框图及初始化结构体讲解(包括STM32中断应用总结) EXTI功能框图 EXTI初始化结构体讲解 STM32中断应用总结 NVIC介绍 优先级 优先…

安卓Activity上滑关闭效果实现

最近在做一个屏保功能,需要支持如图的上滑关闭功能。 因为屏保是可以左右滑动切换的,内部是一个viewpager 做这个效果的时候,关键就是要注意外层拦截触摸事件时,需要有条件的拦截,不能影响到内部viewpager的滑动处理…

数据结构:静态链表(编程技巧)

文章目录 一、理解二、静态链表2.1、结构定义2.2、静态链表的初始化2.3、操作2.4、示例2.5、优点2.6、缺点 三、例题 ​ 链表的元素用数组存储, 用数组的下标模拟指针。 一、理解 如果有些程序设计语言没有指针类型,如何实现链表?   在使用…

电气识图基础

1 电气系统组成 电气系统分为强电系统和弱电系统。 强电系统有变配电系统,照明系统,动力系统,接地系统。弱电系统有消防报警系统,安全防范系统,楼宇自控系统等等。强电和弱电的区别? 在非电力工程领域。强电和弱电是以电压分界的,工作在交流220伏以上为强电,以下为弱电…

【目标跟踪】红绿灯跟踪

文章目录 一、前言二、结果三、跟踪3.1、检测输入3.2、预测与运动补偿3.3、第一次匹配3.4、第二次匹配3.5、第三次匹配3.6、航迹的起始与信息的发布 四、后记 一、前言 红绿灯场景对当前无人驾驶来说是个灾难性的挑战。暂且不说复杂的十字路口,譬如简单的人行道红绿…

马上蓝桥杯了,干货总结动态规划专题,祝你考场爆杀(拔高篇)最佳课题选择 书本整理 打鼹鼠 吃吃吃 非零字段划分

目录 最佳课题选择 思路: 书本整理 思路: 打鼹鼠 思路: 吃吃吃 思路: 非零字段划分 最佳课题选择 思路: 根本还是论文的分配,每个课题分配多少个论文是不确定的,这个也是很影响转…

天梯算法Day3整理

浮点数解析 炸鱼题掠过 冲突值 题面 解析 方法一 —— 并查集 按照边值排序,然后按边值从大到小遍历,通过并查集判断能否将所有点无冲突地归于两个集合。在判断时,若有两个点不得不产生冲突,则输出这两个点之间的边值并结束。…

PLC通讯时如何判断选用MODBUS方式还是现场总线方式?

在工业自动化领域,PLC扮演着至关重要的角色。然而,许多人在初次接触PLC通讯时,常因其复杂性而感到困扰。事实上,PLC的通讯并不如人们想象中的那么神秘,它主要只有两种类型:一种是需要编写代码的通讯方式&am…

Verilog语法之assign语句学习

assign语法主要是对组合逻辑的变量进行赋值的,就是把一个变量赋值给另一个变量,被复制的变量必须是wire类型的参数。 从仿真结果可以看出,data_in变量的值赋值给了data_out,assign语法就是赋值没有任何延迟,data_in是什么值&#…

服务器被挖矿了怎么办,实战清退

当我们发现服务器资源大量被占用的时候,疑似中招了怎么办 第一时间重启服务是不行的,这些挖矿木马一定是会伴随着你的重启而自动重启,一定时间内重新霸占你的服务器资源 第一步检查高占用进程 top -c ps -ef 要注意这里%CPU,如果…

[Python人工智能] 四十五.命名实体识别 (6)利用keras构建CNN-BiLSTM-ATT-CRF实体识别模型(注意力问题探讨)

从本专栏开始,作者正式研究Python深度学习、神经网络及人工智能相关知识。前文讲解融合Bert的实体识别研究,使用bert4keras和kears包来构建Bert+BiLSTM-CRF模型。这篇文章将详细结合如何利用keras和tensorflow构建基于注意力机制的CNN-BiLSTM-ATT-CRF模型,并实现中文实体识别…

【MySQL】16.事务管理(重点) -- 2

1. 事务隔离级别 如何理解隔离性1 MySQL服务可能会同时被多个客户端进程(线程)访问,访问的方式以事务方式进行一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所…

Linux 动静态库的制作,使用和加载

Linux 动静态库的制作,使用和加载 一.前置说明1.mylib.h2.mylib.c3.mymath.h mymath.c4.如何制作库 二.动静态库的制作1.静态库的制作1.制作2.使用一下静态库,验证是否成功打包 2.动态库的制作1.编译.c源文件文件生成.o目标文件2.打包生成动态库3.编写makefile文件,自动化制作动…

【SpringCloud】Ribbon负载均衡

🏡浩泽学编程:个人主页 🔥 推荐专栏:《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》《项目实战》 🛸学无止境,不骄不躁,知行合一 文章目录 …

警惕.360勒索病毒:如何预防.360勒索病毒攻击

导言: 在网络安全领域,勒索病毒是一种非常危险的恶意软件,它以其独特的加密方式和高昂的赎金要求,给个人和企业带来了严重的损失。.360勒索病毒便是其中之一,它属于BeijingCrypt勒索病毒家族,具有高度的隐…

NO12 蓝桥杯单片机之DS1302的使用

1 DS1302是什么 DS1302由两块存储器组成,一个是日历时钟寄存器还有一个是31位的静态RAM存储器。 而在蓝桥杯中常考的就是日历时钟寄存器,故这里只介绍日历时钟寄存器。简单来说,其就是一个“电子表”,他会自动的实时记录时间&am…

Suno - AI自动作曲

文章目录 关于 Suno创作歌词结构曲风 关于 Suno Suno 是一款自动编曲工具。 官网 :https://www.suno.ai Suno is building a future where anyone can make great music. Whether you’re a shower singer or a charting artist, we break barriers between you …

关于Devc++调试的问题以及解决STL变量无法查看

目前Devc的调试主要有以下几点: 1.调试不能直接查看stl变量,会卡死不动 2.目前单步进入只能用鼠标键按 3.若想按下一步进入函数体内,要在函数体内打上断点才行 4.调试到return 0 ;上一句就停了,不会结束程序 5.目前F2跳至断点…

matplotlib 绘图

matplotlib 绘图 方便设置legend图例的位置 ax1.legend(loc‘upper center’, bbox_to_anchor(0.3, -0.1)) ax2.legend(loc‘upper center’, bbox_to_anchor(0.6, -0.1)) import numpy as np import matplotlib.pyplot as plt from scipy.stats import norm from scipy.inter…

SpringBoot Redis的使用

官方文档: 官方文档:Spring Data Redis :: Spring Data Redis 和jedis一样,SpringBoot Redis 也可以让我在Java代码中使用redis,同样也是通过引入maven依赖的形式。 加速访问github: 使用steam可以免费加速访问github Spring…