当前位置:   article > 正文

数据结构——队列(Queue)详解_queue队列

queue队列

1.队列(Queue)

1.1概念

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

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

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

1.2 队列的使用

在Java中,Queue是个接口,底层是通过链表实现的,在实例化Queue时,必须实例化LinkedList对象,因为LinkedList实现了Queue接口

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

1.3 队列模拟实现(双列表实现)

  1. public class MyQueue {
  2. static class ListNode {
  3. public int val;
  4. public ListNode prev;
  5. public ListNode next;
  6. public ListNode(int val) {
  7. this.val = val;
  8. }
  9. }
  10. public ListNode first;
  11. public ListNode last;
  12. //尾插
  13. public void offer(int val) {
  14. ListNode node = new ListNode(val);
  15. if(first == null) {
  16. first = last = node;
  17. }else {
  18. node.prev = last;
  19. last.next = node;
  20. last = last.next;
  21. }
  22. }
  23. //头删
  24. public int poll() {
  25. //队列为空
  26. if(first == null) {
  27. return -1;
  28. }
  29. int ret = first.val;
  30. //队列只有一个节点
  31. if(first.next == null) {
  32. first = last = null;
  33. }else {
  34. //队列有多个节点
  35. first = first.next;
  36. first.prev = null;
  37. }
  38. return ret;
  39. }
  40. //查看队头元素
  41. public int peek() {
  42. if(first == null) {
  43. return -1;
  44. }
  45. return first.val;
  46. }
  47. //判断队列是否为空
  48. public boolean isEmpty() {
  49. return first == null;
  50. }
  51. }

1.4 循环队列(数组实现)

一开始,first 和 last 从0下标开始,放一个元素 last++ ,如此,last 即为元素当前要存放的下标

 判断循环队列是否已满:

 解决下标从7 到 0 的过程,不能一直让 last++、first++,这样肯定会越界

公式:last = ( last + 1 ) % len(数组长度)

代码:

  1. class MyCircularQueue {
  2. public int[] elem;//数组实现
  3. public int first;
  4. public int last;
  5. public MyCircularQueue(int k) {
  6. //因为计数方法为保留一个空间,所以想要存放K个元素,需要申请K+1个空间
  7. elem = new int[k+1];
  8. }
  9. //队尾添加元素
  10. public boolean enQueue(int value) {
  11. if(isFull()) {
  12. return false;
  13. }
  14. elem[last] = value;
  15. last = (last+1)%elem.length;
  16. return true;
  17. }
  18. //队头删除元素
  19. public boolean deQueue() {
  20. if(isEmpty()) {
  21. return false;
  22. }
  23. first = (first+1)%elem.length;
  24. return true;
  25. }
  26. //从队头获取元素
  27. public int Front() {
  28. if(isEmpty()){
  29. return -1;
  30. }
  31. return elem[first];
  32. }
  33. //从队尾获取元素
  34. public int Rear() {
  35. if(isEmpty()){
  36. return -1;
  37. }
  38. int index = (last == 0) ? elem.length-1 : last-1;
  39. return elem[index];
  40. }
  41. //判空
  42. public boolean isEmpty() {
  43. return first == last;
  44. }
  45. //判满
  46. public boolean isFull() {
  47. return (last+1)%elem.length == first;
  48. }
  49. }

2. 双端队列(Deuqe)常用!

双端队列是指允许两端都可以进行入队和出队操作的队列,deque是 "double ended queue" 的简称

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

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

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

3. OJ

3.1 用队列实现栈

  1. import java.util.LinkedList;
  2. import java.util.Queue;
  3. //用队列实现栈
  4. //该方法用到两个队列
  5. class MyStackUseQueue {
  6. Queue<Integer> qu1;
  7. Queue<Integer> qu2;
  8. public MyStackUseQueue() {
  9. qu1 = new LinkedList<>();
  10. qu2 = new LinkedList<>();
  11. }
  12. public void push(int x) {
  13. if(empty()) {//若两队列均为空,将x添加到qu1中
  14. qu1.offer(x);
  15. return;
  16. }
  17. if(!qu1.isEmpty()) {//两队列哪个不为空,添加到哪个里面
  18. qu1.offer(x);
  19. }else {
  20. qu2.offer(x);
  21. }
  22. }
  23. //删除栈顶元素
  24. public int pop() {
  25. if(empty()) {//若两队列均为空,返回-1
  26. return -1;
  27. }
  28. if(!qu1.isEmpty()) {//若qu1不为空,将qu1中size-1个元素放到qu2中,剩下一个元素即为栈顶元素
  29. int size = qu1.size();//存放qu1元素个数
  30. for (int i = 0; i < size-1; i++) {//循环size-1次将元素放到qu2中
  31. qu2.offer(qu1.poll());
  32. }
  33. return qu1.poll();//将qu1中剩下一个元素出队
  34. }else {
  35. int size = qu2.size();//与上同理
  36. for (int i = 0; i < size-1; i++) {
  37. qu1.offer(qu2.poll());
  38. }
  39. }
  40. return qu2.poll();
  41. }
  42. //获取栈顶元素
  43. public int top() {
  44. if (empty()) {
  45. return -1;
  46. }
  47. //若qu1不为空,循环将qu1中所有元素,通过中间变量ret放到qu2中,当放完后,ret中存放的值即为栈顶元素
  48. if (!qu1.isEmpty()) {
  49. int size = qu1.size();
  50. int ret = -1;
  51. for (int i = 0; i < size; i++) {
  52. ret = qu1.poll();//qu1中元素出队,赋值给ret
  53. qu2.offer(ret);//ret中值入队给qu2
  54. }
  55. return ret;
  56. } else {
  57. int size = qu2.size();
  58. int ret = -1;
  59. for (int i = 0; i < size; i++) {
  60. ret = qu2.poll();
  61. qu1.offer(ret);
  62. }
  63. return ret;
  64. }
  65. }
  66. public boolean empty() {
  67. return qu1.isEmpty() && qu2.isEmpty();
  68. }
  69. }

3.2 用栈实现队列

  1. import java.util.Stack;
  2. //用栈实现队列,先进先出,用到两个栈
  3. class MyQueueUseStack {
  4. Stack<Integer> st1;
  5. Stack<Integer> st2;
  6. public MyQueueUseStack() {
  7. st1 = new Stack<>();
  8. st2 = new Stack<>();
  9. }
  10. //添加元素全部添加到st1中
  11. public void push(int x) {
  12. st1.push(x);
  13. }
  14. //删除队首元素
  15. public int pop() {
  16. if(empty()) {
  17. return -1;
  18. }
  19. //若st2不为空,将st1中元素pop,push到st2中
  20. if(st2.empty()) {
  21. while(!st1.empty()) {
  22. st2.push(st1.pop());
  23. }
  24. }
  25. //因为栈是先进后出,所以模拟队列的队首元素在st1的最下面
  26. //当把元素全部挪到st2中后,st2的栈顶元素即是队首元素
  27. return st2.pop();
  28. }
  29. public int peek() {
  30. if(empty()) {
  31. return -1;
  32. }
  33. if(st2.empty()) {
  34. while(!st1.empty()){
  35. st2.push(st1.pop());
  36. }
  37. }
  38. return st2.peek();
  39. }
  40. public boolean empty() {
  41. return st1.empty() && st2.empty();
  42. }
  43. }

以上两个OJ,若用双端队列来实现会更简单

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/975010
推荐阅读
相关标签
  

闽ICP备14008679号