两个栈实现队列操作
最近看了個面試的帖子講的是“怎么用兩個棧來實現(xiàn)隊列的操作”,好奇的我也想試下這道題目,咋一看這道題目挺簡單的呀,嗯,確實不難。先簡單講下我第一眼看到這個題目時想到的解法。講解法之前先給大家講下數(shù)據(jù)結(jié)構(gòu)中的棧和隊列吧,免得有的人不明白棧和隊列,那就沒辦法繼續(xù)看下去了。
棧(stack)(wiki)
我們經(jīng)常會在面試中聽到“?!边@個詞語,理解這個概念對于理解程序的運行至關(guān)重要。棧這個詞語在不同的語境中表達的含義是不同的。下面我將解釋下棧的三種含義(參考:《Stack的三種含義》)。
-
含義一:數(shù)據(jù)結(jié)構(gòu)
? 我們這里講的其實就是這種含義,stack是一種存儲數(shù)據(jù)的結(jié)構(gòu),特點是LIFO,即后進先出(last in First out)。
?
? 這種數(shù)據(jù)結(jié)構(gòu)其底層是用鏈表來現(xiàn)實的,最大特點是只能操作最上面的元素,所以先進棧的被壓在下面只能后出棧。
? 這種數(shù)據(jù)結(jié)構(gòu)通常又下面幾種方法來操作最上面的元素:
? push : 進棧
? pop : 出棧
? top : 獲取棧頂元素
? empty :判斷棧是否為空
-
含義二:代碼的運行方式
? stack的第二種含義是“調(diào)用?!?#xff0c;表示函數(shù)像積木一樣的堆放,以供層層調(diào)用,我們在函數(shù)中的遞歸就是用堆棧實現(xiàn)的,遞歸簡單點來說就是函數(shù)中調(diào)用該函數(shù)。
-
含義三:內(nèi)存區(qū)域
stack的第三種含義就是存儲數(shù)據(jù)的一種內(nèi)存區(qū)域。程序在運行時需要一定的空間來存儲數(shù)據(jù)。一般來說系統(tǒng)會劃分出兩種不同的內(nèi)存空間,一種是棧(stack),另一種是堆(heap)。
棧是由操作系統(tǒng)自動分配和釋放的,存放函數(shù)的參數(shù)值,局部變量值等。堆一般由程序員分配并釋放,若程序員不釋放,程序結(jié)束時可能由OS回收,分配方式類似于鏈表。我們經(jīng)常講的內(nèi)存泄漏其實就是指的就是堆。
介紹完了棧的定義,簡單說下棧和隊列的區(qū)別吧,棧的特點是先進的后出,隊列的特點是先進的先出。這道題目考查的重點還是對于棧和隊列特性的理解,其次再加上一些思考就好了。
看完這道題目我其實第一反應(yīng)就覺得這道題挺簡單的,新建兩個棧s1、s2,然后當(dāng)有入棧請求的時候先將s1棧中的數(shù)據(jù)依次出棧進入到s2的棧中,然后將新請求入棧的數(shù)據(jù)放入s1中,最后將s2棧中數(shù)據(jù)依次出棧進入到s1棧中。每次有出棧請求的時候?qū)1棧中的數(shù)據(jù)出棧就好了。這種解法應(yīng)該是比較常規(guī)的解法,也比較容易想到的。
但是仔細想下這種方法效率比較低,有頻繁的出棧和入棧操作,對于性能的影響比較大,那有沒有什么更好的方法能解決這個問題呢?其實我們可以在出棧的時候把棧底元素取出來,入棧的時候正常入棧。具體實現(xiàn)就是當(dāng)有入棧請求的時候?qū)?shù)據(jù)壓入棧s1,當(dāng)有出棧請求的時候?qū)1數(shù)據(jù)依次出棧壓入s2棧中,那么這時s2的棧頂元素就是s1的棧底元素,最后將s2的數(shù)據(jù)又依次壓入s1中。這么這樣的話就只有出棧的操作會有頻繁的棧操作,對于入棧來講沒有額外的棧操作。這種方法其實效率已經(jīng)非常高了。
其實還有一種效率更高的方法來解決這個問題,仔細想下這么問題,將上面的解法做個優(yōu)化,將s1棧中的數(shù)據(jù)依次壓入s2中后又依次壓入s1中,那為什么又要將s2中的數(shù)據(jù)重新壓回s1呢?其實這步操作可以避免,我們可以當(dāng)有入棧的操作時將數(shù)據(jù)壓入s1,當(dāng)有出棧操作時將s2中的數(shù)據(jù)出棧,若s2棧為空,則將s1中的數(shù)據(jù)全部依次壓入s2中,這樣的方法效率會比上面的方法更優(yōu)。
下面的代碼就是上面提到的最后一種方法的實現(xiàn):
using namespace std; std::stack<int>s1, s2; int main() {printf("Please input argument:1 push,2 pop\n");int operation, num;while(scanf("%d", &operation) != EOF){if(operation == 1){printf("please input queue push num:");scanf("%d", &num);s1.push(num);}else if(operation ==2){if(!s2.empty()){printf("Queue pop num: %d\n", s2.top());s2.pop();}else if(!s1.empty()){while(!s1.empty()){s2.push(s1.top());s1.pop();}printf("Queue pop num: %d\n", s2.top());s2.pop();}else{printf("queue empty\n");}}else{printf("Input invalid, please input repeat");}}return 0; } 復(fù)制代碼轉(zhuǎn)載于:https://juejin.im/post/5c83371ef265da2dac457fa5
總結(jié)
- 上一篇: 初识前端——个人总结
- 下一篇: Go数组反转练习