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

数据结构之队列

系列文章目录

数据结构之ArrayList-CSDN博客

数据结构之LinkedList-CSDN博客

数据结构之栈-CSDN博客


目录

系列文章目录

前言

一、队列和链表

二、队列的常用方法

三、队列的模拟实现

1. 使用双向链表实现队列

2. 使用环形数组实现队列

四、队列和栈

1. 使用两个队列模拟实现栈

2. 使用两个栈模拟实现队列


前言

本文介绍了队列的常用方法,分别使用双向链表和环形数组模拟实现队列,使用队列模拟实现栈,以及使用栈模拟实现队列。


一、队列和链表

队列是一种特殊的线性表,允许在一端进行数据的插入,另一端进行数据的删除。插入一端称为队尾,删除一端称为队头。

队列的底层是一个链表,Queue 是单链表的数据结构,Deque 是双端链表,LinkedList 既实现了Queue,也实现了 Deque,同时还实现了 List,因此 LinkedList 既可以实现队列,又可以实现栈;

如果使用单链表实现栈:

尾插法入栈的时间复杂度是 O(N),尾删出栈的时间复杂度也是 O(N);

头插法入栈的时间复杂度是 O(1),头删出栈的时间复杂度也是 O(1);

如果增加尾指针:

尾插法入栈的时间复杂度是 O(1),尾删出栈的时间复杂度还是 O(N);

如果使用双向链表实现栈:

头插法入栈,头删出栈,尾插法入栈,尾删出栈的时间复杂度都是 O(1);

因此栈的实现既可以是顺序栈,也可以是链式栈;

队列也可以使用环形数组进行实现。

二、队列的常用方法

offer(E e): boolean 元素入队;

poll(): E 元素出队;

peek(): E 查看队头元素;

size(): int 返回队列元素个数;

isEmpty(): boolean 判断队列是否为空;

三、队列的模拟实现

1. 使用双向链表实现队列

public class MyQueue {static class ListNode{private int val;private ListNode prev;private ListNode next;public ListNode(int val){this.val = val;}}private ListNode front;private ListNode rear;private int usedSize;public void offer(int x){ListNode node = new ListNode(x);if(this.front == null){this.front = node;this.rear = node;}else{this.rear.next = node;node.prev = this.rear;this.rear = node;}this.usedSize++;}public ListNode poll(){if(this.front == null){return null;}ListNode ret = this.front;this.usedSize--;if(this.front == this.rear){this.front = null;this.rear = null;return ret;}this.front = this.front.next;this.front.prev = null;return ret;}public ListNode peek(){if(this.front == null){return null;}return this.front;}public int size(){return this.usedSize;}public boolean isEmpty(){return this.usedSize == 0;}
}

2. 使用环形数组实现队列

front 表示环形数组中第一个元素的下标;

rear 表示环形数组中能够存放元素的下标;

len 表示环形数组的长度;

如何识别空和满:

可以定义一个 usedSize,当 usedSize == len 时,数组满;

可以通过标记,满了就将标记置为 true;

可以浪费一个空间,当 rear + 1 == front 就是满;

如何解决从最后一个下标到 0 下标的问题:

rear = (rear + 1) % len 

front = (front + 1) % len

通过上述公式,可以保证 front 和 rear 从最后一个下标往下走一步达到 0 下标;

以下采用浪费一个空间的方式使用环形数组模拟实现队列:

class MyCircularQueue {private int[] queue;private int front;private int rear;public MyCircularQueue(int k) {this.queue = new int[k + 1];}public boolean enQueue(int value) {if(isFull()) return false;this.queue[this.rear] = value;this.rear = (this.rear + 1) % this.queue.length;return true;}public boolean deQueue() {if(isEmpty()) return false;this.front = (this.front + 1) % this.queue.length;return true;}public int Front() {if(isEmpty()) return -1;return this.queue[this.front];}public int Rear() {if(isEmpty()) return -1;return this.queue[(rear - 1 + this.queue.length) % this.queue.length];}public boolean isEmpty() {if(this.rear == this.front) {return true;}return false;}public boolean isFull() {if((this.rear + 1) % this.queue.length == this.front) {return true;}return false;}
}

四、队列和栈

1. 使用两个队列模拟实现栈

入栈:当两个队列都为空,元素先放在队列 1 中,当有一个不为空,放到不为空的队列中;

出栈:当两个队列都为空,返回 -1,当有一个队列不为空,将该队列的前 n - 1 个元素放到另一个队列,弹出该队列的最后一个元素并返回;

查看栈顶元素:当两个队列都为空,返回 -1,当一个队列不为空,将该队列的前 n - 1 个元素放到另一个队列,弹出该队列的最后一个元素并保存,将该元素也存到另一个队列,并返回保存的值;

判断栈是否为空:当两个队列都为空,返回 true,否则返回 false;

import java.util.*;public class QueueToStack {private Queue<Integer> q1;private Queue<Integer> q2;public QueueToStack() {q1 = new LinkedList<>();q2 = new LinkedList<>();}public void push(int x) {if(q1.isEmpty() && q2.isEmpty()){q1.offer(x);}else{if(!q1.isEmpty()){q1.offer(x);}else{q2.offer(x);}}}public int pop() {if(empty()) return -1;if(!q1.isEmpty()){int size = q1.size();while(--size > 0){int t = q1.poll();q2.offer(t);}return q1.poll();}else{int size = q2.size();while(--size > 0){int t = q2.poll();q1.offer(t);}return q2.poll();}}public int top() {if(empty()) return -1;int ret = 0;if(!q1.isEmpty()){int size = q1.size();while(--size > 0){int t = q1.poll();q2.offer(t);}ret = q1.poll();q2.offer(ret);return ret;}else{int size = q2.size();while(--size > 0){int t = q2.poll();q1.offer(t);}ret = q2.poll();q1.offer(ret);return ret;}}public boolean empty() {if(q1.isEmpty() && q2.isEmpty()){return true;}return false;}
}

2. 使用两个栈模拟实现队列

入队:放到第一个栈;

出队:如果队列为空,返回 -1,否则从第二个栈出,如果第二个栈为空,就将第一个栈的元素出栈,放到第二个栈,直到第一个栈为空,从第二个栈出;

查看队头元素:如果队列为空,返回 -1,否则查看第二个栈栈顶元素,如果第二个栈为空,就将第一个栈的元素出栈,放到第二个栈,直到第一个栈为空,查看第二个栈栈顶元素;

判断队列是否为空:如果两个栈都为空,返回 true,否则返回 false;

import java.util.*;public class StackToQueue {private Stack<Integer> stack1;private Stack<Integer> stack2;public StackToQueue() {stack1 = new Stack<>();stack2 = new Stack<>();}public void push(int x) {stack1.push(x);}public int pop() {if(empty()) return -1;if(stack2.isEmpty()){while(!stack1.isEmpty()){int t = stack1.pop();stack2.push(t);}}int ret = stack2.pop();return ret;}public int peek() {if(empty()) return -1;if(stack2.isEmpty()){while(!stack1.isEmpty()){int t = stack1.pop();stack2.push(t);}}int ret = stack2.peek();return ret;}public boolean empty() {if(stack1.isEmpty() && stack2.isEmpty()){return true;}return false;}
}

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

相关文章:

  • 基于SpringBoot实现的汽车资讯网站设计与实现【源码+文档】
  • CppCon 2015 学习:Simple, Extensible Pattern Matching in C++14
  • AI重塑SEO关键词精准策略
  • Linux离线(zip方式)安装docker
  • 能源即服务:智慧移动充电桩的供给模式创新
  • 网络安全:数字时代的守护盾
  • 爬虫基础学习day2
  • 解密鸿蒙系统的隐私护城河:从权限动态管控到生物数据加密的全链路防护
  • C++编译之导入库理解与使用
  • React Hooks 的原理、常用函数及用途详解
  • crackme006
  • 抽象类和接口(全)
  • 98.错误走百度翻译API的苦98步
  • 深入浅出JavaScript中的ArrayBuffer:二进制数据的“瑞士军刀”
  • 从数据到价值:企业构建大数据价值链的核心战略
  • 闭合逻辑检测(保留最大连通分量)
  • 浏览器中 SignalR 连接示例及注意事项
  • 信创领域下的等保合规建设及解读
  • ava多线程实现HTTP断点续传:原理、设计与代码实现
  • 大学生职业发展与就业创业指导教学评价
  • 用 FFmpeg 实现 RTMP 推流直播
  • ArcGIS Pro裁剪栅格影像
  • 洞见未来医疗:RTC技术如何重塑智慧医疗新生态
  • __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined.
  • android RecyclerView 加载不同的item
  • 基于STM32物联网智能鱼缸智能家居系统
  • Android Framework 之 AudioDeviceBroker
  • 关于TFLOPS、GFLOPS、TOPS
  • 高等三角函数大全
  • 基于Flask,MySQL和MongoDB实现的在线阅读系统