数据结构——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)官网 - 全球极客挚爱的技术成长平台(队列实现栈)

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

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

相关文章

Zookeeper集群

一、Zookeeper概述 1.1 Zookeeper 定义 Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 1.2 Zookeeper 工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理…

华夏基金“冰火两重天”:产品增量不增值,靠什么赢得用户?

近日&#xff0c;华夏基金发布关于华夏野村日经225交易型开放式指数证券投资基金&#xff08;QDII&#xff09;&#xff08;下称“华夏野村日经ETF”&#xff09;二级市场交易价格溢价风险提示及临时停牌公告。 公告内容显示&#xff0c;华夏野村日经ETF二级市场交易价格明显高…

备战2个月,面试被问麻了....

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

为什么静态IP是您批量创建社交媒体和账户管理必备?

“新设备登录请求被拒绝&#xff0c;请使用常用设备登录。”谁没有遇到过远程管理社交或商业账户时登录被拒的情况呢? 更糟糕的情况可能是遇到这样的提示&#xff1a;“您的账号可能被盗用&#xff0c;暂时限制使用。请按要求进行身份验证。” 最坏的结果则可能是因为各种原…

工业RFID读卡器的功能和作用

工业读卡器主要用于识别和读写特定目标的数据&#xff0c;它的种类有很多&#xff0c;有分体的读写器也有一体的读写器&#xff0c;根据不同场景的应用可以选择不同的读写器。 工业RFID读卡器的功能和作用 工业RFID读卡器在工业自动化和物流管理等领域中发挥着重要作用。其主要…

什么是DDoS攻击?

什么是DDoS攻击&#xff1f; 拒绝服务&#xff08;Denial-of-Service&#xff0c;DoS&#xff09;攻击是一种针对某些服务可用性的攻击。 通过耗尽CPU、内存、带宽以及磁盘空间等系统资源&#xff0c;来阻止或削弱对网络、系统或应用程序的授权使用的行为。 如果攻击者采用单一…

动态权限有哪些

定位权限&#xff1a; ACCESS_FINE_LOCATION&#xff1a;精确位置ACCESS_COARSE_LOCATION&#xff1a;大致位置 相机权限&#xff1a; CAMERA&#xff1a;访问摄像头 存储权限&#xff1a; READ_EXTERNAL_STORAGE&#xff1a;读取外部存储WRITE_EXTERNAL_STORAGE&#xff1a;…

springboot集成easypoi

easypoi,主打的功能就是容易,通过简单的配置&#xff0c;就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出 pom导入依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star…

SpringCloud Aliba-Seata【上】-从入门到学废【7】

目录 &#x1f9c2;.Seata是什么 &#x1f32d;2.Seata术语表 &#x1f953;3.处理过程 &#x1f9c8;4.下载 &#x1f37f;5.修改相关配置 &#x1f95e;6.启动seata 1.Seata是什么 Seata是一款开源的分布式事务解决方案&#xff0c;致力于在微服务架构下提供高性能…

【C++修行之道】STL(初识pair、vector)

目录 一、pair 1.1pair的定义和结构 1.2pair的嵌套 1.3pair自带排序规则 1.4代码示例 二、vector 2.1vector的定义和特性 2.2vector的初始化 一维初始化&#xff1a; 2.3vector的常用函数 2.4vector排序去重 排序: 去重&#xff1a; 示例&#xff1a; 一、pair …

宠物空气净化器推荐哪个好?实惠的猫用猫用净化器牌子测评

作为宠物主人&#xff0c;我们深知养宠物的乐趣和责任&#xff0c;但同时也面临着一些挑战&#xff0c;比如宠物掉毛、异味和空气质量等问题。这就是为什么越来越多的家庭选择宠物空气净化器&#xff0c;为我们创造一个清新、健康的室内环境。 无论我们多么爱我们的毛茸茸伙伴…

STM32(--001) Win10、Win11 上的驱动安装说明

一、USB线插到 CMSIS-DAP 接口上&#xff0c;将自动识别到两个设备 ① CMSIS-DAP&#xff1a;用于烧录代码、在线硬件仿真; 在Keil里烧录&#xff0c;无需通过FlyMCU; ② USB转TTL&#xff1a;用于开发板与电脑间串口通信 &#xff0c;即USART1, TX-PA9、RX-PA10; 接口备注&a…

UDP和TCP代理协议有什么区别?哪个更好

在互联网的世界里&#xff0c;数据传输的方式有很多种&#xff0c;其中 UDP 和 TCP 是两种常见的传输协议。而代理协议则是为了在网络中传输数据时提供安全、稳定和高效的传输环境。那么&#xff0c;UDP 和 TCP 代理协议有什么区别呢&#xff1f;哪个更好呢&#xff1f;接下来&…

web系统服务器监控检查

一、检查操作系统是否存在增减文件&#xff0c;是否有shell被上传 要检查操作系统是否存在增减文件或是否有shell被上传&#xff0c;您可以按照以下步骤进行操作&#xff1a; 文件完整性检查&#xff1a; 使用文件系统的完整性检查工具&#xff0c;例如fsck&#xff08;对于ext…

Linux之快速入门

一、Linux目录结构 从Windows转到Linux最不习惯的是什么&#xff1a; 目录结构 Windows会分盘&#xff0c;想怎么放东西就怎么放东西&#xff0c;好处自由&#xff0c;缺点容易乱 Linux有自己的目录结构&#xff0c;不能随随便便放东西 /&#xff1a;根目录/bin:二进制文件&…

Mapbox加载浙江省天地图服务和数据处理

1. 加载影像服务 通过浙江省天地图官网申请所需服务&#xff0c;使用token获取服务数据 由于浙江省天地图使用的坐标系是 cgcs2000&#xff0c;需要使用 的框架对应为 cgcs2000/mapbox-gl&#xff0c;通过cdn引入或npm下载 影像服务地址为&#xff1a; ‘https://ditu.zjzw…

力扣hot100 环形链表 快慢指针 哈希 数学公式

Problem: 142. 环形链表 II 文章目录 思路Code 思路 &#x1f468;‍&#x1f3eb; 参考题解 Code ⏰ 时间复杂度: O ( n ) O(n) O(n) &#x1f30e; 空间复杂度: O ( 1 ) O(1) O(1) /** /*** Definition for singly-linked list.* class ListNode {* int val;* …

Vector源码

Vector源码 总结 Vector底层采用数组对元素进行存储&#xff0c;与ArrayList不同的是使用synchronized保障了线程安全&#xff0c;并且扩容机制为原容量的1.5倍&#xff0c;而数组的初始化时机是调用构造方法后&#xff0c;ArrayList是调用add方法后,由于读和写都加了锁&…

Pytorch自动求导机制

PyTorch框架可以帮我们计算好反向传播&#xff0c;需要求导的&#xff0c;可以手动定义 示例&#xff1a; #先构造一个随机的三行四列矩阵&#xff0c;两种方法都可以#方法1 x torch.randn(3,4,requires_gradTrue) x#方法2 x torch.randn(3,4) x.requires_gradTrue x #再构…