前言
前面说明了什么是栈,栈是数据结构的一种结构,其特点是先入后出,而今天所要说明的是一个新的结构,其特点是先进先出,就和我们在饭堂打饭是一样的!!都是从队尾进,队头出,这和栈是不一样的,但是两个结构也是可以相互实现的,下面让我们进入队列的世界!
一、队列是什么?
队列是一种特殊的线性表,特殊之处在于它只允许在表的队头进行删除操作,而在表的队尾进行插入操作,和栈一样,队列是一种操作受限制的线性表。队列下层实际上一个双向链表(LinkedList),所以实现队列也是和这个息息相关的。
二、各种方法
入队操作:offer(e)常用,add(e)此入队(如果违反的容量限制会直接抛出异常,而前者不会)
Queue<Integer> queue = new LinkedList<>();
queue.offer(1);
出队操作:poll()常用,remove()也会抛出异常
queue.poll();
队顶元素:peek()常用,element()也会抛出异常
queue.peek();
是否为空:isEmpty()
queue.isEmpty();
三、栈和队列的相互实现
使用栈实现队列
class MyQueue {
public Stack<Integer> stack1;
public Stack<Integer> stack2;
public MyQueue() {
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()){
stack2.push(stack1.pop());
}
}
return stack2.pop();//第二个栈出来的元素就是第一个栈刚放进去的元素
}
public int peek() {
if(empty())return -1;
if(stack2.isEmpty()){
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
}
return stack2.peek();
}
public boolean empty() {
return stack1.isEmpty() && stack2.isEmpty();
}
}
使用队列实现栈
class MyStack {
public Queue<Integer> qu1;
public Queue<Integer> qu2;
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);
}
}
public int pop() {
if(empty()){
return -1;//业务处理,可以抛异常
}
if(!qu1.isEmpty()){//不空的队列就出队,,给另一个队列,只剩下一个最后一个元素,这个就应该是要出栈的元素
int x = qu1.size();
for(int i = 0;i < x - 1;i ++){
qu2.offer(qu1.poll());
}
return qu1.poll();
}
if(!qu2.isEmpty()){
int x = qu2.size();
for(int i = 0;i < x - 1;i ++){
qu1.offer(qu2.poll());
}
return qu2.poll();
}
return -1;
}
public int top() {
if(empty())return -1;//业务处理,可以抛异常
if(!qu1.isEmpty()){
int x = qu1.size();
int val = 0;
for(int i = 0;i < x;i ++){
val = qu1.poll();
qu2.offer(val);//保留最后一个元素的val值就是栈顶的元素
}
return val;
}
if(!qu2.isEmpty()){
int x = qu2.size();
int val = 0;
for(int i = 0;i < x;i ++){
val = qu2.poll();
qu1.offer(val);
}
return val;
}
return -1;
}
public boolean empty() {
return qu1.isEmpty() && qu2.isEmpty();
}
}
四、循环队列
循环队列就类似于是一个环形数组
判断循环队列是否满与空
1.定义一个变量usedSize,与数组长度进行比较,相等则为满,为0则为空;
2.使用标志位:开始设置一个flg为false,rear走动即每放一个元素将其变为true,front走动即出一个元素将其变为false,当front和rear相遇时,若flg为true则为满,反之则为空;
3.牺牲一个位置,若front与rear相遇则为空,若(rear + 1 )% length== front则为满
可以使用数组实现循环队列
class MyCircularQueue {
public int[] elem;
public int front;//队头
public int rear;//队尾
public myCircularQueue(int k) {
elem = new int[k + 1];//会浪费一个元素 所以要多一个元素
}
public boolean enQueue(int value) {//入队
if(isFull())return false;
elem[rear] = value;
//rear++
rear = (rear + 1) % elem.length;
return true;
}
public boolean deQueue() {//出队
if(isEmpty())return false;
//floan ++
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 a = -1;
if(rear == 0){//队尾为0 则要重新赋值
a = elem.length - 1;
}else{
a = rear -1;
}
return elem[a];
}
public boolean isEmpty() {//是否为空
return rear == front;
}
public boolean isFull() {//是否满
if((rear + 1) % elem.length == front){//队尾的下一个元素为队头
return true;
}
return false;
}
}
总结
使用单链表,双向链表,栈都是可以实现队列的,队列相对而言是比较方便的,也更符合我们的日常生活,所以学会队列还是很关键的!