棧和隊列
-
棧:棧是一個非常常見的數據結構,特點是先機後出,即最先壓入(push)棧的元素會第一個被彈出(pop)。在計算機中被廣泛使用。例如,操作系統會給每個線程創建一個棧用來存儲函數調用時各個函數的參數。
通常棧是一個不考慮排序的數據結構,我們需要的時間才能找到棧中的元素,TODO:考慮一下是否要刪除,這塊不動就不要誤導
-
隊列:和棧一樣,隊列也是非常重要的數據結構。它的特徵是先進先出,即第一個入隊的元素將會第一個出來。
棧和隊列隊列雖然是特點爭鋒相對的兩類數據結構,但有意思的是它們卻相互聯繫,來看看面試題。
面試題 7:兩個棧實現一個隊列
題目
用兩個棧實現一個隊列。隊列申明如下,請實現它的兩個函數appendTail
和deleteHead
,分別完成在隊列尾部插入節點和在隊列頭部刪除節點的功能。
template<typename T>
class Queue {
public:
Queue(void);
~Queue(void);
void appendTail(const T &node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
分析
用兩個棧實現隊列的功能,粗一看不得其法,只能慢慢分析。
先模擬入隊,入隊時肯定需要一個數據結構來存放,姑且就選stack1吧。如果我們講1、2、3依次入隊,即在將1、2、3依次壓入stack1中。此時stack1中的出棧順序爲3、2、1,如果此時出隊,順序必然也是3、2、1和隊列先進先出的特性不符。
考慮到還有一個棧stack2未使用,而棧的特性是先入後出,剛好會將壓入順序反轉,負負得正,在出隊時,只要將stack1中的元素依次拷貝到stack2中。stack2的出棧順序將符合出隊順序。
該題重要的解題思路就是:棧的壓入順序和彈出順序相反。使用兩個棧,就可以讓壓入順序和彈出順序一致。
解:Java
import java.util.Stack;
public class Queue<T> {
private Stack<T> mStackAppend;
private Stack<T> mStackDelete;
public Queue() {
mStackAppend = new Stack<>();
mStackDelete = new Stack<>();
}
public void appendTail(T node) {
mStackAppend.push(node);
}
public T deleteHead() {
if (mStackDelete.empty()) {
while (!mStackAppend.empty()) {
mStackDelete.push(mStackAppend.pop());
}
}
if (mStackDelete.empty()) {
return null;
}
return mStackDelete.pop();
}
}
測試代碼:
public static void main(String args[]) {
Queue<Integer> queue = new Queue<>();
queue.appendTail(1);
queue.appendTail(2);
queue.appendTail(3);
System.out.println(queue.deleteHead());
System.out.println(queue.deleteHead());
System.out.println(queue.deleteHead());
}
解:C++
template<typename T>
class Queue {
public:
Queue(void){}
~Queue(void){}
void appendTail(const T &node) {
stack1.push(node);
}
T deleteHead() {
if (stack2.empty()) {
while (!stack1.empty()) {
T &data = stack1.top();
stack1.pop();
stack2.push(data);
}
}
if (stack2.empty()) {
throw std::exception();
}
T head = stack2.top();
stack2.pop();
return head;
}
private:
stack<T> stack1;
stack<T> stack2;
};
int main() {
Queue<int> queue;
queue.appendTail(1);
queue.appendTail(2);
queue.appendTail(3);
cout << queue.deleteHead()
<< queue.deleteHead()
<< queue.deleteHead() << endl;
return 0;
}