首页 > 编程语言 >「Java数据结构」- 栈和队列

「Java数据结构」- 栈和队列

时间:2022-11-30 16:01:36浏览次数:37  
标签:Java 队列 top 元素 节点 int 数据结构 public

栈的认识

========

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。

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

????????

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

? ? ? ? ?

栈是一种先进后出的数据结构

栈的功能

========

由于栈是一种特殊的数据结构,一次出栈的元素只能出最后入栈的元素,所以不能通过下标进行随机查询,也不能通过下标进行随机取元素操作,以下是栈涉及到的操作

public boolean empty() // 返回栈是否为空。

public int peek() // 返回栈顶部的对象,而不从栈中删除它。

public int pop() // 删除栈顶部的对象,并将该对象作为此函数的值返回。

public void push() // 入栈操作

接下来,就使用 Java 实现以上的方法,在实现功能前,先创建一个数组用来储存数据,再创建一个变量 top 记录当前栈顶的元素.

class MyStack{

private int[] elem;//数组存放元素

private int top;// 栈顶指针

public MyStack() {

this.elem = new int[10];// 初始容量为10

this.top = 0;

}

}

实现

======

入栈


从图中,可以知道,每次入栈操作,都在 top 指针处插入数据,且 top 指针自增一次,所以可以写成在数组的top位置进行插入数据.

public void push(int item) {

// 可以分为两步操作

/*

this.elem[top] = item;

this.top++;

*/

// 也可以一步到位

this.elem[top++] = item;

}

取栈顶元素


这个操作,是不会把栈中的元素进行删除,所以根据图片可以看到,要想得到栈顶的元素,top 指针要往下走一步,且不能改变 top 的位置,否则下次插入会改变当前栈首元素的值,所以可以直接取 top - 1 位置处的元素,既不改变 top,也能拿到栈顶元素,不过在 top 为 0 的情况下,也就是栈为空的情况下,我们需要进行处理,否则会产生数组越界异常.

??public int peek() {

if (this.top == 0) {

throw new UnsupportedOperationException("栈中元素为空!");// 手动抛一个异常 提示

}

return this.elem[this.top - 1]; // 返回top - 1 的元素,不改变 top 本身

}

出栈


出栈操作,使用的是覆盖方法,将当前 top 指针往下一位,等下次 添加元素的时候就能覆盖当前要删除的元素,即使没有要添加的元素,由于 top 指针变了,当前其它操作也访问不到删除的元素,所以移动 top 指针既可达到我们逻辑上的删除.

public int pop() {

if (this.top == 0) {

throw new UnsupportedOperationException("栈顶元素为空");

}

return this.elem[--this.top];// 将 top 指针下移一位,切返回当前的要删除的元素

}

栈是否为空


判断当前 top 是否等于 0 即可

public boolean empty() {

return this.top == 0;

}

栈的使用

====

实现完方法之后,接下来简单了解一下栈的使用方法

public static void main(String[] args) {

MyStack myStack = new MyStack();

Stack<Integer> stack = new Stack<>();

myStack.push(1);

myStack.push(2);

myStack.push(3);

myStack.push(4);

myStack.push(5);

while (!myStack.empty()){

System.out.print(myStack.pop() + " ");

}

}

由于添加的顺序是 1 -> 2 -> 3 -> 4 -> 5 , 根据后进先出的特性,输出 应该为 5 -> 4 -> 3 -> 2 -> 1

ze_20,color_FFFFFF,t_70,g_se,x_16)

以上就是关于如何使用 JAVA 实现 栈 的所有内容,接下来我们去学习一下 另外一种数据结构 <队列>


队列的认识

=========

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表

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

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

?

队列是一个具有先进先出特性的数据结构

队列的功能

=========

队列这种特殊的数据结构的特性,在现实生活中很多也很常见,拿火车站买票来说,先到售票窗口前的人能先买到票,后到购票窗口的人只能排队等先到的人买完才能买,队列也是,只有先入队列的元素出队列之后,后面入队列的元素才能出队列,不允许随机访问元素

public boolean isEmpty() // 判断队列是否为空

public void offer(E e) // 入队列,则将指定的元素插入到此队列中。

public int peek() // 返回队头元素

public int poll() // 出队列,删除队头元素,并返回改值

上面就是队列的常用方法,在实现功能前,我们先考虑是用数组来实现队列,还是用链表来实现比较好?我们可以比较一下两种结构的时间复杂度

  1. 入队列:入队列的时候使用的是尾插法
1.  数组:用数组实现尾插法 , 使用一个指针记录尾部 , 进行插入时直接通过尾部指针进行插入 , 不需要格外的遍历 , 时间复杂度为 O(1).
2.  链表:用链表实现尾插法 , 使用一个尾节点记录尾部 , 进行插入时直接通过尾节点进行插入,不需要格外的遍历 , 时间复杂度为 O(1)
  1. 出队列:出队列的时候使用的是头删法
1.  数组:用数组实现头删法 , 需要将后面的数据覆盖前面的数据 , 时间复杂度是O(N)
2.  链表:用链表实现头删法,只需要使用一个头节点记录对头位置 , 删除时 将头节点指向当前对头的下一个节点即可

由此得出,在实现队列使用的存储方式时,使用链表的时间复杂度更低,那就先创建一个节点类,用来存储数据及下一个节点的地址

public class MyQueue {

// 可以使用内部类,定义在实现类里面

private static class Node {

public int val;

public Node next;

public Node(int val) {

this.val = val;

}

}

private Node head;// 记录头节点

private Node tail; // 记录尾节点

}

实现

======

入队列


入队列分为两种情况

  1. 第一次入队列,队列是为空的,需要先将头节点和尾节点都指向当前的节点

  1. 非第一次队列,需要将 tail 的 next 指针指向 当前插入的节点,且 tail 节点 也要更新成当前节点

public void offer(int val) {

// 创建新节点

Node node = new Node(val);

//尾插法 需要判断是不是第一次插入

if (isEmpty()) {

this.head = node;

this.tail = node;

return;

}

this.tail.next = node;

this.tail = node;

}

出队列


出队列也分两种情况

  1. 队列为空:如果队列为空,调用出队列的方法时,我们应该抛出一个异常提示

  2. 队列不为空:队列不为空,采用头删法,将 head 节点 更新成 head.next 的节点,此时就能达到删除队头元素的效果了.

public int poll() {

//判断是否为空队列的

if (isEmpty()) {

throw new UnsupportedOperationException("队列为空");

}

// 记录要删除对头的元素

int ret = this.head.val;

// 更改 head 指向

this.head = this.head.next;

return ret;

}

取对头元素


我们在前面使用了 head 引用,记录了 队头,所以只需要放回 head 引用的值即可,需要判断队列是否为空,为空的话需要抛出异常提示

public int peek() {

//不要移动first

if (isEmpty()) {

throw new UnsupportedOperationException("链表为空");

}

return this.head.val;

标签:Java,队列,top,元素,节点,int,数据结构,public
From: https://blog.51cto.com/u_15767198/5899853

相关文章

  • Java-根据父级id将List结构转Tree结构
    1.方法一:List的stream()方法publicResultDataqueryMenuList(){//获取所有数据ListList<MenuVo>list=MenuDao.queryMenuList();//通过list.s......
  • C++数据结构和算法:排序算法
    为了便于测试,先写一个生成随机数组的方法。1pair<int*,int>GenerateRandomArray(intmaxSize,intmaxValue,intminValue)2{3//随机数组长度4cons......
  • java项目中使用oshi搭建监控系统
    官网地址:​​https://github.com/oshi/oshi​​首先引入jar包<dependency><groupId>com.github.oshi</groupId><artifactId>oshi-core</artifact......
  • JAVA规定时间循环定时执行某个任务
    在我们做web项目的时候有些需求需要我们定时每周每天执行什么任务,这里给大家介绍一种方式,我就直接贴代码web.xml<listener><listener-class>com.hw.util.BeginRun......
  • [JavaScript] 自顶向下学习如何手写promise
    引子去年写了一篇有关promise的手写文章,写到一半发现自己的理解还不是很透彻,写的很烂,今年卷土重来,实现部分采用功能分解,目录跳转的形式呈现,力求最通俗易懂得剖析promise,我......
  • Java生成帮助文档
    在要生成帮助文档的目录下打开cmd   输入javadoc-encodingUTF-8-charrsetUTF-8要生成的Java文件  在生成的文件中打开index.html......
  • Java基础
    注释平时我们编写代码,在代码量很少时,我们还可以看懂自己写的,但当项目结构一旦复杂起来,我们就需要用到注释了注释并不会被执行,是给我们写代码的人看的书写注释是......
  • Java基础----内部类
    内部类分为1.成员内部类2.静态内部类3.局部内部类4.匿名内部类内部类概念:在一个类的内部再定义一个类特点:编译之后可以独立生成独立的字节码文件内部类可以......
  • java并发编程(二十二)-并发安全的基本概念
    类的线程安全定义  如果多线程下使用这个类,不过多线程如何使用和调度这个类,这个类总是表示出正确的行为,这个类就是线程安全的。类的线程安全表现为:操作的原子性内存的可见......
  • java并发编程(二十三)-并发安全之死锁
    死锁资源一定是多于1个,同时小于等于竞争的线程数,资源只有一个,只会产生激烈的竞争。死锁的根本成因:获取锁的顺序不一致导致。 死锁的一般情况:packagecom.caojiulu;importc......