@

一 前言

go语言中,并没有栈与队列相关的数据结构,但是我们可以借助切片来实现栈与队列的操作;接下来我们一起实现栈与队列基本操作,并且还会实现用栈实现队列用队列实现栈的操作。

二 实现栈与队列基本操作

2.1 栈基本操作

go语言实现栈和队列主要用到append 和切片(用内置数组类型进行操作)

  1. //创建栈
  2. stack := make([]int, 0)
  3. //push压入栈
  4. stack = append(stack, 10)
  5. //pop弹出
  6. v := stack[len(stack)-1]
  7. stack = stack[:len(stack)-1]
  8. //检查栈空
  9. len(stack) == 0

2.2 队列基本操作

  1. //创建队列
  2. queue := make([]int, 0)
  3. //enqueue入队
  4. queue = append(queue, 10)
  5. //dequeue出队
  6. v := queue[0]
  7. queue = queue[1:]
  8. //检查队列为空
  9. len(queue) == 0

三 用栈实现队列

3.1 理论

使用栈来模式队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈一个输入栈,一个输出栈,这里要注意输入栈和输出栈的关系。

下面动画模拟以下队列的执行过程如下:

执行语句:

  1. queue.push(1);
  2. queue.push(2);
  3. queue.pop(); 注意此时的输出栈的操作
  4. queue.push(3);
  5. queue.push(4);
  6. queue.pop();
  7. queue.pop();注意此时的输出栈的操作
  8. queue.pop();
  9. queue.empty();



在push数据的时候,只要数据放进输入栈就好,但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入),再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。

最后如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。

3.2 算法题

接下来看一下LeetCode原题

232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

实现 MyQueue 类:

void push(int x) 将元素 x 推到队列的末尾

int pop() 从队列的开头移除并返回元素

int peek() 返回队列开头的元素

boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。

你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

3.3 思路

解决这个问题,需要一个输出栈和输入栈

先将数据放到输入栈,再把数据从输入栈放到输出栈,此时输出栈输出数据的顺序就和队列一样了,先入先出

3.4 代码部分

  1. type MyQueue struct {
  2. stackIn []int // 用来保存Push数据
  3. stackOut []int // 用来保存Pop数据
  4. }
  5. // 栈构造器
  6. func Constructor() MyQueue {
  7. return MyQueue{
  8. stackIn: make([]int, 0),
  9. stackOut: make([]int, 0),
  10. }
  11. }
  12. func (this *MyQueue) Push(x int) {
  13. // 判断stackOut中是否有元素,有的话全部放到stackIn
  14. for len(this.stackOut) != 0 {
  15. val := this.stackOut[len(this.stackOut)-1]
  16. this.stackOut = this.stackOut[:len(this.stackOut)-1]
  17. this.stackIn = append(this.stackIn, val)
  18. }
  19. // 将数据加进stackIn
  20. this.stackIn = append(this.stackIn, x)
  21. }
  22. func (this *MyQueue) Pop() int {
  23. // 判断stackIn中是否有元素,有的话全部放到stackOut
  24. for len(this.stackIn) != 0 {
  25. val := this.stackIn[len(this.stackIn)-1]
  26. this.stackIn = this.stackIn[:len(this.stackIn)-1]
  27. this.stackOut = append(this.stackOut, val)
  28. }
  29. // stackOut为零,说明没有元素,return 0
  30. if len(this.stackOut) == 0 {
  31. return 0
  32. }
  33. // stackOut Pop 元素
  34. res := this.stackOut[len(this.stackOut)-1]
  35. this.stackOut = this.stackOut[:len(this.stackOut)-1]
  36. return res
  37. }
  38. func (this *MyQueue) Peek() int {
  39. // 调用Pop()方法
  40. val := this.Pop()
  41. // val为零,说明没有元素,return 0
  42. if val == 0 {
  43. return 0
  44. }
  45. // Pop()方法删除了val,这里加上
  46. this.stackOut = append(this.stackOut, val)
  47. return val
  48. }
  49. func (this *MyQueue) Empty() bool {
  50. // 两个栈都为空,说明为空,否则不为空
  51. return len(this.stackOut) == 0 && len(this.stackIn) == 0
  52. }

代码可以直接拿到力扣上运行。我已经将细节全部用注释解释了,如果不懂可以私信博主。

四 用队列实现栈

4.1 理论

队列模拟栈,其实一个队列就够了,那么我们先说一说两个队列来实现栈的思路。

队列是先进先出的规则,把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并没有变成先进后出的顺序。

所以用栈实现队列, 和用队列实现栈的思路还是不一样的,这取决于这两个数据结构的性质。

但是依然还是要用两个队列来模拟栈,只不过没有输入和输出的关系,而是另一个队列完全用又来备份的!

如下面动画所示,用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。

模拟的队列执行语句如下:

  1. queue.push(1);
  2. queue.push(2);
  3. queue.pop(); // 注意弹出的操作
  4. queue.push(3);
  5. queue.push(4);
  6. queue.pop(); // 注意弹出的操作
  7. queue.pop();
  8. queue.pop();
  9. queue.empty();

4.2 算法题

接下来看一下LeetCode原题

225. 用队列实现栈

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

实现 MyStack 类:

void push(int x) 将元素 x 压入栈顶。

int pop() 移除并返回栈顶元素。

int top() 返回栈顶元素。

boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

注意:

你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。

你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。

4.3 思路

用两个队列que1和que2实现队列的功能,que2其实完全就是一个备份的作用,把que1最后面的元素以外的元素都备份到que2,然后弹出最后面的元素,再把其他元素从que2导回que1。

4.4 使用两个队列实现

  1. type MyStack struct {
  2. //创建两个队列
  3. queue1 []int
  4. queue2 []int
  5. }
  6. func Constructor() MyStack {
  7. return MyStack{ //初始化
  8. queue1:make([]int,0),
  9. queue2:make([]int,0),
  10. }
  11. }
  12. func (this *MyStack) Push(x int) {
  13. //先将数据存在queue2中
  14. this.queue2 = append(this.queue2,x)
  15. //将queue1中所有元素移到queue2中,再将两个队列进行交换
  16. this.Move()
  17. }
  18. func (this *MyStack) Move(){
  19. if len(this.queue1) == 0{
  20. //交换,queue1置为queue2,queue2置为空
  21. this.queue1,this.queue2 = this.queue2,this.queue1
  22. }else{
  23. //queue1元素从头开始一个一个追加到queue2中
  24. this.queue2 = append(this.queue2,this.queue1[0])
  25. this.queue1 = this.queue1[1:] //去除第一个元素
  26. this.Move() //重复
  27. }
  28. }
  29. func (this *MyStack) Pop() int {
  30. val := this.queue1[0]
  31. this.queue1 = this.queue1[1:] //去除第一个元素
  32. return val
  33. }
  34. func (this *MyStack) Top() int {
  35. return this.queue1[0] //直接返回
  36. }
  37. func (this *MyStack) Empty() bool {
  38. return len(this.queue1) == 0
  39. }

4.5 优化

其实这道题目就是用一个队列就够了。

一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。

4.6 使用一个队列实现

  1. type MyStack struct {
  2. queue []int//创建一个队列
  3. }
  4. /** Initialize your data structure here. */
  5. func Constructor() MyStack {
  6. return MyStack{ //初始化
  7. queue:make([]int,0),
  8. }
  9. }
  10. /** Push element x onto stack. */
  11. func (this *MyStack) Push(x int) {
  12. //添加元素
  13. this.queue=append(this.queue,x)
  14. }
  15. /** Removes the element on top of the stack and returns that element. */
  16. func (this *MyStack) Pop() int {
  17. n:=len(this.queue)-1//判断长度
  18. for n!=0{ //除了最后一个,其余的都重新添加到队列里
  19. val:=this.queue[0]
  20. this.queue=this.queue[1:]
  21. this.queue=append(this.queue,val)
  22. n--
  23. }
  24. //弹出元素
  25. val:=this.queue[0]
  26. this.queue=this.queue[1:]
  27. return val
  28. }
  29. /** Get the top element. */
  30. func (this *MyStack) Top() int {
  31. //利用Pop函数,弹出来的元素重新添加
  32. val:=this.Pop()
  33. this.queue=append(this.queue,val)
  34. return val
  35. }
  36. /** Returns whether the stack is empty. */
  37. func (this *MyStack) Empty() bool {
  38. return len(this.queue)==0
  39. }

Go实现栈与队列基本操作的更多相关文章

  1. 栈与队列基本操作 Java实现

    一.顺序栈 //数组实现顺序栈 public class OrderStack { private String[] elem; private int top; OrderStack(int k) ...

  2. c++用类写栈和队列的简单基本操作(实验)

    继续更文.这次用类来写栈和队列,都是用数组模拟的: 以下是栈和队列的定义: 然后分别是栈和队列的类: 完整代码贴上: 栈 //使用类来定义栈 class ZHAN { public: STACK s; ...

  3. 二、 编写一个类,用两个栈实现队列,支持队列的基本操作(add,poll,peek)

    请指教交流! package com.it.hxs.c01; import java.util.Stack; /* 编写一个类,用两个栈实现队列,支持队列的基本操作(add,poll,peek) */ ...

  4. SDUT-3335_数据结构实验之栈与队列八:栈的基本操作

    数据结构实验之栈与队列八:栈的基本操作 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 堆栈是一种基本的数据结构.堆栈具 ...

  5. C实现栈和队列

    这两天再学习了数据结构的栈和队列,思想很简单,可能是学习PHP那会没有直接使用栈和队列,写的太少,所以用具体代码实现的时候出现了各种错误,感觉还是C语言功底不行.栈和队列不论在面试中还是笔试中都很重要 ...

  6. 用JS描述的数据结构及算法表示——栈和队列(基础版)

    前言:找了上课时数据结构的教程来看,但是用的语言是c++,所以具体实现在网上搜大神的博客来看,我看到的大神们的博客都写得特别好,不止讲了最基本的思想和算法实现,更多的是侧重于实例运用,一边看一边在心里 ...

  7. Swift 算法实战之路:栈和队列

    这期的内容有点剑走偏锋,我们来讨论一下栈和队列.Swift语言中没有内设的栈和队列,很多扩展库中使用Generic Type来实现栈或是队列.笔者觉得最实用的实现方法是使用数组,本期主要内容有: 栈和 ...

  8. 数据结构与算法(C/C++版)【栈与队列】

    第三章<栈与队列> (一)栈简介  栈(Stack):只允许在一端进行插入或删除操作的线性表.首先栈是一种线性表,但是限定这种线性表只能在某一端进行插入和删除操作栈顶(top):线性表允许 ...

  9. 数据结构(C语言版)-第3章 栈和队列

    3.1 栈和队列的定义和特点3.2 案例引入3.3 栈的表示和操作的实现3.4 栈与递归3.5 队列的的表示和操作的实现3.6 案例分析与实现 基本操作有入栈.出栈.读栈顶元素值.建栈.判断栈满.栈空 ...

随机推荐

  1. PHP实现获取本地视频进行随机播放

    创建一个文件夹,里面随便方视频文件即可 列如文件夹名字是assets代码如下 <? $handler = opendir('./assets/mp4/');//当前目录中的文件夹下的文件夹 需要 ...

  2. KingbaseES 多列分区的方法与性能

    前言 对于多列分区,可以选择单级多列的范围分区,也可以选择范围加子分区的方式.但二者在不同场景下对于性能是有差异的,这里的性能差异主要是分区裁剪引起的差异. 例子 创建两张分区表,采取不同的分区策略: ...

  3. Netty使用手册翻译

    前言 痛点 时至今日,我们通常会使用应用程序或第三方库去提供通信功能.比如:我们通常使用HTTP客户端库去Web服务器检索信息;通过web服务调用一个远程程序.然而,一个通用协议或者它的实现往往不能适 ...

  4. 字节跳动 DanceCC 工具链系列之Xcode LLDB耗时监控统计方案

    作者:李卓立 仲凯宁 背景介绍 在<字节跳动 DanceCC 工具链系列之Swift 调试性能的优化方案>[1]一文中,我们介绍了如何使用自定义的工具链,来针对性优化调试器的性能,解决大型 ...

  5. Java根据Freemarker模板生成Word文件

    1.  准备模板 模板 + 数据 = 模型 1.将准备好的Word模板文件另存为.xml文件(PS:建议使用WPS来创建Word文件,不建议用Office) 2.将.xml文件重命名为.ftl文件 3 ...

  6. Rust-函数

    函数结构 函数要点 函数名和变量名使用蛇形命名法(snake case),例如 fn add_two() -> {} 函数的位置可以随便放,Rust 不关心我们在哪里定义了函数,只要有定义即可 ...

  7. 面试说:聊聊JavaScript中的数据类型

    前言 请讲下 JavaScript 中的数据类型? 前端面试中,估计大家都被这么问过. 答:Javascript 中的数据类型包括原始类型和引用类型.其中原始类型包括 null.undefined.b ...

  8. ProxySQL Main库

    转载自:https://www.jianshu.com/p/eee03c5ec879 Main库表清单 Admin> SHOW TABLES FROM main; +-------------- ...

  9. 1.通俗易懂理解Kubernetes核心组件及原理

    文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247483736&idx=1&sn=0cbc3d6a ...

  10. Init Container(初始化容器)

    在很多应用场景中,应用在启动之前都需要进行如下初始化操作. ◎ 等待其他关联组件正确运行(例如数据库或某个后台服务). ◎ 基于环境变量或配置模板生成配置文件. ◎ 从远程数据库获取本地所需配置,或者 ...