標籤:資料結構 隊列 棧 面試題
廢話:要找工作了,面試方面得做些準備了,刷一刷題應該沒有壞處的,就從《劍指offer》開始吧。
第2.3.5節提到使用兩個棧實現隊列,相應的代碼也已給出。練習題裡有一道使用兩個隊列實現一個棧的題目,大體思路跟使用棧實現隊列差不多,書裡也給出了大致的思路。需要注意的一點是,如果每次入棧都選則將元素插入到第一個隊列中,出隊時先將前n-1個元素移交到第二個隊列中,然後返回隊列一中剩餘的唯一一個元素,再將隊列二中的元素又依次移交回隊列一中,這樣做未免效率過於低下。
事實上這樣的思路我們可以看作是一直選用隊列一作為棧元素的儲存容器,而使用隊列二作為一個出隊時的協助工具輔助,這樣每次出棧時來回複製元素容器元素的操作,效率確實低下。因為兩個隊列完全一樣的,所以我們完全有理由讓兩個隊列輪流作為棧元素的儲存容器,這樣每次出棧時,只需將所有前n-1個元素從一個隊列移交到另一個隊列中,然後返回最後一個元素作為出棧結果,這樣始終至少有一個隊列是空的,而每次進棧時,只需將進佔元素放在那個非空隊列的末尾(如果兩個隊列均為空白,則隨便放在那個裡面都行)。這樣減少了一半的複製操作。
如果上面說的不好理解,那還是看代碼吧
#include <iostream>#include <queue>#include <stdexcept>using namespace std;template <typename T>class CStack{public: CStack(void){}; ~CStack(void){}; void push(const T& node); const T& pop();private: queue<T> q1; queue<T> q2;};template <typename T>void CStack<T>::push(const T &node){ if(!q1.empty()) //隊列1在工作 q1.push(node); else //隊列2在工作 q2.push(node);}template <typename T>const T & CStack<T>::pop(){ if(!q1.empty()) //當前隊列1在工作,將要移交至隊列2 { while(q1.size()>1) { q2.push(q1.front()); q1.pop(); } T &temp=q1.front(); q1.pop(); return temp; } else if(!q2.empty()) //當前隊列2在工作,將要移交至隊列1 { while(q2.size()>1) { q1.push(q2.front()); q2.pop(); } T &temp=q2.front(); q2.pop(); return temp; } else //當前兩個隊列均為空白,即棧空。 throw out_of_range("stack is empty");}int main(){ CStack<int> stack; stack.push(1); stack.push(2); stack.push(3); try{ cout<<stack.pop()<<endl; stack.push(4); cout<<stack.pop()<<endl; cout<<stack.pop()<<endl; cout<<stack.pop()<<endl; cout<<stack.pop()<<endl; }catch(exception &e) { cout<<e.what()<<endl; } return 0;}
運行結果:
3
4
2
1
stack is empty
Process returned 0 (0x0) execution time : 0.002 s
Press ENTER to continue.