当前位置: 首页 > news >正文

[数据结构] 栈和队列

目录

1.栈

1.1 栈的概念

1.2 栈的模拟实现

1.3 栈的应用

1.3.1 将递归转为循环

1.3.2 括号匹配

1.3.3 逆波兰表达式求值

1.3.4 出栈入栈次序匹配

1.3.5 最小栈

2. 队列

2.1 队列的概念

2.2 队列中的方法

2.3 队列中方法的模拟实现

2.4 循环队列

2.4.1 循环队列的概念

2.4.2 循环队列的实现

2.5 双端队列

2.6 相关题目

2.6.1 用队列实现栈

2.6.2 用栈实现队列


1.栈

1.1 栈的概念

栈是一种特殊的线性表,只能从一端进行插入和删除操作,进行插入和删除操作的一端称为栈顶,另一端称为栈底。

压栈:将元素放入栈中,出栈:将元素从栈中取出。

栈遵循 先进后出,后进先出 原则。

栈在Java中代码实现的类是Stack类。

1.2 栈的模拟实现

这里用的顺序表实现的栈:

import java.util.Arrays;
public class MyStack {public int[] elem;public int stackSize;public MyStack() {elem = new int[10];}//入栈public void push(int val) {if(isFull()) {elem = Arrays.copyOf(elem,2 * elem.length);}elem[stackSize] = val;stackSize++;}//出栈public int pop() {if(isEmpty()) {return -1;}stackSize--;return elem[stackSize-1];}//查看栈顶元素public int peek() {if(isEmpty()) {return -1;}return elem[stackSize-1];}//返回栈的真实元素数量public int size() {return stackSize;}//判断栈为空public boolean isEmpty() {return stackSize == 0;}//判断栈为满public boolean isFull() {return stackSize == elem.length;}
}

1.3 栈的应用

1.3.1 将递归转为循环

逆序打印链表:

这里利用了递归的后进先出的原理,将链表的数据放入栈中,然后再从栈中取出来打印。

    //链表逆序(递归)public void printList(ListNode node) {if(node != null) {printList(node.next);System.out.println(node.val);}}//链表逆序(循环)public void printList1(ListNode node) {if(node == null) {return;}Stack<Integer> stack = new Stack<>();while(node != null) {stack.add(node.val);node = node.next;}while(!stack.isEmpty()) {System.out.print(stack.pop() + " ");}}

1.3.2 括号匹配

题目链接

解题思路:这里是利用栈,将字符串中的左符号依次放入栈中,直到遇到右符号,再与栈顶元素进行比较,看是否相同。

代码实现:

class Solution {public boolean isValid(String s) {Stack<Character> stack = new Stack<>();for(int i = 0; i < s.length(); i++) {char c = s.charAt(i);if(c == '[' || c == '(' || c == '{') {stack.push(c);}else {if(stack.isEmpty()) {return false;}if(stack.peek() == '(' && c == ')' || stack.peek() == '[' && c == ']' || stack.peek() == '{' && c == '}') {stack.pop();}else {return false;}}}if(stack.isEmpty()) {return true;}return false;      }
}

1.3.3 逆波兰表达式求值

题目链接

逆波兰表达式就是后缀表达式,是计算机运算使用的表达式,中缀表达式就是我们平时写的表达式,例如:2 *(3 +4)- 9  转换为后缀表达式就是: 2 3 4 + * 9  -  ,转换过程:

解题思路:这道题是将数字依次压入栈中,碰到运算符,取出栈顶元素作为右操作数,栈顶下的一个元素作为左操作数,运算完后放入栈中,循环往复。

代码实现:

class Solution {public int evalRPN(String[] tokens) {Stack<Integer> stack = new Stack<>();for(int i = 0; i < tokens.length; i++) {String s = tokens[i];if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {int x = stack.pop();int y = stack.pop();switch(s) {case "+":stack.push(y + x);break;case "-":stack.push(y - x);break;case "*":stack.push(y * x);break;case "/":stack.push(y / x);break;}}else {stack.push(Integer.parseInt(s));}}return stack.peek();}
}

1.3.4 出栈入栈次序匹配

题目链接

解题思路:

将第一个数组的数依次放入栈中,每次放完后跟第二个数组的元素比较,相同则抛出栈顶元素,不相同,则接着往栈中放元素。

代码实现:

import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** @param pushV int整型一维数组* @param popV int整型一维数组* @return bool布尔型*/public boolean IsPopOrder (int[] pushV, int[] popV) {Stack<Integer> stack = new Stack<>();int j = 0;for (int i = 0; i < pushV.length; i++) {stack.push(pushV[i]);while(!stack.isEmpty() && stack.peek() == popV[j]) {stack.pop();j++;}}if(!stack.isEmpty()) {return false;}return true;}
}

1.3.5 最小栈

题目链接

解题思路:这题需要设立两个栈,一个普通栈,一个最小栈,最小栈为空时,放入元素,然后后面新放入的元素要跟最小栈的栈顶元素比较,比栈顶元素大则不放,其他情况放。返回最小栈的栈顶元素就是最小值。

代码实现:

class MinStack {Stack<Integer> stack;Stack<Integer> minStack;public MinStack() {stack = new Stack<>();minStack = new Stack<>();}public void push(int val) {stack.push(val);if(minStack.isEmpty()) {minStack.push(val);}else {if(minStack.peek() >= val) {minStack.push(val);}}}public void pop() {if(stack.isEmpty()) {return;}int a = stack.pop();if(minStack.peek() == a) {minStack.pop();}}public int top() {if(stack.isEmpty()) {return -1;}return stack.peek();}public int getMin() {return minStack.peek();}
}/*** Your MinStack object will be instantiated and called as such:* MinStack obj = new MinStack();* obj.push(val);* obj.pop();* int param_3 = obj.top();* int param_4 = obj.getMin();*/

2. 队列

2.1 队列的概念

队列遵循先进先出,后进后出的原则,只允许在一端插入数据,另一端取出数据。插入数据的一端称为队尾,取出数据的一端称为队头。

在Java中队列是一个接口Queue,里面包含队列的抽象方法,具体实现是在LinkedList类里面实现的,队列的底层逻辑是链表。

2.2 队列中的方法

下面是队列中的抽象方法:

add和offer方法都是:往队列里面添加元素

remove和poll方法都是:删除队列中的元素

element和peek方法都是:获取队头元素

我们常用的方法是:offer() poll()  peek()

2.3 队列中方法的模拟实现

下面是我自己实现的队列(Queue)里面的方法:

package Queuedemo;public class MyQueue {static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;//入队操作(尾插)public void offer(int key) {ListNode node = new ListNode(key);if(isEmpty()) {head = node;last = node;return;}last.next = node;node.prev = last;last = node;}//出队操作public int poll() {if(isEmpty()) {return -1;}int val = head.val;if(head.next == null) {head = null;last = null;}else {head.next.prev = null;head = head.next;}return val;}//查询头节点的值public int peek() {if(isEmpty()) {return -1;}return head.val;}//判断队列是否为空public boolean isEmpty() {if(head == null && last == null) {return true;}return false;}//获取队列的大小public int size() {if(isEmpty()) {return -1;}ListNode node = head;int size = 0;while(head != null) {size++;}return size;}}

2.4 循环队列

2.4.1 循环队列的概念

循环队列通常是由数组实现的,图形如下:

这就是一个循环队列,将一个数组的首和尾连接起来。

rear如何走到最后再从头开始呢?

现在rear在6下标位置,假设让rear走到2位置,可以利用(rear + rear到2下标位置的距离) % 数组长度。

(6 + 4)% 8 = 2;

front如何从队头逆向移动到队尾?

现在front在1下标位置,假设让front走到5位置,可以利用(front + 数组长度 - front逆序到5下标位置的距离) % 数组长度。

(1 + 8 - 4)% 8 = 5;

如何区分队列是空还是满?

方法1:

添加size属性记录,每次入队时加1,出队时减1.

方法2:

保留一个位置,当(rear + 1) % 数组长度 等于 front 时候就停止添加元素,这时候rear所在位置没有元素,处于数组的最后一个位置。

方法3:

设置一个标记变量isFull :

初始情况下:front == rear 时,isFull = false。

添加元素时,每添加一个元素,判断front是否等于rear ,相等则isFull = true。

删除元素时,isFull = false。

2.4.2 循环队列的实现

设计循环队列

代码实现:

class MyCircularQueue {public int[] elem;public int front;//队头public int rear;//队尾//创建循环队列public MyCircularQueue(int k) {elem = new int[k+1];}//插入元素public boolean enQueue(int value) {//判断队列是否已满if(isFull()) {return false;}elem[rear] = value;rear = (rear + 1) % elem.length;return true;}//删除元素public boolean deQueue() {//判断队列是否为空if(isEmpty()) {return false;}front = (front + 1) % elem.length;return true;}//获取队首元素public int Front() {if(isEmpty()) {return -1;}return elem[front];}//获取队尾元素public int Rear() {if(isEmpty()) {return -1;}return elem[(rear + elem.length - 1) % elem.length];}//判断队列是否为空public boolean isEmpty() {return rear == front;}//判断队列是否已满public boolean isFull() {return (rear + 1) % elem.length == front;}}/*** Your MyCircularQueue object will be instantiated and called as such:* MyCircularQueue obj = new MyCircularQueue(k);* boolean param_1 = obj.enQueue(value);* boolean param_2 = obj.deQueue();* int param_3 = obj.Front();* int param_4 = obj.Rear();* boolean param_5 = obj.isEmpty();* boolean param_6 = obj.isFull();*/

2.5 双端队列

双端队列是指允许两队都可以进行插入和删除操作,在Java中对应的是Deque接口,具体实现方法的类是LinkedList类。

在实际开发中,栈和队列都可以实现该接口。

        //双端队列的顺序实现Deque<Integer> deque1 = new ArrayDeque<>();//双端队列的链式实现Deque<Integer> deque2 = new LinkedList<>();

2.6 相关题目

2.6.1 用队列实现栈

题目链接

代码实现:

class MyStack {public Queue<Integer> que1;public Queue<Integer> que2;public MyStack() {que1 = new LinkedList<>();que2 = new LinkedList<>();}//将元素存入栈中public void push(int x) {if(!que1.isEmpty()) {que1.offer(x);}else if(!que2.isEmpty()) {que2.offer(x);}else {que1.offer(x);}}//移除并返回栈顶元素public int pop() {if(!que1.isEmpty()) {int size = que1.size();while(size-1 != 0) {que2.offer(que1.poll());size--;}return que1.poll();}else if (!que2.isEmpty()) {int size = que2.size();while(size-1 != 0) {que1.offer(que2.poll());size--;}return que2.poll();}else {return -1;}}//返回栈顶元素public int top() {if(!que1.isEmpty()) {int size = que1.size();int tmp = -1;while(size != 0) {tmp = que1.peek();que2.offer(que1.poll());size--;}return tmp;}else if (!que2.isEmpty()) {int size = que2.size();int tmp = -1;while(size != 0) {tmp = que2.peek();que1.offer(que2.poll());size--;}return tmp;}else {return -1;}}//判断栈是否为空public boolean empty() {if(que1.isEmpty() && que2.isEmpty()) {return true;}return false;}
}/*** Your MyStack object will be instantiated and called as such:* MyStack obj = new MyStack();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.top();* boolean param_4 = obj.empty();*/

2.6.2 用栈实现队列

题目链接

代码实现:

class MyQueue {Stack<Integer> stack1;Stack<Integer> stack2;public MyQueue() {stack1 = new Stack<>();stack2 = new Stack<>();}//将元素放入队列中public void push(int x) {stack1.push(x);}//删除队列中元素并返回public int pop() {if(stack2.isEmpty()) {while(stack1.size() != 0) {stack2.push(stack1.pop());}}return stack2.pop();}//返回队列开头的元素public int peek() {if(stack2.isEmpty()) {while(stack1.size() != 0) {stack2.push(stack1.pop());}}return stack2.peek();}//判断队列是否为空public boolean empty() {if(stack1.isEmpty() && stack2.isEmpty()) {return true;}return false;}
}/*** Your MyQueue object will be instantiated and called as such:* MyQueue obj = new MyQueue();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.peek();* boolean param_4 = obj.empty();*/

文章转载自:

http://RWf6p5CY.brwwr.cn
http://6Oo6YFDv.brwwr.cn
http://wshF7Tjj.brwwr.cn
http://8Bcp4JkM.brwwr.cn
http://bhXKQTLm.brwwr.cn
http://8hI340wm.brwwr.cn
http://FcouOISp.brwwr.cn
http://RLYRwkmk.brwwr.cn
http://VhuoUsUz.brwwr.cn
http://Qa5Wxcce.brwwr.cn
http://vje0BaAj.brwwr.cn
http://fpoGBro2.brwwr.cn
http://UJTQcYV0.brwwr.cn
http://TL8auB1D.brwwr.cn
http://zM8ZNeWG.brwwr.cn
http://Tg7h2SGT.brwwr.cn
http://geZOKhEy.brwwr.cn
http://J0cExSHg.brwwr.cn
http://jBIrAOuv.brwwr.cn
http://YyqxHK1O.brwwr.cn
http://YWWTEJf5.brwwr.cn
http://rCjUzqmY.brwwr.cn
http://cZn0xoAP.brwwr.cn
http://iNxXhUdr.brwwr.cn
http://USMJcdHD.brwwr.cn
http://PDj2d8wI.brwwr.cn
http://42FPAeyE.brwwr.cn
http://HN4vy7WV.brwwr.cn
http://3GLGGm6u.brwwr.cn
http://MjsQ5pG6.brwwr.cn
http://www.dtcms.com/a/371948.html

相关文章:

  • 基于moduo库实现protobuf通信
  • Android开发-图像显示
  • OpenHarmony之设备风险管理平台(SecurityGuard)模块源码详解
  • Kotlin 协程之 Flow 的理解使用及源码解析
  • Vue2.x核心技术与实战(六)-Vuex
  • 认知篇#12:基于非深度学习方法的图像特征提取
  • 软考备考①
  • 信息安全工程师软考攻坚:第三章网络安全技术深度解析与实战训练
  • JDK17日期格式‘MMM’导致九月Sept/Sep格式化异常问题❗❗❗
  • Vulkan 学习(20)---- UniformBuffer 的使用
  • 微信小程序中实现AI对话、生成3D图像并使用xr-frame演示
  • 【不背八股】9.MySQL知识点汇总
  • MySQL6
  • 论文阅读:ICLR 2021 BAG OF TRICKS FOR ADVERSARIAL TRAINING
  • GD32自学笔记:4.ADC
  • LeetCode 522.最长特殊序列2
  • CentOS 7.2 虚机 ssh 登录报错在重启后无法进入系统
  • 腾讯混元 3D 2.0 Windows 便携版:低显存需求下的高效文/图生3D体验
  • 火山 RTC 引擎15 拉流 推流 地址生成器 、合流转推 开关
  • CesiumJS详解:打造专业级Web 3D地球仪与地图的JavaScript库
  • 数据结构:顺序表与链表
  • C++ 前缀和 高频笔试考点 实用技巧 牛客 DP34 [模板] 前缀和 题解 每日一题
  • kotlin - 平板分屏,左右拖动,2个Activity计算宽度,使用ActivityOptions、Rect(三)
  • 【软考架构】第七章 系统架构设计基础知识-7.2基于架构的软件开发方法:Architecture-Based Software Design,ABSD
  • Dify 从入门到精通(第 81/100 篇):Dify 的多模态模型监控(高级篇)
  • 2019年11月系统架构设计师真题及解析摘要
  • 基于Django的“社区爱心养老管理系统”设计与开发(源码+数据库+文档+PPT)
  • IO性能篇(二):文件读写的四种分类
  • 超越模仿,探寻智能的本源:从人类认知机制到下一代自然语言处理
  • 计算机视觉(十二):人工智能、机器学习与深度学习