[面试题]堆来模拟栈

#pre
面试的时候遇到的,面试官要求手写代码。问题本身不难,但是需要注意自己的想法是否最优

#问题分析
堆是后进先出,栈是先进先出,所以自然而然有了想法1,用栈去存储数据,如果需要返回数据,那么新建一个栈,把原来栈所有的东西弹出来,退出最底部的元素,返回给外部,然后将栈还原。

//使用语言java
import java.util.*;

//这里假定访问方式是单线程,如果多线程访问  需要对stack进行保护
public class Solution{

	Stack<Object> valueStack;
	
	public Solution(){
		//这部分声明不确定,java中可能是这么调用的
		valueStack = new ArrayList<>();
	}
	
	//返回值表明压栈是否成功
	public boolean push(Object value){
		//栈溢出的时候会返回异常
		try{
			valueStack.push(value);
		}catch(Exception e){
			return false;
		}
		return true;
	}
	
	//假定存储的元素不会是null
	public Object pop(){
		if(valueStack.size() <= 0){
			return null;
		}

		Stack cacheStack = new ArrayList<>();

		while(valueStack.size() > 0){
			cacheStack.push(valueStack.pop());
		}

		Object reval = cacheStack.pop();

		while(cacheStack.size() > 0){
			valueStack.push(cacheStack.pop());
		}
		return reval;
	}

}

#提示1:栈为什么还原
在想法1的基础上,在我们每次弹出一个元素的时候我们需要将栈反转一次,然后还原回来,如果连续遇到两次弹出操作,这个还原操作反而是浪费时间的操作,所以这里可以得到想法2,我们可以通过状态量来检测这个连续弹出的情况,如果不是连续弹出,然后就可以不用还原栈。

//使用语言java
import java.util.*;

//这里假定访问方式是单线程,如果多线程访问  需要对stack进行保护
public class Solution{

	Stack<Object> valueStack;
	Stack<Object> cacheStack;
	boolean inOrigin;
		

	public Solution(){
		//这部分声明不确定,java中可能是这么调用的
		valueStack = new ArrayList<>();
		cacheStack = new ArrayList<>();
		inOrigin = true;
	}
	
	//返回值表明压栈是否成功
	public boolean push(Object value){
		if(value == null){
			return false;
		}
		//栈溢出的时候会返回异常
		try{
			if(!inOrigin){
				while(cacheStack.size() > 0){
					valueStack.push(cacheStack.pop());
				}
				inOrigin = true;
			}
			valueStack.push(value);
		}catch(Exception e){
			return false;
		}
		return true;
	}
	
	//假定存储的元素不会是null
	public Object pop(){
		if(inOrigin){
			while(valueStack.size() > 0){
				cacheStack.push(valueStack.pop());
			}
			inOrigin = false;
		}
		if(cacheStack.size() <= 0){
			return null;
		}

		Object reval = cacheStack.pop();
		
		return reval;
	}

}

#提示2:栈有没有必要还原
重新思考数据的表示,这里假设存在两个栈(baseStack和reverseStack),数据存储在baseStack中,在时间点A,如果需要弹出元素,那么reverseStack会按照逆序存储这个时间点A时baseStack中所剩下的元素,之后添加的所有元素都是在reverseStack中元素之后的,在reverseStack元素没有弹完之前,后续添加的元素不需要压入到reverseStack,也就是后续添加的元素可以直接堆积在baseStack中,而我们之前还原栈的操作,只是保证在弹出栈的时候,reverseStack中按照顺序存储了所有数据。由此我们得到了想法3,我们声明两个栈(baseStack和reverseStack),在弹出时,如果reverseStack没有元素,那么就将baseStack的元素以此放入到reverseStack中,然后弹出尾部,在压入时,数据直接压入到baseStack中。

//使用语言java
import java.util.*;

//这里假定访问方式是单线程,如果多线程访问  需要对stack进行保护
public class Solution{

	Stack<Object> valueStack;
	Stack<Object> cacheStack;

	public Solution(){
		//这部分声明不确定,java中可能是这么调用的
		valueStack = new ArrayList<>();
		cacheStack = new ArrayList<>();
	}
	
	//返回值表明压栈是否成功
	public boolean push(Object value){
		if(value == null){
			return false;
		}
		//栈溢出的时候会返回异常
		try{
			valueStack.push(value);
		}catch(Exception e){
			return false;
		}
		return true;
	}
	
	//假定存储的元素不会是null
	public Object pop(){
		if(cacheStack.size() <= 0){
			while(valueStack.size() > 0){
				cacheStack.push(valueStack.pop());
			}
			if(cacheStack.size() <= 0){
				return null;
			}
		}

		Object reval = cacheStack.pop();
		
		return reval;
	}
}

#总结
在操作数据的时候需要进行仔细分析,尽可能避免无意义的操作。

猜你喜欢

转载自blog.csdn.net/u010953266/article/details/83654026