关于栈和队列

news2024/11/8 15:24:18

目录

  • 栈(Stack)
    • 什么是栈
    • 栈的使用
    • 栈的模拟实现
  • 队列(Queue)
    • 什么是队列
    • 队列的使用
    • 队列的模拟实现
    • 循环队列
    • 双端队列 (Deque)

栈(Stack)

什么是栈

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

压栈:栈的插入操作叫做进栈/压栈/入栈,入数据是在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
在这里插入图片描述
出栈时,是C先出,然后是B,再是A .

注意:这个栈是一种数据结构,与JVM内存模型中的栈不同,JVM中的栈是指JVM中一段内存区域。

栈的使用

在这里插入图片描述

public static void main(String[] args) {
	Stack<Integer> s = new Stack();  //尖括号里是我要存放的数据类型
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);
	System.out.println(s.size()); // 获取栈中有效元素个数---> 4
	System.out.println(s.peek()); // 获取栈顶元素---> 4
	s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
	System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为2
	if(s.empty()){
		System.out.println("栈空");
	}else{
		System.out.println(s.size());
	}
}

在这里插入图片描述

栈的模拟实现

在这里插入图片描述
可以看到,Stack继承了Vector,Vector是动态顺序表,与ArrayList类似,不同的是 Vector 是线程安全的。

import java.util.Arrays;

public class MyStack {
    int array[];     //数组用于存放数据
    int size = 0;    //size用于记录当前元素个数

    public MyStack() {  
        this(12);     //默认开辟大小为12的空间
    }
    public MyStack(int m) {
        array = new int[m];
    }
    //入栈
    public int push(int value) {
        if(size == array.length) {
            //扩容
            int[] copy;
            //复制array,并将其扩容一倍
            copy = Arrays.copyOf(array,2* array.length);
            array = copy;  //将array指向扩容后的数组
        }
        array[size] = value;
        size++;
        return value;
    }
    //出栈
    public int pop() {
        if(size == 0) {
            throw new RuntimeException("栈中没有元素");
        }
        int n = array[size-1];
        size--;
        return n;
    }
    //获取栈顶元素
    public int peek() {
        if(size == 0) {
            throw new RuntimeException("栈中没有元素");
        }
        return array[size-1];
    }
    //获取元素个数
    public int getSize() {
        return size;
    }
    //判断栈是否为空
    public boolean isEmpty() {
        return size == 0;
    }
}

队列(Queue)

什么是队列

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出特性。
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头

在这里插入图片描述

队列的使用

在这里插入图片描述
在Java中,Queue是个接口,底层是通过链表LinkedList实现的,LinkedList实现了Queue接口,我们可以通过LinkedList实例化对象,如:

	Queue<Integer> queue = new LinkedList<>();

队列里的方法:

在这里插入图片描述

public static void main(String[] args) {
	Queue<Integer> queue = new LinkedList<>();
	queue.offer(1);
	queue.offer(2);
	queue.offer(3);
	queue.offer(4);
	queue.offer(5); // 从队尾入队列
	System.out.println(queue.size());  //获取元素个数
	System.out.println(queue.peek()); // 获取队头元素
	queue.poll();
	System.out.println(queue.poll()); // 从队头出队列,并将删除的元素返回
	if(queue.isEmpty()){
		System.out.println("队列空");
	}else{
		System.out.println(queue.size());
	}
}

输出:
在这里插入图片描述

队列的模拟实现

实现一个队列,我们可以用数组存储数据,也可以用链表存储数据,那究竟用哪种存储方式更好呢?

我们认为链表存储更好,因为链表的存储空间不连续,可以更好的利用存储空间(可以利用零碎的空间),而数组它的空间是连续的,万一空间不足就会出问题(不能利用零碎空间)。

public class MyQueue {
    //双向链表节点
    public static class ListNode {
        ListNode next;  //记录下一个节点
        ListNode prev;  //记录上一个节点
        int val;      //记录该节点存储的值
        ListNode(int val){
            this.val = val;
        }
    }
    ListNode head; // 队头
    ListNode last; // 队尾
    int size = 0;

    //入队列
    public void offer(int val) {
        ListNode node = new ListNode(val);  //先实例化这个节点出来
        if(last == null) {   //链表中未存放元素时
            last = node;
            head = last;
        }else {
            last.next = node;
            node.prev = last;
            last = node;
        }
        size++;   //链表元素个数加一
    }

    //出队列
    public int poll() {
        if(isEmpty()) {  //判断队列是否为空
            throw new RuntimeException("队列为空,无法出元素");
        }
        int m = head.val;
        head = head.next;
        head.prev = null;
        size--;
        return m;
    }

    //判断队列是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    //获取对头元素
    public int peek() {
        if(isEmpty()) {  //判断队列是否为空
            throw new RuntimeException("队列为空,无法获取元素");
        }
        return head.val;
    }

    //获取元素个数
    public int getSize() {
        return size;
    }
}

循环队列

我们有时还会使用一种队列叫循环队列。环形队列通常使用数组实现。
队头添加元素,队尾删除元素,每块空间都能反复利用,有效节省空间。

front 指向队列的第一个元素,即array[front]为队列的第一个元素,初始值为0;

rear 指向最后一个元素的后一个元素,初始值为0;
在这里插入图片描述
从上图可以看出队列为空的条件:front == rear
当队列存放一个元素时,rear向前走一步,如下图:
在这里插入图片描述

那队列啥时候满了呢?当情况为下图时吗?
在这里插入图片描述
如果这就是满的话,但如何判断呢?是 front == rear 吗?
显然,这与判断队列为空相矛盾,我们不应该这样判断,那应如何判断呢?
我们有两种方法:

  1. 通过添加 size 属性记录(用size记录元素个数)
  2. 牺牲一个位置来表示满

我们就以牺牲一个位置为例吧,如果我们牺牲一个位置来表示满,当情况为下图时:
在这里插入图片描述
此情况就表示满,条件即是:(rear + 1) % array.length == front

class MyCircularQueue {
    int front = 0;
    int rear = 0;
    int[] array;
    public MyCircularQueue(int k) {  //设计一个可以存放k个数据的数组
        array = new int[k+1];     //为什么要设计k+1个大小呢?
    }                           //因为在队尾后面需要牺牲一个空间,方便判满
    
    //向循环队列插入一个元素。如果成功插入则返回真。
    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        array[rear] = value;
        rear = (rear + 1) % array.length;
        return true;
    }
    
    //从循环队列中删除一个元素。如果成功删除则返回真。
    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        front = (front + 1) % array.length;
        return true;
    }
    
    //从队首获取元素。如果队列为空,返回 -1 。
    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return array[front];
    }
    
    //获取队尾元素。如果队列为空,返回 -1 。
    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        return array[(rear+array.length-1)%array.length];
    }
    
    //检查循环队列是否为空。
    public boolean isEmpty() {
        if(rear == front) {
            return true;
        }
        return false;
    }
    
    //检查循环队列是否已满。
    public boolean isFull() {
        if((rear+1) % array.length == front) {
            return true;
        }
        return false;
    }
}

双端队列 (Deque)

双端队列:指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。

Deque是一个接口,使用时必须创建LinkedList或ArrayDeque的对象。

在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口

	Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
	Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现

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

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

相关文章

JavaScriptArray和String对象~

初识Array&#xff1a; 定义&#xff1a; 方式1 var 变量名new Array(元素列表);举例&#xff1a; <script>var arraynew Array(1,2,3);alert(array); </script>显示如下&#xff1a; 方式2 var 变量名[元素列表];举例&#xff1a; <script>var array[…

App Inspector使用 (macaca移动端元素检查器)

App Inspector安装说明&#xff1a;https://macacajs.github.io/app-inspector/zh/guide/install.html#%E7%8E%AF%E5%A2%83%E9%9C%80%E8%A6%81 依赖安装说明&#xff1a; 1、node环境&#xff1a;这里安装的时候和初始化的时候报错使用了两个版本&#xff0c;所以这里使用nvm…

Python-模块、包和发布模块

1.模块1.1模块的概念模块是python程序架构的一个核心概念每一个以扩展名.py结尾的python源代码文件都是一个模块模块名同样也是一个标识符&#xff0c;需要符合标识符的命名规则在模块中定义的全局变量、函数、类都是提供给外界直接使用的工具模块就好比工具包&#xff0c;要想…

世界坐标系->相机坐标系详细推导

基变换 理论部分 在n维的线性空间中&#xff0c;任意n个线性无关的向量都可以作为线性空间的基&#xff0c;即空间基不唯一。对于不同的基&#xff0c;同一个向量的坐标一般是不同的。因为在计算机图形学中&#xff0c;主要研究三维的空间&#xff0c;所以可以简化问题倒三维…

Hi3861鸿蒙物联网项目实战:智能测距仪

华清远见FS-Hi3861开发套件&#xff0c;支持HarmonyOS 3.0系统。开发板主控Hi3861芯片内置WiFi功能&#xff0c;开发板板载资源丰富&#xff0c;包括传感器、执行器、NFC、显示屏等&#xff0c;同时还配套丰富的拓展模块。开发板配套丰富的学习资料&#xff0c;包括全套开发教程…

真假流量卡区别,一篇文章教你怎么区分流量卡和物联卡!

真假流量卡区别&#xff0c;小编教你怎么区分流量卡和物联卡&#xff0c;近年来&#xff0c;市面上的流量卡种类繁多&#xff0c;其中不乏有一些虚假的、有套路的套餐&#xff0c;那么&#xff0c;我们如何辨别流量卡的正规性呢&#xff0c;接下来&#xff0c;跟着小编一块来了…

114.简单的动态切换app的图标,两种方式

第一种方式&#xff1a; 1.第一步 通过activity-alias别名实现&#xff0c;manifest 这里写的是一个默认的图标Default和一个需要切换的图标Test&#xff0c;以及一个默认的首页面HomeActivity&#xff1a; <!-- 默认的图标--> <activity-aliasandroid:name".ac…

基于java SSM springboot+redis网上水果超市商城设计和实现以及文档

基于java SSM springbootredis网上水果超市商城设计和实现以及文档 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留…

java8中stream流式编程的使用大全

一、概述 Stream流操作是Java 8提供一个重要新特性&#xff0c;它允许开发人员以声明性方式处理集合&#xff0c;其核心类库主要改进了对集合类的API和新增Stream操作。Stream类中每一个方法都对应集合上的一种操作。将真正的函数式编程引入到Java中&#xff0c;能 让代码更加简…

Node.js教程笔记(四)数据库与身份认证

学习目标 1、能够知道如何配置Mysql数据库环境 2、能够认识并使用常见的SQL语句操作数据库 3、能够在Express中操作Mysql数据库 4、能够了解Session的实现原理 5、能够了解JWT的实现原理 目录 1、数据库的基本概念 2、安装并配置Mysql 3、Mysql的基本使用 4、在Expre…

全球数十万客户选择亚马逊云科技数据库服务构建自己的应用

日前&#xff0c;全球市场分析机构Gartner发布《2022云数据库管理系统魔力象限》报告&#xff08;2022 Gartner Magic Quadrant™ for Cloud Database Management Systems&#xff09;。Gartner数据显示&#xff0c;整个数据库管理系统市场在2021年实现强劲增长22.3%&#xff0…

【五六七人口普查】我国省市两级各行业门类人口及三次产业人口比重

人口数据是我们在各项研究中最常使用的数据&#xff01;之前我们分享过第七次人口普查&#xff08;简称七普&#xff09;的数据&#xff01;很多小伙伴拿到数据后都反馈数据非常好用&#xff0c;同时很多小伙伴咨询有没有前面几次人口普查的数据&#xff0c;这样方便做人口变化…

【Java】final关键字和final的四种用法

final定义 final翻译成中文的意思是 “最终” &#xff0c; 它是java当中的一个关键字&#xff0c;使用final修饰的对象不允许修改或替换其原始值或定义。 假如当final修饰一个类的时候&#xff0c;是不能被其他类继承的。 final的四种用法 修饰类修饰方法修饰变量修饰参数 1.…

会话保持技术:cookie、session

目录 1.概述 2.cookie 3.session 1.概述 会话保持技术的出现是因为HTTP 是一个无状态的协议&#xff0c;这一次请求和上一次请求是没有任何关系的&#xff0c;互相无法感知&#xff0c;上一次请求干了什么&#xff1f;这一次请求完全不知道&#xff0c;会话保持技术就是为了…

Python协程asyncio异步编程结合uvloop性能提升

asyncio介绍 和我们以前常用的gevent模块相似&#xff0c;asyncio模块也是在Python中实现协程的模块区别是gevent是第三方库&#xff0c;通过greenlet实现协程&#xff0c;遇到I/O自动切换&#xff08;自动挡&#xff09;asyncio是Python 3.4版本引入的标准库&#xff0c;asyc…

GitHub访问问题与FastGithub下载及使用(详细篇)

前言 &#x1f4dc; “ 作者 久绊A ” 专注记录自己所整理的Java、web、sql等&#xff0c;IT技术干货、学习经验、面试资料、刷题记录&#xff0c;以及遇到的问题和解决方案&#xff0c;记录自己成长的点滴 目录 前言 FastGithub的介绍 FastGithub的下载 FastGithub的安装及…

23种设计模式之综合实战篇

23种设计模式之综合实战篇1. 设计模式概述1.1 什么是设计模式1.2 设计模式的好处2. 设计原则分类3. 详解3.1 单一职责原则3.2 开闭原则3.3 里氏代换原则3.4 依赖倒转原则3.5 接口隔离原则3.6 合成复用原则3.7 迪米特法则4. Awakening1. 设计模式概述 我们的软件开发技术也包括一…

微刊:做了很多的16S三代测序,文章可以这样写~

三代的黄金时代已经来临&#xff01;在扩增子方面与二代相比其优势明显&#xff1a;1&#xff1a;获得的序列更长&#xff0c;信息量更多更准确&#xff01;2;鉴定高精准&#xff0c;“种”水平物种鉴定中实现了大幅提升。3:PCR扩增无GC偏好性&#xff0c;数据更准确。4:V1-V9全…

MySQL多表操作的外键约束

目录 一.多表关系 一对一关系 一对多/多对一关系 多对多关系 二.外键约束 特点 创建外键约束 方式1-在创建表时设置外键约束 方式2-在创建表时设置外键约束 在外键约束下的操作 1.数据插入 2.删除数据 3.删除外键约束 外键约束-多对多关系 操作 一.多表关系 MySQL多表…

51单片机学习笔记-12LCD1602液晶屏

12 LCD1602液晶屏 [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 12.1 LCD1602介绍 LCD1602&#xff08;Liquid Crystal Display&#xff09;…