说明
博主我最近去面试,面试的公司问了很多问题,其中有2个和算法相关的题目,没回答上来,后来回来仔细看了下 其实也是很简单的,主要还是这些年 忽略了基础的一些算法,立下个Flag 这下半年 好好的 温习下算法,刷下leetcode.
话不多说,其中的一问题是这样的:
面试官:你知道栈结构么?栈和队列有啥区别?怎么用2个栈去实现一个队列?
栈??? 嗯嗯 知道这个结构 但是很少用呀~? 栈和队列的区别不就是 数据一个树先进先出,一个先进后出么!2个栈实现一个队列???
分析
其实这个题目,我很久之前就看过,当时也没注意,就是大概扫了一下,自己也没有用心去思考!导致了面试的时候 不知道怎么去实现~
首先我们看下这个栈的结构:
栈
Java 中的栈是Stack
class Stack<E> extends Vector<E> {
public E push(E item) {
addElement(item);
return item;
}
/**
* 放入一个元素到栈的顶端
*/
public E push(E item) {
addElement(item);
return item;
}
/**
* 线程安全的方法 从栈顶取值 并做取出完移除操作
*/
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
/**
* 线程安全的方法 从栈顶取值 如果空 抛出异常
*/
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
}
从栈的源码上来看,内部得代码很少,基本都是调用的继承类Vector的方法
Vector
我们再看下 Vector的代码 是怎么做的:
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
protected Object[] elementData;//存储栈元素的容器
protected int elementCount;//栈元素的大小
public Vector() {
this(10);// 默认大小是10
}
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);//确认数组容量的大小,如果不够会去做数组扩容操作
elementData[elementCount++] = obj;// 相当于栈顶放入元素
}
public synchronized E elementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);//Stack 在调用此方法的时候,传的都是栈顶的原数的位置
}
E elementData(int index) {
return (E) elementData[index];
}
}
有兴趣的可以看下ensureCapacityHelper 这个方法 看名字 应该也能猜到 这个是一数组大小判断的,如果不够应该会做扩容操作,Vector的扩容 还可以设置每次扩容的时候增长的大小,如果不设置 就是默认的double!~
说了这么多和面试的题目一点儿关系都没有哈全是废话 哈哈~
现在步入正题,上面我也说过 栈是后入先出 队列是 先入先出,这个时候又2个栈,怎么去实现?
其实现在想想也简单的,一个栈是后入先出,如果我们把这个栈 倒入另外一个栈 这样另外一个栈数据的顺序 刚好从栈顶到栈底,然后再冲栈顶取出,这样不就是间接实现了先入先出的么!
嗯嗯应该是这样的~
代码
show code:
/// 定义实现类
static class StackToQueue<T> {
public volatile boolean IsEmpty = true;//判断 元素是否为空
private volatile Stack<T> stack1 = new Stack<>();// 栈1
private volatile Stack<T> stack2 = new Stack<>();// 栈2
public synchronized void push(T data) {
stack1.push(data);
IsEmpty = false;
}
public synchronized T pop() {
if (stack1.isEmpty()) {
return null;
}
while (stack1.isEmpty() == false) {
stack2.push(stack1.pop());//将栈1元素倒入到栈2中
}
T popData = stack2.pop();// 从栈2的取出原数 此元素就是栈1的底部元素
while (stack2.isEmpty() == false) {
stack1.push(stack2.pop());
}
if (stack1.isEmpty()) {
IsEmpty = true;
}
return popData;
}
}
测试方法:
/**
* @ClassName StackForListTest
* @Auther burgxun
* @Description: 2个栈去实现一个队列
* @Date 2020/09/07 11:16
**/
public class StackToQueueTest {
public static void main(String[] args) {
Queue<Integer> queue;
StackToQueue<Integer> stackToQueue = new StackToQueue<>();
stackToQueue.push(1);
stackToQueue.push(2);
stackToQueue.push(3);
stackToQueue.push(4);
stackToQueue.push(5);
while (stackToQueue.IsEmpty == false) {
Integer integer = stackToQueue.pop();
if (integer != null) {
System.out.println("输出:" + integer);
}
}
}
}
输入结果:
输出:1
输出:2
输出:3
输出:4
输出:5
总结
其实这个题目 真的不是很难的,我没有回答出来的原因有2个:
- 2个面试官 问了大概40分钟后,出现的这个题目,当时已经很累了,加上这个面试已经是我当天下午第二场面试,个人确实有点困乏!
- 没回答上来 也不能给自己找借口 还是自己对算法性的题目掌握不好,基础不扎实导致,后面继续加油吧~
- 面试的时候 应该冷静一下,和面试官说 让思考一下,我相信 如果 冷静下来,这个题目还是很好回答的,其实当时心里已经有思路了,但是由于紧张和累,就懒得继续想下去了~
继续加油~!!!!