数据结构——Java实现栈和队列
一、栈 Stack
1.特点
(1)栈是一种线性数据结构
(2)规定只能从栈顶添加元素,从栈顶取出元素
(3)是一种先进后出的数据结构(Last First Out)LIFO
2.具体实现
Java中可以直接调用方法来实现栈
如何自己写代码来实现栈呢?
先定义一个接口,方便后边进行调用
package com.algo.lesson.lesson02.stack;public interface Stack_I<T> {//入栈void push(T ele);//出栈T pop();//查看栈顶元素T peek();//判断是否为空boolean isEmpty();//后去栈中元素int getSize();
}
接下来来实现栈的方法,调用接口,完善方法:
package com.algo.lesson.lesson02.stack;import com.algo.lesson.lesson01.MyArr;//以数组作为栈顶的底层数据结构
public class ArrStack<T> implements Stack_I<T> {private MyArr<T>data;int size;public ArrStack() {this.data=new MyArr<>(100);this.size=0;}@Overridepublic void push(T ele) {//在数组尾部添加元素this.data.add(ele);this.size++;}@Overridepublic T pop() {if(isEmpty()){return null;}this.size--;return this.data.removeBFromLast();}@Overridepublic T peek() {return this.data.getLastValue();}@Overridepublic boolean isEmpty() {return this.size==0;}@Overridepublic int getSize() {return this.size;}
}
以上就是方法的代码,接下来,写个main函数来调用,检查方法是否正确
package com.algo.lesson.lesson02.stack;import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class StackTest<T> {public void test(Stack_I<T>stack, List<T> list){//开始时间long startTime=System.nanoTime();for(int i=0;i<list.size();i++){stack.push(list.get(i));}System.out.println(stack.getSize());while(!stack.isEmpty()){T ele=stack.pop();System.out.println(ele+" ");}//结束时间long endTime=System.nanoTime();System.out.println("总耗时:"+(endTime-startTime)/100000000.0);}public static void main(String[] args) {StackTest<Integer>stackTest=new StackTest<>();Stack_I<Integer>stack=new ArrStack<>();List<Integer>list=new ArrayList<>();Random random=new Random();for(int i=0;i<100;i++){int val= random.nextInt(1000);list.add(val);}stackTest.test(stack,list);}
}
注:其中long startTime=System.nanoTime();方法是获取一个时间(单位毫秒)
在程序运行前和运行后个添加一个,最后将两个时间相减,得到程序运行时间。
3.时间复杂度分析
二、队列
1.特点
(1)队列也是一种线性数据结构
(2)只能从一端添加元素,另一端取出元素
(3)是一种先进先出的数据结构(FIFO——fist in fist out )
2.具体实现
Java中也可以直接调用队列的方法:
自己的实现:
接口:
package com.algo.lesson.lesson02.queue;public interface Queue_I<T> {void offer(T ele);//入队T poll();//出队T peek();//查找队首元素int getSize();boolean isEmpty();}
方法代码:
package com.algo.lesson.lesson02.queue;import com.algo.lesson.lesson01.MyArr;public class ArrQueue<T>implements Queue_I<T> {private MyArr<T>data;/*private int size;//队列中元素的个数
*/public ArrQueue(){this.data=new MyArr<>(50);}@Overridepublic void offer(T ele) {this.data.add(ele);}@Overridepublic T poll() {if(isEmpty()){return null;}return this.data.removeByIndex(0);}@Overridepublic T peek() {if(isEmpty()){return null;}return this.data.getValueByIndex(0);}@Overridepublic int getSize() {return this.data.getSize();}@Overridepublic boolean isEmpty() {return this.data.isEmpty();}
}
3.出现的问题
入队列时间复杂度为O(n),因为在出队时,元素要前移,会出现假溢出的情况。
所以就出现了循环队列来解决这个问题
循环队列:
front记录队首,tail记录队尾,队尾达到容积时,返回到队头,将空位置补上,可以继续存储数据。
package com.algo.lesson.lesson02.queue;import java.util.Random;/*
基于Java中的数组进行二次封装,制作一个可变数组*/
//泛型:就是类型作为参数
public class LoopArr<T> {private T[] data;//保存数据private int size;//数组中实际存放元素的个数private int front;//队首private int tail;//队尾int capacity;//容积//构造函数public LoopArr(int capacity) {if (capacity <= 0) {this.capacity = 11;} else {this.capacity = capacity + 1;}this.size = 0;this.front = this.tail = 0;this.data = (T[]) (new Object[this.capacity]);}//获取数组中实际存放元素的个数public int getSize() {return this.size;}//获取数组的容积public int getCapacity() {return this.capacity;}//判断数组是否为空public boolean isEmpty() {return this.front == this.tail;}//向数组中添加元素(尾部)public void add(T item) {//判断数组是否满if ((this.tail + 1) % this.capacity == this.front) {//扩容resize((this.capacity-1)*2+1);}//从index位置开始元素需要进行后移this.data[this.tail] = item;this.tail = (this.tail + 1) % this.capacity;//更新this.sizethis.size++;}private void resize(int newCapacity) {System.out.println("resize:" + newCapacity);T[] newData = (T[]) (new Object[newCapacity]);//将原数组驾到新数组里for (int i = 0; i < this.size; i++) {newData[i] = this.data[(this.front+i)%this.capacity];}//改变容器this.data = newData;this.capacity = newCapacity;//将this.front置零this.front=0;this.tail=this.size;}//获取指定位置的值public T getValueByIndex() {if(isEmpty()){return null;}return this.data[this.front];}//移除队首元素public T remove() {if (isEmpty()) {return null;}//删除操作的核心/*1.找到删除的位置2.删除位置之后的元素要前移 arr[j-1]=arr[j]*/T delValue = this.data[this.front];this.front = (this.front + 1) % this.capacity;this.size--;//判断是否缩容if (this.size < this.capacity / 4 && this.capacity / 2 > 0) {resize((this.capacity-1) / 2 +1);}return delValue;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("[");for (int i = 0; i < this.size; i++) {sb.append(this.data[i]);if (i != this.size - 1) {sb.append(",");}}sb.append("]");return sb.toString();}
}
package com.algo.lesson.lesson02.queue;public class LoopQueue<T> implements Queue_I<T>{private LoopArr<T>data;//容器public LoopQueue(){this.data=new LoopArr<>(100);}@Overridepublic void offer(T ele) {this.data.add(ele);}@Overridepublic T poll() {return this.data.remove();}@Overridepublic T peek() {return this.data.getValueByIndex();}@Overridepublic int getSize() {return this.data.getSize();}@Overridepublic boolean isEmpty() {return this.data.isEmpty();}
}
4.循环队列的复杂度分析
三、栈和队列的互相实现
既然我们了解了栈和队列,知道了这两种数据结构十分相似,也就可以大胆假设以下,可不可以相互实现,不是用上面所写的以数组为底层,而是相互为底层存储。
1.用栈来实现队列
import java.util.Stack;class MyQueue {private Stack<Integer> A;private Stack<Integer> B;public MyQueue() {A = new Stack<>();B = new Stack<>();}public void push(int x) {while (!B.isEmpty()) {A.push(B.pop());}A.push(x);while (!A.isEmpty()) {B.push(A.pop());}}public int pop() {return B.pop();}public int peek() {return B.peek();}public boolean empty() {return B.isEmpty();}
}
2.用队列实现栈
import java.util.LinkedList;
import java.util.Queue;class MyStack {private Queue<Integer> queue1;private Queue<Integer> queue2;public MyStack() {queue1 = new LinkedList<>();queue2 = new LinkedList<>();}public void push(int x) {queue2.add(x);while (!queue1.isEmpty()) {queue2.add(queue1.remove());}Queue<Integer> temp = queue1;queue1 = queue2;queue2 = temp;}public int pop() {return queue1.remove();}public int top() {return queue1.peek();}public boolean empty() {return queue1.isEmpty();}
}
这就是这两种数据结构相互实现的代码
在LeetCode中也有相对应的题目:
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台(栈实现队列)
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台(队列实现栈)
相关文章:

数据结构——Java实现栈和队列
一、栈 Stack 1.特点 (1)栈是一种线性数据结构 (2)规定只能从栈顶添加元素,从栈顶取出元素 (3)是一种先进后出的数据结构(Last First Out)LIFO 2.具体实现 Java中可…...

【状态压缩】【动态规划】【C++算法】691贴纸拼词
作者推荐 【动态规划】【数学】【C算法】18赛车 本文涉及知识点 状态压缩 动态规划 LeetCode:691 贴纸拼词 我们有 n 种不同的贴纸。每个贴纸上都有一个小写的英文单词。 您想要拼写出给定的字符串 target ,方法是从收集的贴纸中切割单个字母并重新排列它们。如…...
JavaEE之多线程编程:3. 线程的状态(易懂!)
文章目录 一、关于线程的状态二、观察线程的所有状态1. NEW状态2. TERMINATED状态3. RUNNABLE状态4. TIMED_WAITING 一、关于线程的状态 进程最核心的状态,一个是就绪状态,一个是阻塞状态(对于线程同样使用)。 以线程为单位进行调…...
Android13预装APP到data分区
修改步骤与Android11是差不多的,只是有部分代码所在位置不一样。 Android 11内置APP到data/app Android 8(O)预置APP到data/app 默认内置应用到data会出错 1970-01-01 08:03:54.499 1177-1177/system_process I/PackageManager: /data/app/xx changed; collecting…...

Docker registry镜像仓库,私有仓库及harbor管理详解
目录 registry镜像仓库概述 Docker 镜像仓库(Docker Registry): registry 容器: 私有仓库概述 搭建本地私有仓库示例 Harbor概述 harbor架构 详解构成 Harbor由容器构成 Harbor部署示例 环境准备 部署Docker-Compose服…...

用 Rust 过程宏魔法简化 SQL 函数实现
#[function("length(varchar) -> int4")] pub fn char_length(s: &str) -> i32 {s.chars().count() as i32 }这是 RisingWave 中一个 SQL 函数的实现。只需短短几行代码,通过在 Rust 函数上加一行过程宏,我们就把它包装成了一个 SQL…...

OpenSource - 基于 DFA 算法实现的高性能 java 敏感词过滤工具框架
文章目录 sensitive-word创作目的特性变更日志更多资料敏感词控台敏感词标签文件 快速开始准备Maven 引入核心方法判断是否包含敏感词返回第一个敏感词返回所有敏感词默认的替换策略指定替换的内容自定义替换策略 IWordResultHandler 结果处理类使用实例 更多特性样式处理忽略大…...

端杂七杂八系列篇四-Java8篇
后端杂七杂八系列篇四-Java8篇 ① Lombok插件① RequiredArgsConstructor② SneakyThrows③ UtilityClass④ Cleanup ② Lambda 4个常用的内置函数① Function<T, R> - 接受一个输入参数并返回一个结果② Consumer - 接受一个输入参数,并执行某种操作…...
操作系统一些面试
你这个请求队列是属于一写多读对吧,怎么解决冲突的? 可以采用双buffer或者说双缓冲区,一个缓冲区用来写,一个缓冲区用来读,采用交换指针的方法来进行缓存区的交换,这样交换效率是O(1)的,但是交…...

大语言模型
概念 大语言模型(Large Language Model,简称LLM)是一种基于人工智能技术的自然语言处理模型,是指在大量数据上训练的高级人工智能算法,以自上文推理词语概率为核心任务。它通过在海量文本数据上进行训练,学…...

php反序列化之pop链构造(基于重庆橙子科技靶场)
常见魔术方法的触发 __construct() //创建类对象时调用 __destruct() //对象被销毁时触发 __call() //在对象中调用不可访问的方法时触发 __callStatic() //在静态方式中调用不可访问的方法时触发 __get() //调用类中不存在变量时触发(找有连续箭头的…...

k8s---对外服务 ingress
目录 目录 目录 ingress与service ingress的组成 ingress-controller: ingress暴露服务的方式 2.方式二:DaemonSethostnetworknodeSelector DaemonSethostnetworknodeSelector如何实现 3.deploymentNodePort: 虚拟主机的方式实现http代…...

最优解-最长公共子序列
问题描述 最长公共子序列(Longest Common Subsequence,LCS)即求两个序列最长的公共子序列(可以不连续)。比如3 2 1 4 5和1 2 3 4 5两个序列,最长公共子序列为2 4 5 长度为3。解决这个问题必然要使用动态规划。既然要用到动态规划,就要知道状…...

el-tree获取当前选中节点及其所有父节点的id(包含半选中父节点的id)
如下图,我们现在全勾中的有表格管理及其下的子级,而半勾中的有工作台和任务管理及其子级 现在点击保存按钮后,需要将勾中的节点id及该节点对应的父节点,祖先节点的id(包含半选中父节点的id)也都一并传给后端,那这个例子里就应该共传入9个id,我们可以直接将getCheckedK…...

新上线一个IT公司微信小程序
项目介绍 项目背景: 一家IT公司,业务包含以下六大块: 1、IT设备回收 2、IT设备租赁 3、IT设备销售 4、IT设备维修 5、IT外包 6、IT软件开发 通过小程序,提供在线下单,在线制单,在线销售,业务介绍,推广,会员 项目目的: 业务介绍: 包含企业业务介绍 客户需…...

MCAL配置-PWM(EB23.0)
PWM配置项的介绍 一、General 1、PwmDeInitApi 从代码中添加/删除Pwm_17_GtmCcu6_Delnit() API。 TRUE:Pwm_17_GtmCcu6_Delnit() API可供用户使用。 FALSE:Pwm_17_GtmCcu6_Delnit() API对用户不可用。 注意:默认情况下禁用Pwm_17_GtmCcu6_Delnit() …...

v-if和v-for哪个优先级更高?
v-if和v-for哪个优先级更高? 结论: vue2输出的渲染函数是先执行循环,在看条件判断,如果将v-if和v-for写在一个标签内,哪怕只渲染列表中的一小部分,也要重新遍历整个列表,无形造成资源浪费。vu…...
Mapstruct 常用案例(持续更新.).
将A转换为B Mapper(componentModel "spring") public interface DemoConvert {B A2B(A a); }将List转换为List 注意:以下两个都不可缺少,需要先声明单个和集合的同时生命才可 Mapper(componentModel "spring") public interface …...
QT基础篇(10)QT5网络与通信
QT5网络与通信是指在QT5开发环境中使用网络进行数据传输和通信的相关功能和技术。 QT5提供了一套完善的网络模块,包括了TCP、UDP、HTTP等协议的支持,可以方便地在QT应用程序中进行网络通信。通过QT5的网络模块,开发者可以实现客户端和服务器…...
【Leetcode】269.火星词典(Hard)
一、题目 1、题目描述 现有一种使用英语字母的火星语言,这门语言的字母顺序与英语顺序不同。 给你一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。 请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...