【Java实现】栈和队列就是这么简单
一、前言
上一篇已经讲过了链表【Java实现单向链表】了,它跟数组都是线性结构的基础,本文主要讲解线性结构的应用:栈和队列
如果写错的地方希望大家能够多多体谅并指正哦,如果有更好的理解的方式也希望能够在评论下留言,让大家学习学习~
二、数据结构【栈】就是这么简单
2.1数据结构【栈】介绍
数据结构的栈长的是这个样子:
其实非常好理解,我们将栈可以看成一个箱子
- 往箱子里面放东西叫做入栈
- 往箱子里面取东西叫做出栈
- 箱子的底部叫做栈底
- 箱子的顶部叫做栈顶
说到栈的特性,肯定会有一句经典的言语来概括:先进后出(LIFO, Last In First Out)
- 往箱子里边放苹果,箱子底部的苹果想要拿出来,得先把箱子顶部的苹果取走才行
2.2数据结构【栈】 代码实现
栈的分类有两种:
- 静态栈(数组实现)
- 动态栈(链表实现)
从上一篇写链表我就认知到我的算法是有多渣了,普通的单链表操作也能把我绕得晕晕的。
由于我的链表还不是很熟,栈又不是很难,那么我就用链表来创建动态栈了!
既然是用链表,我们还是把上一篇节点的代码拿过来吧:
public class Node {
//数据域
public int data;
//指针域,指向下一个节点
public Node next;
public Node() {
}
public Node(int data) {
this.data = data;
}
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
}
要链表用来表示栈,这次会有两个指针:
- 栈顶
- 栈底
public class Stack {
public Node stackTop;
public Node stackBottom;
public Stack(Node stackTop, Node stackBottom) {
this.stackTop = stackTop;
this.stackBottom = stackBottom;
}
public Stack() {
}
}
2.2.1进栈
将原本栈顶指向的节点交由新节点来指向,栈顶指向新加入的节点
/**
* 进栈
*
* @param stack 栈
* @param value 要进栈的元素
*/
public static void pushStack(Stack stack, int value) {
// 封装数据成节点
Node newNode = new Node(value);
// 栈顶本来指向的节点交由新节点来指向
newNode.next = stack.stackTop;
// 栈顶指针指向新节点
stack.stackTop = newNode;
}
2.2.2遍历栈
只要栈顶元素的指针不指向栈底,那么就一直输出遍历结果:
/**
* 遍历栈(只要栈顶指针不指向栈底指针,就一直输出)
*
* @param stack
*/
public static void traverse(Stack stack) {
Node stackTop = stack.stackTop;
while (stackTop != stack.stackBottom) {
System.out.println("关注公众号:Java3y:" + stackTop.data);
stackTop = stackTop.next;
}
}
测试:
public static void main(String[] args) {
//初始化栈(无元素)
Stack stack = new Stack(new Node(), new Node());
//栈顶和栈尾是同一指向
stack.stackBottom = stack.stackTop;
//指向null
stack.stackTop.next = null;
//进栈
pushStack(stack, 3);
pushStack(stack, 4);
pushStack(stack, 5);
traverse(stack);
}
结果:
这就符合了先进后出的特性了~
2.2.3判断该栈是否为空
很简单,只要栈顶和栈底是同一指向,那么该栈就为空
/**
* 判断该栈是否为空
*
* @param stack
*/
public static void isEmpty(Stack stack) {
if (stack.stackTop == stack.stackBottom) {
System.out.println("关注公众号:Java3y---->该栈为空");
} else {
System.out.println("关注公众号:Java3y---->该栈不为空");
}
}
2.2.4出栈
- 在出栈之前看看该栈是否为空,不为空才出栈...
- 将栈顶的元素的指针(指向下一个节点)赋值给栈顶指针(完成出栈)
/**
* 出栈(将栈顶的指针指向下一个节点)
* @param stack
*/
public static void popStack(Stack stack) {
// 栈不为空才能出栈
if (!isEmpty(stack)) {
//栈顶元素
Node top = stack.stackTop;
// 栈顶指针指向下一个节点
stack.stackTop = top.next;
System.out.println("关注公众号:Java3y---->出栈的元素是:" + top.data);
}
}
测试出栈:
多次出栈:
2.2.5清空栈
当时学C的时候需要释放内存资源,可是Java不用呀,所以栈顶指向栈底,就清空栈了
/**
* 清空栈
* @param stack
*/
public static void clearStack(Stack stack) {
stack.stackTop = null;
stack.stackBottom = stack.stackTop;
}
三、数据结构【队列】就是这么简单
数据结构的队列长的是这个样子:
其实队列非常好理解,我们将队列可以看成小朋友排队
- 队尾的小朋友到指定的地点了-->出队
- 有新的小朋友加入了-->入队
相对于栈而言,队列的特性是:先进先出
- 先排队的小朋友肯定能先打到饭!
队列也分成两种:
- 静态队列(数组实现)
- 动态队列(链表实现)
这次我就使用数组来实现静态队列了。值得注意的是:往往实现静态队列,我们都是做成循环队列
做成循环队列的好处是不浪费内存资源!
3.1数据结构【队列】 代码实现
这次我们使用的是数组来实现静态队列,因此我们可以这样设计:
public class Queue {
//数组
public int [] arrays;
//指向第一个有效的元素
public int front;
//指向有效数据的下一个元素(即指向无效的数据)
public int rear;
}
从上面的设计我们可以发现:rear并不指向最后一个有效的元素,在循环队列中这样设计是非常方便的!因为这样设计可以让我们分得清队头和队尾(不然循环队列不断入队或出队,位置是变化很快的)
由于我们是循环队列,所以front
和rear
值会经常变动,我们得把front
和rear
的值限定在一个范围内,不然会超出队列的长度的。
有这么一个算法:rear=(rear+1)%数组长度
- 比如rear的下标是2,数组的长度是6,往后面移一位是3,那么
rear = (rear+1) % 6
,结果还是3
3.1.2初始化队列
此时队列为空,分配了6个长度给数组(只能装5个实际的数字,rear指向的是无效的位置的)
public static void main(String[] args) {
//初始化队列
Queue queue = new Queue();
queue.front = 0;
queue.rear = 0;
queue.arrays = new int[6];
}
3.1.3判断队列是否满了
如果rear指针和front指针紧挨着,那么说明队列就满了
/**
* 判断队列是否满了,front和rear指针紧挨着,就是满了
* @param queue
* @return
*/
public static boolean isFull(Queue queue) {
if ((queue.rear + 1) % queue.arrays.length == queue.front) {
System.out.println("关注公众号:Java3y--->此时队列满了!");
return true;
} else {
System.out.println("关注公众号:Java3y--->此时队列没满了!");
return false;
}
}
3.1.4入队
- 判断该队列是否满了
- 入队的值插入到队尾中(具体的位置就是rear指针的位置【再次声明:rear指向的是无效元素的位置】
- rear指针移动(再次指向无效的元素位置)
/**
* 入队
*
* @param queue
*/
public static void enQueue(Queue queue,int value) {
// 不是满的队列才能入队
if (!isFull(queue)) {
// 将新的元素插入到队尾中
queue.arrays[queue.rear] = value;
// rear节点移动到新的无效元素位置上
queue.rear = (queue.rear + 1) % queue.arrays.length;
}
}
3.1.5遍历
只要front节点不指向rear节点,那么就可以一直输出
/**
* 遍历队列
* @param queue
*
*/
public static void traverseQueue(Queue queue) {
// front的位置
int i = queue.front;
while (i != queue.rear) {
System.out.println("关注公众号:Java3y--->" + queue.arrays[i]);
//移动front
i = (i + 1) % queue.arrays.length;
}
}
队列没满时:
队列已满了就插入不了了(验证上面的方法是否正确):
3.1.6判断该队列是否为空
只要rear
和front
指针指向同一个位置,那该队列就是空的了
/**
* 判断队列是否空,front和rear指针相等,就是空了
* @param queue
* @return
*/
public static boolean isEmpty(Queue queue) {
if (queue.rear == queue.front) {
System.out.println("关注公众号:Java3y--->此时队列空的!");
return true;
} else {
System.out.println("关注公众号:Java3y--->此时队列非空!");
return false;
}
}
3.1.7出队
出队的逻辑也非常简单:
- 判断该队列是否为null
- 如果不为null,则出队,只要front指针往后面移就是出队了!
/**
* 出队
*
* @param queue
*/
public static void outQueue(Queue queue) {
//判断该队列是否为null
if (!isEmpty(queue)) {
//不为空才出队
int value = queue.arrays[queue.front];
System.out.println("关注公众号:Java3y--->出队的元素是:" + value);
// front指针往后面移
queue.front = (queue.front + 1) % queue.arrays.length;
}
}
结果:
四、总结
数据结构的栈和队列的应用非常非常的多,这里也只是最简单的入门,理解起来也不困难。
- 栈:先进后出
- 队列:先进先出
关于数据结构这方面我就到暂时到这里为止了,都简单的入个门,以后遇到更加复杂的再继续开新的文章来写~毕竟现在水平不够,也无法理解更深层次的东西~数据结构这东西是必备的,等到研究集合的时候还会来回顾它,或者遇到新的、复杂的也会继续学习....
想要更加深入数据结构的同学就得去翻阅相关的书籍咯~这仅仅是冰山一角
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y
【Java实现】栈和队列就是这么简单的更多相关文章
- 剑指Offer——Java实现栈和队列的互模拟操作
剑指Offer--Java实现栈和队列的互模拟操作 栈模拟队列 题目:JAVA实现用两个栈来实现一个队列,完成队列的Push和Pop操作.队列中的元素为int类型. 思路:其实就是把队列正常入 ...
- Java的栈和队列
package com.ipmotor.sm.db;import java.util.LinkedList;import java.util.Queue;import java.util.Stack; ...
- Java 用栈实现队列
栈是先入后出,队列是先入先出.根据这个思想,可以用一个栈作为入队,另一个栈作为出队.只要把第一个栈的栈顶的元素压入第二个栈就好了,出队的时候输出第二个栈的栈顶,如果第二个栈的空了就需要不断操作从第一个 ...
- 剑指 Offer 09. 用两个栈实现队列 +java中栈和队列的使用
剑指 Offer 09. 用两个栈实现队列 题目链接 class CQueue { private Stack<Integer> sta1; private Stack<Intege ...
- java实现栈与队列
一.栈 栈是一种特殊的线性表.其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行.(先进后出) 访问权限:栈限制了访问权限,只可以访问尾节点,也就是最后添加的元素 即栈顶的元素 /** * ...
- Java 实现栈,队列
package base.structure; /** * @program: Algorithm4J * @description: 实现一个Stack * @author: Mr.Dai * @c ...
- java实现栈和队列
class Node { int val; Node next; Node(int x) { val = x; next = null; } } class Stack { Node top; pub ...
- 《数据结构与算法分析:C语言描述_原书第二版》CH3表、栈和队列_reading notes
表.栈和队列是最简单和最基本的三种数据结构.基本上,每一个有意义的程序都将明晰地至少使用一种这样的数据结构,比如栈在程序中总是要间接地用到,不管你在程序中是否做了声明. 本章学习重点: 理解抽象数据类 ...
- 线性表 及Java实现 顺序表、链表、栈、队列
数据结构与算法是程序设计的两大基础,大型的IT企业面试时也会出数据结构和算法的题目, 它可以说明你是否有良好的逻辑思维,如果你具备良好的逻辑思维,即使技术存在某些缺陷,面试公司也会认为你很有培养价值, ...
随机推荐
- 一种基于主板BIOS的身份认证方案及实现
.分析AwardBIOSDOS工具cbrom cbrom的功能就是在BIOS文件中添加.删除与提取模块,以便满足用户自己的需求,用法如下: cbromBIOS文件名/参数模块名|RELEASE|EXT ...
- javaWeb事务
JDBC事务: cmd 命令上的事务开启: start transaction; / begin; 回滚 rollback; 提交 commit; JDBC事务控制: 开启事务:co ...
- 异常-----spring明明注入了Service到Action中,为什么运行的时候Service为空,在抽象类中,有子类来继承的
xml的配置文件 <bean id="fftController" class="com.bill99.query.controller.FftController ...
- 动态地添加HTML控件-JavaScript基础
相关: document对象的createElement()方法可以创建一个新的HTML控件(document.createElement("input");) setAttrib ...
- css边框小结
css边框 CSS对界面的分割如上图,他们的含义如下: contend:包含HTML元素中包含的文本,图像或其他媒体. padding:内容和边框之间的空格. 你可以想像这样的内在空间. ...
- angularjs中的下拉框默认选中
1. ng-init 属性: <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...
- C#多线程编程序--聊聊线程
这篇文章主要给您讲解几个基本问题,什么是线程?为什么要用线程?线程万能?这几个问题.我这篇博客是在该系列另外几篇博客之后写的,之所以不往下继续写,而是回到最初的问题,是因为我感觉到我没有很好的讲解开头 ...
- PDB调试python代码常用命令
常用命令 where(w) 找出当前代码运行位置 list(l) 显示当前代码的部分上下文 list n(line number) 显示指定行的上下文 list m, n(line number) 显 ...
- Java最大公约数和最小公倍数的求法(辗转相除法)
这道题计算了三个数的最小公倍数 import java.util.Scanner; public class D { public static int gcd(int a,int b) { int ...
- openflow 和 sdn (软件定义网络) 原理和教程
OpenFlow概述 OpenFlow简介 通俗的讲,OpenFlow是使用类似于API进程配置网络交换机的协议.OpenFlow的思路很简单,网络设备维护一个FlowTable并且只按照FlowTa ...