栈和队列
栈
栈:是一种先进后出的数据结构
例题1:不可能的出栈顺序
一个栈的入栈序列是a,b,c,d,e则栈的不可能的输出序列是:(c) A edcba B decba C dceab D abcde
分析:
A,根据先进先出的原则,将abcde全部入栈,然后再出栈,即为A选项
B,d先出,说明abc已经在栈中了,然后d进栈,再出栈,e进栈,再出栈,然后cba一次出栈,即为B选项
C,a不可能比b先出栈
D,a进栈,再出栈,b进栈,再出栈,c进栈,再出栈,d进栈,再出栈,e进栈,再出栈
例题2:中缀表达式转为后缀表达式(逆波兰表达式)
手工方式:
- 按先加减后乘除的原则给表达式加括号
((a+(b*c))+(((d*e)+f)*g))
- 由内到外把每个括号里的表达式换成后缀
abc*+de*f+g*+
例题3:利用顺序表实现栈
public class CreatStack {
public int[] elem;
public int usedSize;//记录当前下标
public CreatStack() {
this.elem = new int[5];
}
//压栈
public void push(int val) {
if (isFull()){
System.out.println("栈满");
return;
}
elem[usedSize]=val;
usedSize++;
}
//判满
public boolean isFull() {
if (usedSize==elem.length){
return true;
}
return false;
}
//弹出栈顶元素
public int pop() {
if (empty()) {
// System.out.println("栈空");
// return -1;
throw new RuntimeException("栈空");
}
int val = elem[usedSize - 1];
usedSize = usedSize - 1;
return val;
}
//判空
public boolean empty() {
if (usedSize==0){
return true;
}
return false;
}
//只是获取栈顶元素 但是不删除
public int peek() {
if (empty()) {
throw new RuntimeException("栈空");
}
return elem[usedSize - 1];
}
public static void main(String[] args) {
CreatStack creatStack = new CreatStack();
creatStack.push(2);
int ret1=creatStack.pop();
System.out.println(ret2);
}
}
队列
队列Queue:先进先出的数据结构,尾进,头进
双端队列Deque:队头可进可出,队尾可进可出
1.1 队列
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上 出数据,效率会比较低
public static void main(String[] args) {
Queue<Integer> queue=new LinkedList<>();
queue.offer(1);
queue.add(2);
int ret1=queue.poll();//出队【删除】
int ret2=queue.peek();//获取队头
}
例题1:用链表实现队列
public class TestQueue {
public static class Node{
public int val;
public Node next;
public Node(int val){
this.val=val;
}
}
public Node first;
public Node last;
//入队(尾插法)
public void offer(int val){
Node node=new Node(val);
if (this.first==null){
this.first=node;
this.last=node;
}else {
this.last.next=node;
this.last=node;
}
}
//出队(删除头结点)
public int poll(){
if(isEmpty()){
throw new RuntimeException("队列为空");
}else {
int val=this.first.val;
this.first=this.first.next;
return val;
}
}
public boolean isEmpty(){
return this.first==null;
}
public int peek(){
if (isEmpty()){
throw new RuntimeException("队列为空");
}
return this.first.val;
}
}
1.2 循环队列
循环队列通常用数组来实现
分析循环队列实现过程:
step1:设首节点front和尾结点rear都指向0下标,当一组数进入队列时,放在0下标,新的rear=(rear+1)%lengh
step2:此时队满rear再一次遇见front,都指向0下标,因此无法判断何时为空为满
step3:解决办法:浪费一个空间来表示队满的情况
放值之前,先判断rear的下一个是不是front,如果是,就不能放值了,如下图:该队列已满,7下标虽然没放值,但是99不能放进去
step4:出队时,出一个值,front向后走一个,新的front=(front+1)%lengh,直到front和rear相遇,指向同一下标时,队列为空。
例题1:循环队列的实现
public class MyCircularQueue {
private int[] elem;
private int front;
private int rear;
public MyCircularQueue(int k) {
this.elem=new int[k+1];//需要多给一个空间放判断满的rear
}
//入队
public boolean enQueue(int value) {
if (isFull()){
return false;
}
this.elem[this.rear]=value;
this.rear=(this.rear+1)%this.elem.length;
return true;
}
//出队
public boolean deQueue() {
if (isEmpty()){
return false;
}
this.front=(this.front+1)%this.elem.length;
return true;
}
//显示队头
public int Front() {
if (isEmpty()){
return -1;
}
return this.elem[this.front];
}
//除了空之外,还要判断0下标为值空的情况
public int Rear() {
if (isEmpty()){
return -1;
}
int index=-1;
if (this.rear==0){
index=elem.length-1;
}else {
index=this.rear-1;
}
return this.elem[index];
}
//判空,判满
public boolean isEmpty() {
return this.rear==this.front;
}
public boolean isFull() {
return (this.rear+1)%this.elem.length==this.front;
}
}