当前位置: 首页 > java >正文

Java数据结构——栈(Stack)和队列(Queue)

一、栈(Stack)

1.1 栈的概念

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

进栈:进栈就是栈的插入操作,在栈顶插入一个数据元素

出栈:出栈就是栈的删除操作,在栈顶删除一个数据元素

我们在生活中也能经常看到栈的使用,比如子弹装入弹夹,我们只能在一个口放入或拿出子弹

1.2 栈的使用

1.2.1 栈的构造

class Student{String name;int age;
}public class stack {public static void main(String[] args) {Stack<Integer> stack=new Stack<>();Stack<Student> stack1=new Stack<>();}
}

可以看到Stack里面可以传入参数,可以是系统有的包装类 Integer,String……,也可以是自己的创建的类Student

1.2.2 栈的方法

方法功能
Stack()构造一个空的栈
E push(E e)将e入栈,并返回e
E pop()将栈顶元素出栈并返回
E peek()获取栈顶元素
int size()获取栈中有效元素的个数
boolean empty检测栈是否为空

1.3 栈的模拟实现

public class MyStack {int[] array;int size;public MyStack(){array = new int[3];}public int push(int e){ensureCapacity();array[size++] = e;return e;}public int pop(){int e = peek();size--;return e;}public int peek(){if(empty()){throw new RuntimeException("栈为空,无法获取栈顶元素");}return array[size-1];}public int size(){return size;}public boolean empty(){return 0 == size;}private void ensureCapacity(){if(size == array.length){array = Arrays.copyOf(array, size*2);}}
}

二、队列(Queue)

2.1 队列的概念

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

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

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

2.2 队列的使用

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

2.2.1 队列的构造

class student{String name;int age;
}public class queue {public static void main(String[] args) {Queue<Integer> queue1=new LinkedList<>();Queue<student> queue2=new LinkedList<>();}
}

2.2.2 队列的方法

方法功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空

2.3 队列的模拟实现

队列需要存储元素的空间,我们之前学过两种储存元素的结构,顺序结构和链式结构,我们需要考虑队列的实现使用顺序结构还是链式结构好?

2.3.1 链式实现

public class Queue {// 双向链表节点public static class ListNode{ListNode next;ListNode prev;int value;ListNode(int value){this.value = value;}}ListNode first; // 队头ListNode last; // 队尾int size = 0;// 入队列---向双向链表位置插入新节点public void offer(int e){ListNode newNode = new ListNode(e);if(first == null){first = newNode;}else{last.next = newNode;newNode.prev = last;}last = newNode;size++;} // 出队列---将双向链表第一个节点删除掉public int poll(){
// 1. 队列为空
// 2. 队列中只有一个元素----链表中只有一个节点---直接删除
// 3. 队列中有多个元素---链表中有多个节点----将第一个节点删除int value = 0;if(first == null){return -1;}else if(first == last){last = null;first = null;}else{value = first.value;first = first.next;first.prev.next = null;first.prev = null;} --size;return value;} // 获取队头元素---获取链表中第一个节点的值域public int peek(){if(first == null){return -1;} return first.value;}public int size() {return size;}public boolean isEmpty(){return first == null;}
}

2.3.2 循环队列

我们可以看到当队列是空的时候,头和尾在同一个位置,当队列为满的时候,头和尾也相遇在同一个位置,那么我们该如何区分队空还是队满呢?

我们一般有3种方法来判断队空和队满

1. 通过添加 size 属性记录

我们创建一个变量usedsize,记录当前队列中的元素个数

public class MyCycleQueue2 {public int[] elem;public int usedSize;public int front;public int rear;public MyCycleQueue2(int k) {elem = new int[k];}//入队列public boolean enQueue(int value) {if(isFull()) {return false;}elem[rear] = value;rear = (rear+1)%elem.length;usedSize++;return true;}//出队列public boolean deQueue() {if(isEmpty()) {return false;}front = (front+1)%elem.length;usedSize--;return true;}//获取队头元素public int Front() {if(isEmpty()) {return -1;}return elem[front];}//获取队尾元素public int Rear() {if(isEmpty()) {return -1;}int index = (rear == 0) ? elem.length-1 : rear-1;return elem[index];}public boolean isEmpty() {return usedSize == 0;}public boolean isFull() {return usedSize == elem.length;}
}
2. 保留一个位置

我们在空出一个位置,也就是浪费一个空间。此时当队满的时候,头尾就不会相遇。队空的时候,头尾相遇,队满的时候,头尾差一个位置,这样就可以区分开来了

public class MyCycleQueue {public int[] elem;//public int usedSize;public int front;public int rear;public MyCycleQueue(int k) {elem = new int[k];}//入队列public boolean enQueue(int value) {if(isFull()) {return false;}elem[rear] = value;//rear++; errorrear = (rear+1)%elem.length;//usedSize++;return true;}//出队列public boolean deQueue() {if(isEmpty()) {return false;}//front++;front = (front+1)%elem.length;return true;}//获取队头元素public int Front() {if(isEmpty()) {return -1;}return elem[front];}//获取队尾元素public int Rear() {if(isEmpty()) {return -1;}int index = (rear == 0) ? elem.length-1 : rear-1;return elem[index];}public boolean isEmpty() {return rear == front;}public boolean isFull() {//return usedSize == elem.length;return (rear+1)%elem.length == front;}
3. 使用标记

我们创建一个boolean变量flg,默认false,在添加元素的时候将flg变为true,删除元素的时候将flg变为false,判空的时候条件为头尾相遇并且flg为false,判满的时候条件为头尾相遇并且flg为true

public class MyCycleQueue3 {public int[] elem;public int usedSize;public int front;public int rear;public boolean flg;//默认是falsepublic MyCycleQueue3(int k) {elem = new int[k];}//入队列public boolean enQueue(int value) {if(isFull()) {return false;}elem[rear] = value;rear = (rear+1)%elem.length;flg = true;return true;}//出队列public boolean deQueue() {if(isEmpty()) {return false;}front = (front+1)%elem.length;flg = false;return true;}//获取队头元素public int Front() {if(isEmpty()) {return -1;}return elem[front];}//获取队尾元素public int Rear() {if(isEmpty()) {return -1;}int index = (rear == 0) ? elem.length-1 : rear-1;return elem[index];}public boolean isEmpty() {if(front == rear && !flg) {return true;}return false;}public boolean isFull() {if(front == rear && flg) {return true;}return false;}
}

2.4 双端队列(Deque)

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

同样的,Deque是一个接口,使用的时候必须创建LinkedList的对象

http://www.xdnf.cn/news/20075.html

相关文章:

  • Qt---状态机框架QState
  • 【Sharding-JDBC】​Spring/Spring Boot 集成 Sharding-JDBC,分表策略与 API、YAML 配置实践​
  • 达梦数据库-共享内存池
  • 3.3.3 钢结构工程施工
  • Kubernetes知识点(三)
  • 探究Linux系统的SSL/TLS证书机制
  • 河南萌新联赛2025第(七)场:郑州轻工业大学
  • 直接让前端请求代理到自己的本地服务器,告别CV报文到自己的API工具,解放双手
  • android View详解—自定义ViewGroup,流式布局
  • 亚洲数字能源独角兽的 “安全密码”:Parasoft为星星充电筑牢软件防线
  • MongoDB 高可用部署:Replica Set 搭建与故障转移测试
  • SpringCloud微服务基于nacos注册中心的服务发现模式及OpenFeign的使用
  • Redis在商城开发中起到什么作用?
  • 漏洞修复 Nginx TLSSSL 弱密码套件
  • 2025国赛C题保姆级教程思路分析 NIPT 的时点选择与胎儿的异常判定
  • 【完整源码+数据集+部署教程】陶瓷物品实例分割系统源码和数据集:改进yolo11-LVMB
  • 第22节:性能监控与内存管理——构建高性能3D应用
  • 3ds Max流体模拟终极指南:打造逼真液体效果,从瀑布到杯中溢出的饮料!
  • 240. 搜索二维矩阵 II
  • 2025年含金量高的经济学专业证书工科!【纯干货分享】
  • 文件系统-哈希结构文件
  • 食物分类案例优化 调整学习率和迁移学习
  • Paraverse平行云实时云渲染助力第82届威尼斯电影节XR沉浸式体验
  • 火山引擎数据智能体DataAgent总结分享
  • 小型企业MES软件开发的核心要点
  • 遥感语义分割辅导
  • PWM正相输出和PWM反相输出的各是怎样的工作原理
  • 别再和正则表达式死磕了!这套AI工具集让你的开发效率翻倍⚙️[特殊字符]
  • OPENCV复习第二期
  • 【ffmepg+ AI 】从mp3歌曲提取伴奏(纯音乐)