目录
一、初识队列
队列的概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(FirstIn First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)
队列的使用
在Java中,Queue是个接口,底层是通过链表实现的。
Queue的方法如下:
方法 | 功能 |
boolean offer(E e) | 入队列 |
E poll() | 出队列 |
peek() | 获取队头元素 |
int size() | 获取队列中有效元素个数 |
boolean isEmpty | 检测队列是否为空 |
二、模拟实现Queue
public class MyQueue {
class Node {
public int val;
public Node next;
public Node(int val){
this.val = val;
}
}
public Node head;
public Node tail;
/**
* 入队操作
* @param val
*/
public void offer(int val) {
Node node = new Node(val);
if(head == null) {
head = node;
tail = node;
}else {
tail.next = node;
tail = tail.next;
}
}
/**
* 出队操作
* @return
*/
public int poll() {
if (head == null) {
return -1;//或者抛异常
}
int oldVal = head.val;
if (head.next == null) {
head = tail = null;
}else {
head = head.next;
}
return oldVal;
}
//查看当前队头元素
public int peek() {
if(head == null) {
return -1;
}
return head.val;
}
}
测试用例:
三、循环队列
实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列通常使用数组实现。(这也意味着扩容的时候不好扩容)
或者使用计数器的方法(定义一个变量)来完成也可以。
代码实现:
public class MyCircularQueue {
public int[] elem;
public int usedSize;
public int front;
public int rear;
public MyCircularQueue(int x) {
this.elem = new int[x+1];
}
//入队操作
public boolean enQueue(int value) {
if (isFull()) {
return false;
}
this.elem[rear] = value;
//这里不能简单的使用++,否则在7-->0的时候就会有问题
rear = (rear+1) % elem.length;
return true;
}
//出队操作
public boolean deQueue() {
if (isEmpty()) {
return false;
}
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 x = (rear == 0) ? elem.length-1 : rear-1;
return elem[x];
}
public boolean isEmpty() {
return rear == front;
}
public boolean isFull() {
return (rear+1) % elem.length == front;
}
}
四、常见面试题
以下题均出自力扣,展示语言为Java。
易得:一个队列无法实现栈。
4.1 用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
- void push(int x) 将元素 x 压入栈顶。
- int pop() 移除并返回栈顶元素。
- int top() 返回栈顶元素。
- boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
源代码:
class MyStack {
Queue<Integer> qu1;
Queue<Integer> qu2;
public int usedSize;
public MyStack() {
qu1 = new LinkedList<>();
qu2 = new LinkedList<>();
}
public void push(int x) {
if(!qu1.isEmpty()) {
qu1.offer(x);
}else if(!qu2.isEmpty()) {
qu2.offer(x);
}else {
qu1.offer(x);
}
usedSize++;
}
public int pop() {
if(empty()) {
return -1;
}
if(!qu1.isEmpty()) {
int size = qu1.size();
for(int i = 0; i < size-1; i++) {
qu2.offer(qu1.poll());
}
usedSize--;
return qu1.poll();
}else {
//qu2不为空
int size = qu2.size();
for(int i = 0; i < size-1; i++) {
qu1.offer(qu2.poll());
}
usedSize--;
return qu2.poll();
}
}
public int top() {
if(empty()) {
return -1;
}
if(!qu1.isEmpty()) {
int size = qu1.size();
int ret = -1;
for(int i = 0; i < size; i++) {
ret = qu1.poll();
qu2.offer(ret);
}
return ret;
}else {
//qu2不为空
int size = qu2.size();
int ret = -1;
for(int i = 0; i < size; i++) {
ret = qu2.poll();
qu1.offer(ret);
}
return ret;
}
}
public boolean empty() {
return usedSize == 0;
}
}
题目来源:力扣
4.2 用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
- void push(int x) 将元素 x 推到队列的末尾
- int pop() 从队列的开头移除并返回元素
- int peek() 返回队列开头的元素
- boolean empty() 如果队列为空,返回 true ;否则,返回 false
说明:
- 你 只能 使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
- 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
源代码:
class MyQueue {
Stack<Integer> s1;
Stack<Integer> s2;
public MyQueue() {
s1 = new Stack<>();
s2 = new Stack<>();
}
public void push(int x) {
s1.push(x);
}
public int pop() {
if(empty()) {
return -1;
}
if(s2.empty()) {
while(!s1.empty()) {
s2.push(s1.pop());
}
}
return s2.pop();
}
public int peek() {
if(empty()) {
return -1;
}
if(s2.empty()) {
while(!s1.empty()) {
s2.push(s1.pop());
}
}
return s2.peek();
}
public boolean empty() {
return s1.empty() && s2.empty();
}
}
4.3 最小栈
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
- MinStack() 初始化堆栈对象。
- void push(int val) 将元素val推入堆栈。
- void pop() 删除堆栈顶部的元素。
- int top() 获取堆栈顶部的元素。
- int getMin() 获取堆栈中的最小元素。
源代码:
class MinStack {
private Stack<Integer> s;//普通栈
private Stack<Integer> minStack;//维护当前栈的最小值
public MinStack() {
s = new Stack<>();
minStack = new Stack<>();
}
public void push(int val) {
s.push(val);
if(minStack.empty()) {
//直接存储一份
minStack.push(val);
} else {
int peek = minStack.peek();
//如果相等也是要存储一份的,不然后续这个最小值就消失了
if(val <= peek) {
minStack.push(val);
}
}
}
public void pop() {
if(!s.empty()) {
int pop = s.pop();
int peek = minStack.peek();
if(pop == peek) {
minStack.pop();
}
}
}
public int top() {
if(!s.empty()) {
return s.peek();
}
return -1;
}
public int getMin() {
if(!minStack.empty()) {
return minStack.peek();
}
return -1;
}
}
题目链接: