java中堆栈的基本操作_玩儿转队列和栈的基本操作及其应用:Java 版

队列的基本操作

队列入队出队实现

队列是种先进先出的数据结构。

队列的基本操作主要是入队和出队。

数据从队尾进入队列,从队首出队列。

861814be57a2f93b5f7b1746d78d99c1.png

下面来写一个简单的队列:

public class MyQueue {

private List data;

private int pointer;

public MyQueue() {

data = new ArrayList<>();

pointer = 0;

}

public boolean isEmpty() {

return pointer >= data.size();

}

/**

* Get the front item from the queue.

*/

public int Front() {

return data.get(pointer);

}

/**

* Insert an element into the queue. Return true if the operation is successful.

*/

public boolean enQueue(int x) {

data.add(x);

return true;

}

/**

* Delete an element from the queue. Return true if the operation is successful.

*/

public boolean deQueue() {

if (isEmpty()) {

return false;

}

pointer++;

return true;

}

}

其中,pointer代表头队首第一个位置的数据。

a5fcedbf71bd63f797077e30936d8fe8.png

当头部有数据出队时,对应的pointer指针会往后移动一位。

f647268fc8a1cd92dced982351e082aa.png

如果有数据入队,会直接加在队尾:

ce30debf0732dc3360569b8658734b25.png

我们会发现,随着队首数据的数据的出队,队首指针之前的空间都会被浪费掉,而且随着使用次数变多,空间浪费会越来越高。

为了重复使用这部分空间,避免浪费,我们可以设计一个队首与队尾相连接的队列,重复利用空间。

循环队列设计

ca7830daa962959bd8ba0fe2f81f1395.png

如上图所示,数据1 ~ 10依次入队,队首head在1处,队尾tail在10处,如果将1出队列,head头指针将移动到2:

53a9035c2a1dfa4a9d0becdb67e3b42b.png

此时,有一个空位,我们还可以继续入队:

a9ac49fe591e0c51b28e81ea52bf8214.png

这样利用空间,刚好可以把队首浪费的空间利用上。

class MyCircularQueue {

private Integer[] data; //队列数据

private Integer size; //队列大小

private Integer head = -1; //头指针

private Integer tail = -1; //尾指针

/**

* 初始化队列

*/

public MyCircularQueue(int k) {

this.data = new Integer[k];

this.size = k;

}

/**

* 入队操作

*/

public boolean enQueue(int value) {

if (isFull()) {

return false;

}

if (head == -1) {

head++;

}

tail++;

data[tail % size] = value;

return true;

}

/**

* 出队操作

*/

public boolean deQueue() {

if (isEmpty()) {

return false;

}

if (head == tail % size) {

head = -1;

tail = -1;

} else {

head++;

}

return true;

}

/**

* 获取队首元素

*/

public int Front() {

if (isEmpty()) {

return -1;

}

return data[head];

}

/**

* 获取队尾元素

*/

public int Rear() {

if (isEmpty()) {

return -1;

}

return data[tail % size];

}

/**

* 判断队列是不是为空

*/

public boolean isEmpty() {

return tail == -1 && head == -1;

}

/**

* 检查队列是不是已经满了

*/

public boolean isFull() {

return (tail % size - head) == size - 1 || (head - tail % size) == 1;

}

}

广度优先搜索(BFS)及其实现

上面我们已经实现过基本的队列已经如果优化队列,下面我们来看一个队列在 BFS(广度优先搜索)算法中的应用。

首先我们来定义结点:

@Getter

@Setter

@EqualsAndHashCode

@NoArgsConstructor

class Node implements Serializable {

private static final long serialVersionUID = 3687337665231315466L;

String value;

Collection previews; //前置结点

Collection tails; //后置结点

public Node(String value, Collection previews, Collection tails) {

this.value = value;

}

public Node(String value) {

this.value = value;

}

}

之后,我们先用队列来实现简单的BFS:

int BFS(Node root, Node target) {

Queue queue = new LinkedBlockingQueue(); // store all nodes which are waiting to be processed

int step = 0; // number of steps neeeded from root to current node

queue.add(root);

while (!queue.isEmpty()) {

step++;

int size = queue.size();

for (int i = 0; i < size; i++) {

Node cur = queue.poll();

if (cur.equals(target)) {

return step;

}

if (cur.tails != null) {

for (Node node : cur.tails) {

queue.add(node);

}

}

}

}

return -1;

}

另外,考虑到图结构中,像上面这样访问,可能会存在访问重复结点的情况,所以,我们记录下访问过的结点,访问过就直接跳过。

下面是改进算法:

/**

* 避免一个节点访问两次,单独检查访问过的结点

*

* @param root

* @param target

* @return

*/

int BFS(Node root, Node target) {

Queue queue = new LinkedBlockingQueue(); // store all nodes which are waiting to be processed

Set userd = new HashSet<>(); // node that be used

int step = 0; // number of steps neeeded from root to current node

queue.add(root);

userd.add(root);

while (!queue.isEmpty()) {

step++;

int size = queue.size();

for (int i = 0; i < size; i++) {

Node cur = queue.poll();

if (cur.equals(target)) {

return step;

}

if (cur.tails != null) {

for (Node node : cur.tails) {

if (!userd.contains(node)) {

queue.add(node);

userd.add(node);

}

}

}

}

}

return -1;

}

Stack

与队列相反,栈是种先入后出的结构。

下面我们来看下Java里面的栈基本入栈和出栈是如何实现的:

首先是入栈操作:

/**

* Pushes an item onto the top of this stack. This has exactly

* the same effect as:

*

* addElement(item)

*

* @param item the item to be pushed onto this stack.

* @return the item argument.

* @see java.util.Vector#addElement

*/

public E push(E item) {

addElement(item);

return item;

}

/**

* Adds the specified component to the end of this vector,

* increasing its size by one. The capacity of this vector is

* increased if its size becomes greater than its capacity.

*

*

This method is identical in functionality to the

* {@link #add(Object) add(E)}

* method (which is part of the {@link List} interface).

*

* @param obj the component to be added

*/

public synchronized void addElement(E obj) {

modCount++;

ensureCapacityHelper(elementCount + 1);

elementData[elementCount++] = obj;

}

入栈 操作即将数据插入数组尾部。ps:入栈之前会去进行容量检查,如果不够,会进行内部数组的扩容操作,会重新产生大容量数组,并将原来老数组拷贝到新数组,完成扩容。过程跟 ArrayList 的类似。

下面来看下出栈:

/**

* Removes the object at the top of this stack and returns that

* object as the value of this function.

*

* @return The object at the top of this stack (the last item

* of the Vector object).

* @throws EmptyStackException if this stack is empty.

*/

public synchronized E pop() {

E obj;

int len = size();

obj = peek();

removeElementAt(len - 1);

return obj;

}

public synchronized void removeElementAt(int index) {

modCount++;

if (index >= elementCount) {

throw new ArrayIndexOutOfBoundsException(index + " >= " +

elementCount);

}

else if (index < 0) {

throw new ArrayIndexOutOfBoundsException(index);

}

int j = elementCount - index - 1;

if (j > 0) {

System.arraycopy(elementData, index + 1, elementData, index, j);

}

elementCount--;

elementData[elementCount] = null; /* to let gc do its work */

}

这里,直接将数组尾部的数移除。

深度优先搜索(DFS)

首先来看DFS的简单递归实现:

/*

* 基于递归实现 DFS

*/

boolean DFS(Node cur, Node target, Set visited) {

if (cur == target) {

return true;

}

if (cur.tails == null || cur.tails.size() < 1) {

return false;

}

for (Node n : cur.tails) {

visited.add(n);

if (DFS(n, target, visited)) {

return true;

}

}

return false;

}

基于递归的实现,系统会自动帮我们生成堆栈调用,但是如果递归的深度过高的话,终将造成堆栈溢出。这时候,我们就需要自己用Stack实现这一过程:

/**

* 基于 stack

*

* @param cur

* @param target

* @return

*/

boolean DFS(Node cur, Node target) {

Set visited = new HashSet<>();

Stack stack = new Stack();

stack.push(cur);

while (!stack.isEmpty()) {

Node temp = stack.pop();

if (temp == target) {

return true;

}

for (Node n : temp.tails) {

if (!visited.contains(n)) {

visited.add(n);

stack.push(n);

}

}

}

return false;

}

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

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

相关文章

java界面编辑教程_java程序设计基础教程第六章图形用户界面编辑.docx

java程序设计基础教程第六章图形用户界面编辑.docx还剩27页未读&#xff0c;继续阅读下载文档到电脑&#xff0c;马上远离加班熬夜&#xff01;亲&#xff0c;很抱歉&#xff0c;此页已超出免费预览范围啦&#xff01;如果喜欢就下载吧&#xff0c;价低环保&#xff01;内容要点…

c盘java文件误删_java获取C盘下的隐藏目录文件名称

题记—— 执剑天涯&#xff0c;从你的点滴积累开始&#xff0c;所及之处&#xff0c;必精益求精&#xff0c;即是折腾每一天。网易云课堂在Java中&#xff0c; File类用来将文件或者文件夹封装成对象&#xff0c;方便对文件与文件夹的属性信息进行操作。File对象可以作为参数传…

对java这门课程的认识_关于java课程的总结

前言本次博客主要内容为此次三次作业的总结&#xff0c;整门java课程学习的总结&#xff0c;以及在此次java课程中的收获&#xff0c;和对课程的意见。作业过程总结第一次作业主要考察的是对程序的可扩展性&#xff0c;实现开闭原则非常重要&#xff0c;因为程序随着时间&#…

linux php和java环境变量配置_Linux下配置Java环境变量

一般来说&#xff0c;我们都会把Java安装到 /usr/local 目录 或者 /opt 目录下。这里假设java安装包已解压在了 /opt下&#xff0c;具体目录为&#xff1a;/opt/java8/java1.8.0_45目录(注意&#xff1a;如果是生产环境中&#xff0c;一定要root用户来安装配置)。下面我们来配置…

java多线程多态_Java学习之多线程

多线程&#xff1a;(一)进程与线程进程特点并发与并行的区别&#xff1a;多线程编程的好处&#xff1a;(二)多线程的建立1&#xff0c;通过继承Thread类&#xff0c;代码如下&#xff1a;class MyThread extendsThread {private static int K 10;//类共享变量private int M10;…

php seaslog安装,浅谈win10下安装php seaslog扩展的方法

本篇文章给大家分享一下win10 php安装seaslog扩展的方法。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助。【推荐学习&#xff1a;《PHP视频教程》】一、检查系统环境情况使用phpinfo()检查系统环境情况&#xff0c;找到需要下载的配置…

php里push的用法,php array_push函数怎么用?

php array_push函数用于向数组尾部插入一个或多个元素&#xff0c;其语法是array_push(array,value1,value2...)&#xff0c;参数array必需&#xff0c;指规定一个数组&#xff1b;value1必需&#xff0c;指规定要添加的值。php array_push函数怎么用&#xff1f;定义和用法arr…

java if (name!=null name!=),java中的NullPointerException异常

java中的NullPointerException异常关注:176 答案:3 mip版解决时间 2021-01-27 20:59提问者侢遇噹姩揂2021-01-27 02:10Login.jsp提供登录表单。到LoginCheck.jsp发生空指针异常错误。LoginCheck.jsp:String userName request.getParameter("userName");String pas…

caany边缘检测matlab,自适应canny算法研究及其在图像边缘检测中的应用.pdf

自适应canny算法研究及其在图像边缘检测中的应用.pdf还剩51页未读&#xff0c;继续阅读下载文档到电脑&#xff0c;马上远离加班熬夜&#xff01;亲&#xff0c;很抱歉&#xff0c;此页已超出免费预览范围啦&#xff01;如果喜欢就下载吧&#xff0c;价低环保&#xff01;内容要…

flask mysql orm,flask的orm框架(Flask-SQLAlchemy)-创建表

标签&#xff1a;# 转载请留言联系ORM 是什么&#xff1f;ORM&#xff0c;Object-Relation Mapping。意思就是对象-关系映射。ORM 主要实现模型对象到关系数据库数据的映射。优点 :只需要面向对象编程, 不需要面向数据库编写代码.对数据库的操作都转化成对类属性和方法的操作.不…

php+使用go编译,golang如何编译

Go语言中使用 go build 命令主要用于编译代码。在包的编译过程中&#xff0c;若有必要&#xff0c;会同时编译与之相关联的包。go build 有很多种编译方法&#xff0c;如无参数编译、文件列表编译、指定包编译等&#xff0c;使用这些方法都可以输出可执行文件。go build 无参数…

oracle19c监听服务启动失败,Oracle19c安装(有失败成功记录)

Oracle19c安装(有失败成功记录)失败过程失败安装设置 (图为安装成功后获取)成功过程安装设置配置监听桌面类与服务器类的区别总结说明&#xff1a;失败过程失败问题一模一样&#xff0c;无论安装成功或者失败都出现“无法添加用户XXXX到%2%组中”的弹窗&#xff0c;都是点6下继…

linux ospf 命令,OSPF单区域配置 - linuxprobe2020的个人空间 - OSCHINA - 中文开源技术交流社区...

为了弥补距离矢量路由协议的不足&#xff0c;IEFI组织开发了一种基于链路状态的内部网关协议OSPF实验环境&#xff1a;红&#xff0c;绿&#xff0c;蓝三个颜色区域代表三个不同网络的办公场所&#xff0c;要求使用OSPF协议实现网络互通。pc1:172.16.1.1pc2:172.16.2.1pc3:172.…

ubuntu下的linux怎样备份文件,Ubuntu系统如何备份还原?Ubuntu系统备份还原教程

Ubuntu系统如何备份还原&#xff1f;Ubuntu系统是一个以桌面应用为主的开源操作系统&#xff0c;专为开发团队而打造&#xff01;无论你使用的是什么操作系统&#xff0c;都有可能出现电脑无法修复的故障&#xff0c;这时候备份还原功能就显得非常重要了。今天小编要给大家分享…

jenkins linux编译c,【Linux】【Jenkins】代码编译和执行过程中的问题汇总

1.问题1&#xff1a;java.io.FileNotFoundException: /root/.jenkins/workspace/Videoyi_AutoTest_Maven/config-log4j\log4j.xml (No such file or directory)该问题是由于代码是在windows下编写和编译的&#xff0c;使用的都是\\来实现目录结构的&#xff0c;结果到linux下的…

linux清理整个磁盘空间,一次Linux磁盘空间清理的经历

最近&#xff0c;在Linux上运行BPM应用总是报没有空间的错误。经过一番调查和周折&#xff0c;终于找出了问题的症结&#xff0c;并顺利解决。今天&#xff0c;我把过程总结一下&#xff0c;方便自己或其他有类似问题的朋友参考。这里不对具体命令的具体各种参数做深入介绍&…

c语言手游常用代码,c语言源代码【操作流程】

很多小伙伴都遇到过c语言源代码的困惑吧&#xff0c;一些朋友看过网上零散的c语言源代码的处理方法&#xff0c;并没有完完全全明白c语言源代码是如何解决的&#xff0c;今天小编准备了简单的解决办法&#xff0c;只需要按照1&#xff1a;编写C源代码for_learning_compile.c2&a…

pdxp协议 C语言,集成CC控制逻辑,PD协议及MCU的Type-C应用方案

Type-C系列亮点介绍内包MCU、集成CC逻辑和DP协议支持Typec DP Alt mode 和单独的DP输入支持速率最高可达4-lane 5.4Gbps(HBR2)支持macbook2016版本,拔掉adapter不掉电● DP1.2/Type C转HDMI1.4&#xff0c;支持HDCP1.3&#xff0c;可扩展PD,USB3.0接口● 支持1/2/4 lane DP输…

Android打开谷歌应用,谷歌确认 Android 12 新增剪贴板访问提醒,将在 Beta 2 上线

IT之家 5 月 19 日消息 据外媒 xda-developers 报道&#xff0c;近年来&#xff0c;谷歌一直在打击 Android 系统中的剪贴板访问&#xff0c;并在发布 Android 10 时禁止后台应用读取剪贴板数据。在最新的 Android 12 中&#xff0c;谷歌引入了一项设置&#xff0c;每当应用访问…

Android nfc编译,【Android编译】各个模块编译方法

一、如何编译出vendor.img1. 首先找到产品对应BoardConfig.mk路径&#xff1a;LINUX/android/device/项目/产品/BoardConfig.mk2. 修改BoardConfig.mk设置下面代码中的ENABLE_VENDOR_IMAGE为true。#Enable split vendor imageENABLE_VENDOR_IMAGE : true#ENABLE_VENDOR_IMAGE :…