数据结构线性表-栈和队列的实现

1. 栈(Stack)

1.1 概念

:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据在栈顶。

1.2 栈的使用

从上图中可以看到,Stack继承了Vector,Vector和ArrayList类似,都是动态的顺序表,不同的Vector是线程安全;Vector类,是线程安全的动态数组,但是性能较差 , 现在已经不是很常用了 , 可以说已经过时了。

常用方法

方法功能
Stack()构造一个空的栈
E push(E e)将e入栈,并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素个数
boolean empty()检测栈是否为空

public static void main(String[] args) {
Stack<Integer> s = new Stack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s.size()); // 获取栈中有效元素个数---> 4
System.out.println(s.peek()); // 获取栈顶元素---> 4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else{
System.out.println(s.size());}
}

1.3 栈的模拟实现

从上图中可以看到,Stack继承了Vector,Vector和ArrayList类似,都是动态的顺序表,不同的是Vector是线程安 全的。

代码实现

1. 构造方法

class MyStack{private int[] arr;// size 记录栈中元素个数private int size;public MyStack(){// 调用无参构造方法 默认最大容量12this(12);}public MyStack(int MaxSize){this.arr = new int[MaxSize];}
}

2. 入栈(push)

// 入栈public int push(int value){if(this.size == arr.length){// 栈满 ,需要扩容int[] copyArr;// 复制arr 数组并扩容一倍copyArr = Arrays.copyOf(arr,2 * arr.length);arr = copyArr;}//将元素添加到size位置this.arr[size] = value;// 元素个数加一this.size++;// 返回添加元素return value;}

3. 出栈(pop)

// 出栈public int pop(){if(this.size == 0){//没有元素//抛出运行时异常,此处也可以自定义异常throw new RuntimeException("栈中没有元素,不能出栈....");}// 获得栈顶元素int value = this.arr[size - 1];// size - 1 之后, 下一次插入时会覆盖原数据,利用覆盖替代删除this.size--;return value;}

4.获取栈顶元素(peek)

// 获取栈顶元素public int peek(){if(this.size == 0){//没有元素//抛出运行时异常,此处也可以自定义异常throw new RuntimeException("栈中没有元素,不能出栈....");}return this.arr[this.size - 1];}

5.获取元素个数(getSize)

//获取元素个数public int getSize(){return this.size;}

6.判断栈是否为空(isEmpty)

//判断元素是否为空public boolean isEmpty(){return this.size == 0;}

完整代码

import java.util.Arrays;public class MyStack{private int[] arr;// size 记录栈中元素个数private int size;public MyStack(){// 调用无参构造方法 默认最大容量12this(12);}public MyStack(int MaxSize){this.arr = new int[MaxSize];}// 入栈public int push(int value){if(this.size == arr.length){// 栈满 ,需要扩容int[] copyArr;// 复制arr 数组并扩容一倍copyArr = Arrays.copyOf(arr,2 * arr.length);arr = copyArr;}//将元素添加到size位置this.arr[size] = value;// 元素个数加一this.size++;// 返回添加元素return value;}// 出栈public int pop(){if(isEmpty()){//没有元素//抛出运行时异常,此处也可以自定义异常throw new RuntimeException("栈中没有元素,不能出栈....");}// 获得栈顶元素int value = this.arr[size - 1];// size - 1 之后, 下一次插入时会覆盖原数据,利用覆盖替代删除this.size--;return value;}// 获取栈顶元素public int peek(){if(isEmpty()){//没有元素//抛出运行时异常,此处也可以自定义异常throw new RuntimeException("栈中没有元素,不能出栈....");}return this.arr[this.size - 1];}//获取元素个数public int getSize(){return this.size;}//判断元素是否为空public boolean isEmpty(){return this.size == 0;}
}

1.4 栈的应用场景

1. 改变元素的序列

1. 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列不可能的一个出栈序列是( )

     A: 1,4,3,2                      B: 2,3,4,1                 C: 3,1,4,2                            D: 3,4,2,1

根据栈先进后出的性质,结合题目中进栈的过程中也可以出栈,如A选项:1进1出,2进3进4进,4出3出2出即符合题意,同理C选项,1进2进3进3出之后不可能直接出1,故C选项不可能实现。

2.一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E依次入栈,然后再依次出栈,则元素出栈的顺 序是( )。

A: 12345ABCDE          B: EDCBA54321         C: ABCDE12345           D: 54321EDCBA

先进后出,依次入栈,依次出栈,故B选项合理

2. 将递归转化为循环

递归实现逆序打印

 public void display(ListNode head){if(head == null){return;}//直到链表末尾,再归回去if(head.next == null){System.out.println(head.val+" ");return;}display(head.next);System.out.println(head.val+" ");
}

使用栈实现逆序打印

public void display(ListNode head){if(head == null){return;}Stack<ListNode> stack  = new Stack<>();ListNode cur = head;while(cur!= null){stack.push(cur);cur = cur.next;}while(!stack.empty()){ListNode ret =   stack.pop();System.out.println(ret.val+" ");}}

2. 队列(Queue)

2.1 概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)

入队列:进行插入操作的一端称为队尾(Tail/Rear)

出队列:进行删除操作的一端称为队头 (Head/Front)

2.2 队列的使用

在Java中,Queue是个接口,底层是通过链表实现的。


方法功能
boolean offer(E e) 入队列
E poll() 出队列
peek() 获取队头元素
int size() 获取队列中有效元素个数
boolean isEmpty()检测队列是否为空

注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

public static void main(String[] args) {
Queue<Integer> q = new LinkedList<>();
q.offer(1);
q.offer(2);
q.offer(3);
q.offer(4);
q.offer(5); // 从队尾入队列
System.out.println(q.size());
System.out.println(q.peek()); // 获取队头元素
q.poll();
System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
if(q.isEmpty()){
System.out.println("队列空");
}else{
System.out.println(q.size());
}
}

2.3 队列模拟实现

队列中既然可以存储元素,那底层肯定要有能够保存元素的空间,通过前面线性表的学习了解到常见的空间类型有两种:顺序结构和链式结构 。

 
public class Queue {// 双向链表节点public static class ListNode{ListNode next;ListNode prev;int value;ListNode(int value){this.value = value;}}ListNode first; // 队头ListNode last; // 队尾int size = 0;// 入队列---向双向链表位置插入新节点public void offer(int e){ListNode newNode = new ListNode(e);if(first == null){first = newNode;
// last = newNode;}else{last.next = newNode;newNode.prev = last;
// last = newNode;}last = newNode;size++;}// 出队列---将双向链表第一个节点删除掉public int poll(){
// 1. 队列为空
// 2. 队列中只有一个元素----链表中只有一个节点---直接删除
// 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除int value = 0;if(first == null){return null;}else if(first == last){last = null;first = null;}else{value = first.value;first = first.next;first.prev.next = null;first.prev = null;}--size;return value;}// 获取队头元素---获取链public int peek(){if(first == null){return null;}return first.value;}public int size() {return size;}public boolean isEmpty(){return first == null;}
}

2.4 循环队列

实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列通常使用数组实现。

数组下标循环的小技巧 

1. 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length

2. 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset)%array.length

如何区分空与满

1. 通过添加 size 属性记录
2. 保留一个位置
3. 使用标记

public class CircularQueue {private int front;private int rear;private int[] circle;public CircularQueue(int k) {//浪费掉一个存储空间circle = new int[k+1];}//入队列public boolean enQueue(int value) {if (isFull()) {return false;}circle[rear] = value;//因为是循环队列,不能写++,要以取模的方式rear = (rear + 1) % circle.length;return true;}//出队列public boolean deQueue() {if (isEmpty()) {return false;}front = (front + 1) % circle.length;return true;}//返回队头元素public int Front() {if (isEmpty()) {return -1;}return circle[front];}//返回队尾元素public int Rear() {if (isEmpty()) {return -1;}return circle[(rear - 1 + circle.length) % circle.length];}public boolean isEmpty() {return rear == front;}public boolean isFull() {return ((rear + 1) % circle.length) == front;}}

3.  双端队列 (Deque)

双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

Deque是一个接口,使用时必须创建LinkedList的对象。

在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口。

Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

4. 栈和队列的互相实现

用栈实现队列:

class MyQueue {public Stack<Integer> stack1;public 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()) {
in2out();}return stack2.pop();}public int peek() {if (stack2.isEmpty()){
in2out();}return stack2.peek();}public boolean empty() {return stack1.isEmpty() && stack2.isEmpty();}private void in2out() {while (!stack1.isEmpty()) {stack2.push(stack1.pop());}}
}

用队列实现栈:

class MyStack {Queue<Integer> queue1;Queue<Integer> queue2;public MyStack() {queue1 = new LinkedList<Integer>();queue2 = new LinkedList<Integer>();}public void push(int x) {queue2.offer(x);while (!queue1.isEmpty()) {queue2.offer(queue1.poll());}Queue<Integer> temp = queue1;queue1 = queue2;queue2 = temp;}public int pop() {return queue1.poll();}public int top() {return queue1.peek();}public boolean empty() {return queue1.isEmpty();}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue学习计划-Vue2--Vue核心(三)methods和computed

Vue 1. 事件 v-on 基础 使用 v-on:xxx或者xxx绑定事件&#xff0c;其中xxx是事件名 事件的回调需要配置在methods对象中&#xff0c;最终会在vm上 methods中配置函数&#xff0c;不要用箭头函数&#xff0c;否则this就不是vm了 methods中配置函数&#xff0c;都是被Vue管…

Seata使用

本文以seata-server-1.5.2&#xff0c;以配置中心、注册中心使用Nacos&#xff0c;store.modedb&#xff08;mysql&#xff09;为例进行操作。 一、Seata Server端 1、下载seata server 链接: http://seata.io/zh-cn/blog/download.html下载压缩包&#xff0c;解压至非中文目录…

Java技术栈 —— 微服务框架Spring Cloud —— Ruoyi-Cloud 学习(一)

Ruoyi-cloud 项目学习 一、项目环境搭建与启动1.1 nacos安装部署1.1.1 nacos安装、启动1.1.2 nacos部署 1.2 seata安装部署1.3 后端部署与运行1.3.1 ruoyi-modules-file模块运行报错 1.4 nginx安装、部署、配置与启动1.5 redis安装与部署1.6 前段框架知识1.7 项目启动1.8 参考 …

实用方法 | 搭建真正满足用户需求的在线帮助中心

随着互联网的普及和信息技术的快速发展&#xff0c;客户服务和支持变得越来越重要。为了提高客户满意度和维持良好的品牌形象&#xff0c;越来越多企业都开始搭建自己的在线帮助中心。 不知从何下手&#xff1f;细想一下&#xff0c;搭建在线帮助中心主要就是为了解决用户的问…

根据java类名找出当前是哪个Excel中的sheet

pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 …

shell_81.Linux在命令行中创建使用函数

在命令行中使用函数 在命令行中创建函数 两种方法 单行方式来定义函数&#xff1a; $ function divem { echo $[ $1 / $2 ]; } $ divem 100 5 20 $ 当你在命令行中定义函数时&#xff0c;必须在每个命令后面加个分号&#xff0c;这样 shell 就能知道哪里是命令的起止了&am…

反射实现tomcat

获取类信息的方法 1.通过类对象 x.getClass() 2.通过class.forname方法 Class.forname(className);这里className是存储类名的字符串 3.通过类名.class 类名.class 通过类名创建对象 类名.newInstance&#xff08;&#xff09;&#xff1b; 反射可以看到类的一切信息&#xff1…

C语言联合和枚举讲解

目录 联合体的大小 联合体如何省空间 巧用联合体 联合判断大小端&#xff08;惊为天人&#xff0c;大佬写的&#xff0c;我借鉴&#xff09; 枚举 枚举类型的使用 首先我们先看一下菜鸟教程中的对C语言联合体的说明 联合体的大小 #include <stdio.h> union u {char…

Proteus仿真--基于ADC0808设计的调温报警器

本文介绍基于ADC0808实现的调温报警器设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 温度调节使用滑动变阻器模拟实现&#xff0c;ADC0808采集信号并输出在LCD上面显示&#xff0c;报警系统是LED灯和蜂鸣器实现声光电报警 仿真图如下 仿真运行视频 Proteus仿真…

Java实现二分法的案例,什么是二分法

文章目录 Java实现二分法的案例&#xff0c;什么是二分法二分法实现 Java实现二分法的案例&#xff0c;什么是二分法 二分法 概念&#xff1a; 二分法&#xff08;Bisection method&#xff09; 即一分为二的方法&#xff0c;又叫折半查找方法。把一组有序数列分为左右两部分…

前程无忧接口分析

前程无忧接口分析 所需用到的工具URL解析通过抓包软件或者开发者选项抓取数据包对代码中的参数解析分析对acw_sc__v2进行分析对acw_sc__v2进行转换代码生成生成outPutList数组生成arg2参数生成arg3参数最终的效果 对详情页面的分析对timestamp__1258的生成分析 所需用到的工具 …

Vue3.0优点详解

相对于Vue2.0 3.0有了比较大的改进&#xff0c;优势主要有以下几点&#xff1a; 一、性能提升 1、Vue3.0的响应式系统使用了Proxy代理对象&#xff0c;取代了Vue2.0中的Object.defineProperty&#xff0c;使得Vue3.0的响应式系统更快、更灵活。 2、Vue3.0对TypeScript的支持更…

Ubuntu22.04安装完成后便可直接使用键盘上的Print键进行截图

概要&#xff1a;Ubuntu22.04安装完成后&#xff0c;无需安装什么截图软件&#xff0c;可以直接使用键盘上的Print键进行截图。 1、按一下Print键 我的电脑上Print键是PrtSc&#xff0c;如下图所示 2、框选区域并截图 如下图中&#xff0c;可以框选(Selection)&#xff0c;也…

【教学类-35-06】17号的学号字帖延伸出的全体字帖(1-9去0)(A4竖版1份)

作品展示 背景需求&#xff1a; 给大4班17号同学单独做了一个学号字帖后&#xff0c;我想可以把这样的学具用在中班&#xff08;我马上要成为中4班老师了&#xff09;&#xff0c;那就需要给全班做一份这样的大号学号贴。 使用17号同学的word模板&#xff08;见下文&#xff…

3dMax vs Cinema4d哪个更好更适合你?

Cinema 4d和3dMax的区别 用于游戏风格、开发和风格可视化的3D建模、动画和渲染软件系统&#xff0c;为用户提供制作和编辑动画、视觉效果和环境的灵活性。4D CINEMA可能是由MAXON构建的强大的3D建模、运动图形、绘画和动画软件系统。Cinema 4D将在每个Windows和MAC操作系统上运…

多目标追踪评价指标

多目标追踪性能评价 基础&#xff1a; GT&#xff1a;Ground Truth&#xff0c;是指真实的标签或者真实的对象&#xff1b; TP&#xff1a;True Positive&#xff0c;被正确预测检测到的样本&#xff1b; TN&#xff1a;True Negative&#xff0c;被预测为负的负样本&#…

啃下这50道笔试题,你就是SQL专家!(附答案,收藏备用)

【关注微信公众号&#xff1a;跟强哥学SQL&#xff0c;回复“笔试”免费领取大厂SQL笔试题。】 有两个名为Department&#xff08;部门&#xff09;和Employees&#xff08;员工&#xff09;的表结构如下&#xff1a; CREATE TABLE Department ( DepId int, DepName va…

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑两阶段鲁棒优化配置的多微网合作博弈》

这个标题涉及到多个概念&#xff0c;让我们逐步解读&#xff1a; 考虑两阶段鲁棒优化配置&#xff1a; 两阶段&#xff1a; 指的是在解决问题或进行优化时&#xff0c;可能存在两个不同的阶段或步骤。这表明问题的解决不是一步完成的&#xff0c;而是需要经过多个步骤或阶段。鲁…

前端学习系列之CSS

目录 CSS 简介 发展史 优势 基本语法 引用方式 内部样式 行内样式 外部样式 选择器 id选择器 class选择器 标签选择器 子代选择器 后代选择器 相邻兄弟选择器 后续兄弟选择器 交集选择器 并集选择器 通配符选择器 伪类选择器 属性选择器 CSS基本属性 优…

virtualenv创建虚拟环境

目录 概念安装创建虚拟环境激活虚拟环境删除虚拟环境退出虚拟环境更改虚拟环境路径概念 virtualenv是一个创建隔离的Python运行环境的工具。它允许用户为每个Python项目创建一个独立的虚拟环境,以避免不同项目之间的依赖冲突。 安装 pip install virtualenv virtualenvwrapper…