栈和队列使操作受限制的线性表,本质上栈和队列没啥不同,可以相互转换。
栈:一种特殊的线性表,其只允许在指定的一端进行查如何删除元素操作,进行数据插入和删除操作的一端称为栈顶,另一端称为栈底,栈中的数据元素遵守后进先出(LIFO)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,push。
出栈:栈的删除操作叫做出栈,pop。
查看栈顶元素peek,只取值,不删除。
栈的实现根据实用的内部结构不同分为顺序栈和链式栈,顺序栈的内部还是动态数组,规定只能从数组的末尾进行插入和删除,链式栈的内部是链表,规定在链表的尾部进行插入和删除。
顺序栈的基础构造和动态数组几乎完全一样。主要实现四个方法,pop,push,peek,toString。
push方法就是相当于动态数组的尾插法,也要考虑到是否扩容。pop方法就是在在栈中有存储时也就是size!=0,存储最后一位元素然后把它删除并且返回。peek就是返回最后一位元素的值不进行其他操作。
public class stack {private int size;private int[] data;public stack(){this(10);}public stack(int capacity){this.data = new int[capacity];}public void push(int val){this.data[size] = val;size++;if(size>data.length){this.data = Arrays.copyOf(data,data.length>>1);}}public int pop() throws NoSuchFieldException {if(size ==0){throw new NoSuchFieldException("stack is Null!");}int i = this.data[size-1];size--;return i;}public int peek() throws NoSuchFieldException {if(size ==0){throw new NoSuchFieldException("stack is Null!");}int i = this.data[size-1];return i;}@Overridepublic String toString() {StringBuilder sb = new StringBuilder("[");for(int i = 0;i
public class stackTest {public static void main(String[] args) throws NoSuchFieldException {stack s = new stack();s.push(1);s.push(3);s.push(5);s.push(7);System.out.println(s.toString());System.out.println(s.pop());System.out.println(s.peek());System.out.println(s.toString());}
}
首先插入1,3,5,7。然后调用toString展示栈,在调用pop,显示最后一位元素并且删除,在调用peek查看新的最后一位元素, 再调用toString展示栈。

JDK中的栈是一个具体的类Stack,主要方法就是pop,push,peek。
只需要把每一项链表的值一个个存储到栈中,然后直到栈空,再停止输出。运用了栈的后进先出的特点。
public void printReverseByStack(){Stack s = new Stack<>();Node node = head;while(node != null){s.push(node.val);node = node.next;}while (!s.empty()){System.out.print(s.pop()+"->");if(s.empty()){System.out.println("NULL");}}}
public static void main(String[] args) {LinkedListR list = new LinkedListR();list.addFirst(1);list.addFirst(3);list.add(5);list.add(7);list.add(1,10);list.print();list.printReverseByStack();}

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack() 初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取堆栈顶部的元素。 int getMin() 获取堆栈中的最小元素。

一个栈是解决不了的,top和getMin是两个相互独立的方法,top返回当前栈顶元素,getMin在O(1)返回最小值。

所以我们创建两个栈,real用于实际存储元素,min用于存储最小值并且保证栈顶元素一定是real中的最小值。

首先第一个元素是-2,直接入real栈,然后判断min栈是否为空,如果是空就直接将元素入min栈。

然后再将第二个元素0入real栈,这时min栈不是空的了,那么就和min栈顶元素进行比较,比他大,那么继续将栈顶元素入min栈。

然后最后一个元素-3先入real栈,这时min栈也不是空的,那么就和min栈顶元素进行比较,比他小,那么直接将该元素元素入min栈。这时入栈操作已经结束了。getMin直接返回的是min的栈顶元素-3,就是最小的元素。

这时在进行real的pop操作,弹出栈顶元素-3,同时也要将min的栈顶元素弹出,这时的top输出的元素就是0。getMin输出的还是min的栈顶元素,这次变成了-2。
public class Num155 {private static class MinStack {private Stack real;private Stack min;public MinStack() {real = new Stack<>();min = new Stack<>();}public void push(int val) {if (min.isEmpty()) {min.push(val);}else {int top = min.peek();int minVal = Math.min(top,val);min.push(minVal);}real.push(val);}public void pop() {real.pop();min.pop();}public int top() {return real.peek();}public int getMin() {return min.peek();}}
}
根据 逆波兰表示法,求表达式的值。 有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。 注意 两个整数之间的除法只保留整数部分。 可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况 。

((1+2)*3+4)/5 是中缀表达式,两个操作数中间是运算符,符合咱们人脑的思维模式,计算机很难使用中缀表达式进行计算。
((((12+)3*)4+))5/ 是后缀表达式,两个操作数先写,后面紧跟的运算符就是马上要进行运算的运算符,称作逆波兰表达式。
所以我们创建一个栈,如果遇到数字直接就入栈,遇到运算符,就弹出两个栈顶元素进行运算,再将结果入栈。并且要注意-和/时两个元素的运算顺序。

首先遇到了两个数字所以将他们依次入栈,然后下一个是+号,则将两个数字出栈进行加法运算然后把得到的3入栈,接下来碰到的也是数字是3,再将3入栈。

这时又碰到了*号,那么再将栈中出栈两个元素进行乘法运算,得到的9入栈。

这时已经将所有tokens元素遍历完,最终stack栈顶元素就是运算后的值。返回即可。
public class MyQueue {private Stack s1 = new Stack<>();private Stack s2 = new Stack<>();public MyQueue() {}public void push(int x) {while(!s1.empty()){s2.push(s1.pop());}s1.push(x);while(!s2.empty()){s1.push(s2.pop());}}public int pop() {return s1.pop();}public int peek() {return s1.peek();}public boolean empty() {return s1.empty();}
}
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

按照正常思维就是将pushed中的数一个一个入栈,如果栈顶元素=popped[0],那么就出栈,然后栈顶元素继续和popped[1]比较,如果不相同就跳出循环然后继续这个操作,先入栈然后继续判断。

如实例一,先把pushed一个一个入栈,当栈顶元素为4时和popped[0]相等,所以出栈,然后继续比较,这个时候有特殊条件就是栈不能为空,栈如果为空直接跳出循环。这是栈顶元素为3和popped[1]不相等,所以跳出循环,继续入栈。

将最后一个pushed元素入栈后再和popped数组剩下元素一个一个比较,比较结束后,如果栈是空的即popped数组是合理的返回true,不为空则不合理返回false。
public boolean validateStackSequences(int[] pushed, int[] popped) {Stack s = new Stack<>();int i = 0;for(int p:pushed){s.push(p);while(i
栈是一个数据结构的栈,是线性表的一种,满足后进先出的特点。保存在栈中的元素都是相同数据类型。
虚拟机栈是一个操作系统栈,是一个概念性的东西,底层到底是不是用的栈(数据结构),到底用的链式栈还是顺序栈都不是关键。
栈帧:函数从调用过程到结束的一个体现,一个函数从调用到销毁其中占用的空间,内部的局部变量都统一放在该函数的栈帧中(一种类型,专门描述函数在操作系统内部的调用过程),可以看做是一个class。
队列也是操作受限的线性表,只能从队列的一段添加元素(队尾),从队列的另一端删除元素(对首)。是一种先进先出的结构(FIFO)。
入队:向队列中添加元素。叫做offer。
出队:从队列中移除元素。叫做poll。
广义上的队列一般有以下几种:
1、普通队列,链式队列-基于链表实现(单链表足够,尾插头删)。
2、循环队列,可以从队尾走到对首,使用定长数组来实现。
3、优先级队列,一般都是先进先出,但是优先级较高的元素可以优先出队。内部使用堆这个数据结构来实现,JDK默认使用的是最小堆-完全二叉树。
一共有四个方法,入队、出队,查看队首元素,判断队列是否为空。
public interface Queue {void offer(int val);// 出队int poll();// 查看队首元素int peek();// 判断队列是否为空boolean isEmpty();
}
普通队列一般都是用单链表实现的,就是多了一个尾结点。
offer就是入队操作,也就是单链表的尾插法。
poll就是出队操作,排除队列为空之后,删除头结点即可。
peek查看队首元素直接输出头结点值即可。
public class LinkedQueue implements Queue {private int size;private Node head;private Node tail;private static class Node {int val;Node next;public Node(int val) {this.val = val;}}@Overridepublic void offer(int val) {Node node = new Node(val);size ++;if (tail == null) {head = tail = node;return;}tail.next = node;tail = node;}@Overridepublic int poll() {if (isEmpty()) {throw new NoSuchElementException("queue is empty!cannot poll!");}Node node = head;head = head.next;node.next = null;return node.val;}@Overridepublic int peek() {if (isEmpty()) {throw new NoSuchElementException("queue is empty!cannot peek!");}return head.val;}@Overridepublic boolean isEmpty() {return size == 0;}public String toString() {StringBuilder sb = new StringBuilder();sb.append("front [");for (Node x = head;x != null;x = x.next) {sb.append(x.val);if (x.next != null) {sb.append(", ");}}sb.append("] tail");return sb.toString();}
}
public static void main(String[] args) {Queue queue = new LinkedQueue();queue.offer(1);queue.offer(3);queue.offer(5);queue.offer(7);System.out.println(queue.poll());System.out.println(queue.peek());System.out.println(queue);}

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。 实现 MyStack 类: void push(int x) 将元素 x 压入栈顶。 int pop() 移除并返回栈顶元素。 int top() 返回栈顶元素。 boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

运用两个队列q1和q2来实现栈,q1一直作为存放元素的队列,q2作为辅助队列。

首先第一次向队列中插入元素,先将元素插入到q2,如果q1为空,则直接将q1和q2相互转换。

然后再将新的元素入队q2,这时q1中有元素那么久直到q1为空,一直把q1元素出队,入队q2。

然后将q1和q2相互转换。
public class MyStack {private Queue q1;private Queue q2;public MyStack() {q1 = new LinkedList<>();q2 = new LinkedList<>();}public void push(int x) {q2.offer(x);while (!q1.isEmpty()) {q2.offer(q1.poll());}Queue temp = q1;q1 = q2;q2 = temp;}public int pop() {return q1.poll();}public int top() {return q1.peek();}public boolean empty() {return q1.isEmpty();}
}
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): 实现 MyQueue 类: void push(int x) 将元素 x 推到队列的末尾 int pop() 从队列的开头移除并返回元素 int peek() 返回队列开头的元素 boolean empty() 如果队列为空,返回 true ;否则,返回 false

运用两个栈来实现队列,s1一直作为存放元素的栈,q2作为辅助栈。

每次有新的元素的时候,都要判断s1是否为空,s1为空那么直接将元素入s1栈即可。

在有新的元素的时候,需要s1不为空,那么就需要将s1的元素逐个向s2中入栈,然后s1为空了再将新元素入栈。

最后再将s2中元素一个一个出栈入s1栈。
public class MyQueue {private Stack s1 = new Stack<>();private Stack s2 = new Stack<>();public MyQueue() {}public void push(int x) {while(!s1.empty()){s2.push(s1.pop());}s1.push(x);while(!s2.empty()){s1.push(s2.pop());}}public int pop() {return s1.pop();}public int peek() {return s1.peek();}public boolean empty() {return s1.empty();}
}
循环队列使用定长数组来实现,数组的首尾相连就构成了循环队列。循环队列一般用在os生产消费者模型。
head指向队列对首,tail引用指向队列最后一个元素的下一个索引,当head==tail,说明队列为空。
为了区分循环队列到底是满还是空,循环队列会浪费一个空间,来区分队列已满还是为空。就是要保存一个最大支持n个元素的循环队列,则开辟一个长度为n+1的数组,多余的这个空间就是来判断队列是否已满。当(tail+1)%num.length == head,则代表队列已满。