[java数据结构] 栈(Stack)和队列(Queue)

news2024/11/26 4:47:10

目录

(一) 栈(Stack)

1. 栈的概念

2. 栈的常见的方法

3. 栈的使用

4. 栈的模拟实现

(二) 队列(Queue)

1. 队列的概念

2. 队列常见的方法

3. 队列的使用

5. 队列的模拟实现

6. 循环队列

总结


(一) 栈(Stack)

1. 栈的概念

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

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

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

假设S = ( a 1 , a 2 , . . . . a n ) S=(a1, a2,....an)S=(a1,a2,....an),则称a 1 a1a1为栈底元素,a n anan为栈顶元素。栈中元素按a 1 , a 2 , . . . a n a1,a2,...ana1,a2,...an的次序进栈,那么出栈的第一个元素应为栈顶元素。

如图:

栈在现实生活中的例子:

也是遵循后进先出,先进看不出原则

2. 栈的常见的方法
  • Stack(): 构造一个空的栈
  • E push(E e): 将e入栈,并返回e
  • E pop(): 将栈顶元素出栈并返回
  • E peek(): 获取栈顶元素
  • int size(): 获取栈中有效元素个数
  • boolean empty(): 检测栈是否为空
3. 栈的使用
import java.util.Stack;

class Main {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(5); //插入5个元素, 1 2 3 4 5 栈顶是5, 栈底是1
        System.out.println(stack.size()); // 获取栈中有效元素个数---> 5
        System.out.println(stack.peek()); // 获取栈顶元素---> 5
        System.out.println(stack.pop()); // 5出栈,栈中剩余1  2  3  4,栈顶元素为4
        System.out.println(stack.pop()); // 4出栈,栈中剩余1  2  3 栈顶元素为3
       
        //为空则返回true 否则false
        if(stack.empty()){   
            System.out.println("栈空");
        }else{
            System.out.println(stack.size()); //出了两个元素还有1 2 3----->3个
        }
    }
}
4. 栈的模拟实现

从上图中可以看到,Stack继承了Vector,Vector和ArrayList类似,都是动态的顺序表,不同的是Vector是线程安全的。

package Stack;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Stack;

public class myStack {
    public int[] arr; // 用于存储栈元素的数组
    public int usedSize; // 记录栈中已使用的元素个数
    public static final int MAX = 10; // 栈的最大容量

    // 构造函数,初始化数组
    public myStack(){
        arr = new int[MAX];
    }

    // 获取栈中已使用的元素个数
    public int size(){
       return usedSize;
    }

    // 判断栈是否已满,若满则扩容
    private void isFull(){
        if (usedSize == MAX) {
            arr = Arrays.copyOf(arr, arr.length * 2); // 扩容为原来的两倍
        }
    }

    // 打印栈中元素
    public void display(){
        for (int i = 0; i < usedSize; i++) {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

    // 入栈操作
    public void push(int data){
        // 判断是否栈满,若满则扩容
        isFull();
        arr[usedSize++] = data; // 将元素入栈
    }

    // 判断栈是否为空
    private boolean isEmpty(){
        if (usedSize == 0){
            return true;
        }
        return false;
    }

    // 出栈操作,获取并删除栈顶元素
    public int pop(){
        // 判断是否栈空 如果空了就没必要出栈了
        if (isEmpty()){
            throw new EmptyStackException("栈为空了!");
        }
        int ret = arr[usedSize-1]; // 获取栈顶元素
        usedSize--; // 栈中元素个数减一
        return ret; // 返回被删除的栈顶元素
    }

    // 获取栈顶元素 如果空了就不用返回栈顶元素了
    public int peek(){
        if (isEmpty()){
            throw new RuntimeException("栈为空了");
        }
        return arr[usedSize-1]; // 返回栈顶元素
    }


    // 获取栈中已使用的元素个数
    public int getUsedSize() {
        return usedSize;
    }
}

(二) 队列(Queue)

1. 队列的概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(FirstIn First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)

生活中体现出队列也挺常见的, 比如排队, 先来的先排在前面, 后来的排在后面 

2. 队列常见的方法
  • boolean offer(E e): 入队列
  • E poll(): 出队列
  • peek(): 获取头元素
  • int size: 获取队列中有效元素个数
  • boolean isEmpty(): 检测队列是否为空
3. 队列的使用

在Java中,Queue是个接口,底层是通过链表实现的。

import java.util.LinkedList;
import java.util.Queue;
class Main {
    public static void main(String[] args) {
        Queue<Integer> q = new LinkedList<>();
        q.offer(1);
        q.offer(2);
        q.offer(3);
        q.offer(4);  // 从队尾入队列 队头是1 队尾是4

        // 获取队列有效元素个数 -> 4
        System.out.println(q.size());

        // 获取队头元素 -> 1
        System.out.println(q.peek());

        // 从队头出队列,并将删除的元素返回 -> 1
        System.out.println(q.poll());
            
        //为空则返回true 否则false
        if (q.isEmpty()) {
            System.out.println("队列空");
        } else {
            System.out.println(q.size()); //前面执行了一次删除操作, 还剩下3个元素        
        }
    }

注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。

5. 队列的模拟实现

package Queue;

public class myQueue {

    static class ListNode{
        public int val;
        public ListNode next;

        public ListNode(int val){
            this.val = val;
        }
    }
    public int usedSize; // 已使用的队列元素个数
    public ListNode head; // 队列头部节点
    public ListNode tail; // 队列尾部节点

    // 入队操作
    public void offer(int data){
        ListNode node  = new ListNode(data); // 创建新节点
        if (head == null){ // 如果队列为空
            tail = node;
            head = node;
        }else {
            tail.next = node; // 将新节点连接到队列尾部
            tail = tail.next; // 更新尾部节点
        }
    }

    // 出队操作
    public int poll(){
        if (head == null){ // 如果队列为空
            return -1; // 返回-1表示出队失败
        }
        ListNode cur = head; // 记录当前头部节点
        head = head.next; // 头部指针后移
        return cur.val; // 返回出队的元素值
    }

    // 获取队首元素
    public int peek(){
        if (head == null){ // 如果队列为空
            return  -1; // 返回-1表示队列为空
        }
        return head.val; // 返回队首元素的值
    }

    // 打印队列中元素
    public void display(){
        ListNode cur = head;
        while (cur != null){ // 遍历队列
            System.out.print(cur.val+" "); // 打印节点值
            cur = cur.next; // 指针后移
        }
        System.out.println();
    }

    // 获取队列中元素个数
    public int size(){
        ListNode cur = head;
        int len = 0;
        while (cur != null){ // 遍历队列
            cur = cur.next; // 指针后移
            len++; // 元素个数加一
        }
        return len; // 返回队列中元素个数
    }
}

当我们使用队列这种基本的数据结构时,很容易发现,随着入队和出队操作的不断进行,队列的数据区域不断地偏向队尾方向移动。当我们的队尾指针指向了队列之外的区域时,我们就不能再进行入队操作了,而此时由于队头已经偏离原来位置,也就意味着实际上队列并没有满。这种实际上还有空间,但是却发生了溢出的现象就称为假溢出现象

6. 循环队列

什么是假溢出现象

假设有以下队列,初始元素为1、2、3、4、队头元素是1,队尾元素就4

当我们弹出队头元素两次得到队列:

这就是假溢出, 可以看出还有多余的空间, 但是当队尾入一个元素发现满了

如何解决这个问题?

为了避免假溢出问题,我们需要对队列进行优化---循环队列,  形如如图

循环队列的性质

数组实现

  • 空队列:front == rear
  • 满队列:牺牲一个单元判满(不牺牲的话队空队满无法区分)

     (rear+1)% len == front

  • 进队:rear = (rear+1)% maxSize
  • 出队:front = (front+1)% maxSize
  • 队中元素个数/长度:(rear - front + len) % len

循环队列题

622. 设计循环队列​编辑https://leetcode.cn/problems/design-circular-queue/

循环队列代码实现:

package Queue;

import java.util.Arrays;

public class CircleQueue {

    public int[] arr; // 数组存储队列元素
    public int usedSize; // 已使用的队列元素个数
    public int font; // 队列头部指针
    public int rear; // 队列尾部指针
    public static final int MAX = 5; // 队列最大容量

    public CircleQueue(){
        arr = new int[MAX]; // 初始化数组
    }

    // 打印队列中元素
    public void display(){
        for (int i = font; i < arr.length-1; i++) {
            System.out.print(arr[i]+" "); // 打印队列元素
        }
        System.out.println();
    }

    // 判断队列是否已满
    private boolean isFull(){
        if ((rear + 1) % MAX == font){ // 判断队列是否已满
          return true;
        }
        return false;
    }

    // 入队操作
    public boolean offer(int data){
      if(isFull()){ // 如果队列已满
          return false; // 返回入队失败
      }
      arr[rear] = data; // 将元素放入队列尾部
      rear = (rear + 1) % arr.length; // 更新队列尾部指针
      usedSize++; // 更新队列元素个数
      return true; // 返回入队成功
    }

    // 判断队列是否为空
    private boolean isEmpty(){
        if (font == rear){ // 判断队列是否为空
            return true;
        }
        return false;
    }

    // 出队操作
    public boolean poll(){
        if (isEmpty()){ // 如果队列为空
            return false; // 返回出队失败
        }
        font = (font+1) % arr.length; // 头部指针后移
        usedSize--; // 更新队列元素个数
        return true; // 返回出队成功
    }

    // 获取队头元素
    public int Front(){
        if(isEmpty()){ // 如果队列为空
            return -1; // 返回-1表示队列为空
        }
        int ret = arr[font]; // 获取队头元素
        return ret; // 返回队头元素的值
    }

    // 获取队尾元素
    public int Rear(){
        if (isEmpty()){ // 如果队列为空
            return -1; // 返回-1表示队列为空
        }
        int ret = (rear == 0) ? arr.length-1 : rear - 1; // 计算队尾元素的下标
        return arr[ret]; // 返回队尾元素的值
    }
    
    // 获取队列元素个数
    public int size() {
    return usedSize; // 返回队列元素个数
    }

}

总结

栈(Stack)和队列(Queue)是两种常见的数据结构,它们在数据存储和访问的方式上有一些重要的区别。

栈(Stack)是一种后进先出(LIFO,Last In First Out)的数据结构,类似于一摞盘子,最后放入的盘子最先取出。栈的操作包括入栈(push)和出栈(pop),只能在栈顶进行操作,不支持随机访问。栈常用于实现函数调用、表达式求值、括号匹配等场景。

队列(Queue)是一种先进先出(FIFO,First In First Out)的数据结构,类似于排队等候的过程,先到先得。队列的操作包括入队(offer)和出队(poll),元素从队列的前端出队,从队列的后端入队。队列常用于实现广度优先搜索、任务调度等场景。

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

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

相关文章

webserver 之 线程同步 线程池(半同步半反应堆)

目录 &#x1f402;前言 &#x1f351;B / S 模型 &#x1f418;线程同步机制 &#x1f33c;概念 &#xff08;1&#xff09;RAII &#xff08;2&#xff09;信号量 &#xff08;3&#xff09;互斥量 &#xff08;4&#xff09;条件变量 &#x1f33c;功能 &#xf…

git merge和git rebase区别

具体详情 具体常见如下&#xff0c;假设有master和change分支&#xff0c;从同一个节点分裂&#xff0c;随后各自进行了两次提交commit以及修改。随后即为change想合并到master分支中&#xff0c;但是直接git commit和git push是不成功的&#xff0c;因为分支冲突了【master以…

JAVA输入任意一个数字,实现递减求和(计算任意整数n的和)

摘要&#xff1a;本文介绍了使用Java编程语言计算任意整数n及其之前所有整数的和的示例代码。代码使用了Scanner类来读取用户输入的整数值&#xff0c;并通过循环计算出和结果并生成计算公式字符串。 内容&#xff1a; 在这个示例中&#xff0c;我们将展示如何使用Java编程语言…

白酒:酿造过程中的微生物作用与控制

云仓酒庄豪迈白酒的酿造是一个复杂的过程&#xff0c;其中微生物的作用与控制是关键环节。在这个过程中&#xff0c;微生物不仅是发酵的驱动者&#xff0c;也是形成云仓酒庄豪迈白酒与众不同风味的重要因素。 在制曲环节&#xff0c;传统的人工踩曲方式被采用。这种方式通过调节…

宠物互联网医院系统:数字化呵护你爱宠的新时代

宠物互联网医院系统正在为宠物主人提供一种前所未有的数字化健康护理体验。通过结合创新技术&#xff0c;这一系统旨在让宠物医疗变得更加便捷、智能和个性化。让我们深入探讨宠物互联网医院系统的技术核心&#xff0c;以及如何应用代码为你的爱宠提供最佳关怀。 1. 远程医疗…

web开发学习笔记(14.mybatis基于xml配置)

1.基本介绍 2.基本使用 在mapper中定义 在xml中定义&#xff0c;id为方法名&#xff0c;resultType为实体类的路径 在测试类中写 3. 动态sql&#xff0c;if和where关键字 动态sql添加<where>关键字可以自动产生where和过滤and或者or关键字 where关键字可以动态生成whe…

【产品设计】详细的B端筛选设计

在实际的工作中&#xff0c;可能会遇到各种筛选类型&#xff0c;不同的筛选类型对应的排版布局各不相同&#xff0c;实际业务中的使用场景也具有差异。 对于产品而言&#xff0c;只有参与的项目越多&#xff0c;设计和思考的场景越全面&#xff0c;了解的产品越多&#xff0c;才…

mac绘画软件有哪些?Mac绘画软件大揭秘

mac绘画软件有哪些&#xff1f;在Mac平台上&#xff0c;有许多优秀的绘画软件可供选择。这些软件不仅功能强大&#xff0c;而且界面设计简洁&#xff0c;使得创作过程更加顺畅。今天&#xff0c;我们将为你介绍一些知名的Mac绘画软件&#xff0c;让你深入了解这个充满创意的世界…

【网络安全】-基本工具msf

secure 1、有此漏洞的目标主机2、无此漏洞的目标主机&#xff08;常用&#xff09; ps.本着兴趣爱好&#xff0c;加强电脑的安全防护能力&#xff0c;并严格遵守法律和道德规范。msf&#xff08;metasploit framework&#xff09;是一个开源的渗透测试框架&#xff0c;用于开发…

python丰富的任务进度显示

pip install txdpy 安装 txdpy from txdpy import progbar 导入 progbar progbar()函数传入一个可遍历对象&#xff0c;返可迭代对象 from txdpy import progbar from random import uniform from time import sleepfor i in progbar(range(4651)):print(f第{i}条任务)…

在ESP32 Arduino框架上实验FreeRTOS:多任务操作系统的简介与应用

FreeRTOS 介绍 实时操作系统&#xff08;RTOS&#xff09;&#xff1a; 实时操作系统是一种专为实时应用程序设计的操作系统。实时应用程序对任务的响应时间有严格的要求&#xff0c;因此实时操作系统必须能够在预定的时间内完成任务的调度和执行。这与通用操作系统&#xff…

Unity 桥接模式(实例详解)

文章目录 示例1&#xff1a;角色与装备系统示例2&#xff1a;UI控件库示例3&#xff1a;渲染引擎模块示例4&#xff1a;AI决策树算法示例5&#xff1a;物理模拟引擎 在Unity游戏开发中&#xff0c;桥接模式&#xff08;Bridge Pattern&#xff09;是一种设计模式&#xff0c;它…

语义分割常用评价指标

在图像处理领域中&#xff0c;语义分割是很重要的一个任务。在实际项目开发中,评估模型预测效果以及各指标的含义对于优化模型极为重要。 本文将主要评价指标的计算算法进行了详细说明,并加上注释解释每个指标的含义。这对理解各指标背后的数学原理以及能否在实践中应用或许有…

【MATLAB基础绘图第20棒】云雨图

MATLAB绘制云雨图 云雨图(Raincloud plots)MATLAB绘制云雨图横向云雨图竖向云雨图 参考 云雨图(Raincloud plots) 云雨图&#xff08;Raincloud plots&#xff09;其实是可以看成核密度估计曲线图、箱形图和抖动散点图的组合图&#xff0c;清晰、完整、美观地展示了所有数据信…

数组与 Web 程序打包

5. 数组 在Java中&#xff0c;数组是一种用于存储相同类型元素的数据结构。以下是如何定义和赋值Java数组的基本方法&#xff1a; 1. 定义数组&#xff1a; 一维数组&#xff1a; // 语法&#xff1a;elementType[] arrayName; int[] intArray; // 声明一个整型数组&#…

操作系统【OS】Ch2【大题】 PV题型分类

生产者-消费者问题&#xff1a;生产资源-消费资源理发师问题&#xff1a;服务-被服务读者-写者问题&#xff1a;同类进程不互斥、异类进程互斥哲学家进餐问题&#xff1a;只有一类进程&#xff0c;每个进程需要同时拥有多种资源才能运行单纯的同步问题&#xff1a;前驱后继图 生…

​第14节-高质量简历写作求职通关-在线测试

在线测试主要包括性格测试、综合能力测试、技能测试三类 性格测试 性格测试主要用于考察个人与工岗位的匹配程度 考察内容包含性格、能力、动机、价值观等&#xff0c;考察形式一般为给出相应的工作场景&#xff0c;让你选择最喜欢或者最不喜欢的答案 技能考试 这类测试一般是针…

xxe漏洞之scms靶场漏洞

xxe-scms 代码审核 &#xff08;1&#xff09;全局搜索simplexml_load_string simplexml_load_string--将XML字符串解释为对象 &#xff08;2&#xff09;查看源代码 ID1 $GLOBALS[HTTP_RAW_POST_DATA]就相当于file_get_contents("php://input"); 因此这里就存…

AI搜索引擎Perplexity来了,谷歌等老牌搜索引擎或许会有新的威胁?

Perplexity AI 是一家 AI 搜索初创公司&#xff0c;它通过结合内容索引技术和大型语言模型的推理能力&#xff0c;提供更便捷和高效的搜索体验。另外&#xff0c;最近很火的小兔子Rabbit R1硬件AI设备中的搜索功能正是这家公司的杰作。在短短一年半的时间里&#xff0c;一个企业…

快速了解工业交换机

工业交换机是专门为工业环境设计的数据通信设备。该设备的主要作用是满足工业控制系统对数据通信的要求&#xff0c;实现不同设备之间的数据传输和网络连接。工业交换机在适应恶劣环境、抗干扰和稳定性等方面表现更出色&#xff0c;相较于传统的商用交换机。 它的基本原理是利用…