1. 程式人生 > >[面試題]堆來模擬棧

[面試題]堆來模擬棧

#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;
	}
}

#總結 在操作資料的時候需要進行仔細分析,儘可能避免無意義的操作。