用兩個棧來實現一個佇列
題目:用兩個棧實現一個佇列。佇列宣告如下,請實現它的兩個函式appendTail和deleteHead,分別完成在佇列尾部插入結點和在佇列頭部刪除結點的功能
宣告:
template <typename T>class CQueue
{
public:
CQueue(void);
~CQueue(void);
void appendTail(const T& node);
T deleteHead();
private:
stack<T> stack1;
stack<T> stack2;
};
從上面的宣告可以看出,一個佇列包含了兩個棧stack1和stack2,因此這道題的意圖是要求我們操作這兩個“先進後出”的棧實現一個“先進先出”的佇列CQueue。
我們通過一個例子來分析往該佇列插入和刪除元素的過程。首先插入一個元素a,不放先把它插入到stack1,此時stack1中的元素有{a},stack2位空,在壓入兩個元素b和c,還是插入到stack1中,此時stack1中有元素{a,b,c},其中c位於棧頂,而stack2仍然是空的。這時候我們試著從佇列中刪除一個元素。按照佇列先入先出的原則,由於a比b、c先插入到佇列中,最先被刪除的元素應該是a。元素a儲存在stack1中,但並不在棧頂,因此不能直接刪除。注意stack2我們還一直沒有用過,現在是讓stack2發揮作用的時候了。如果我們把stack1中的元素逐個彈出應壓入stack2,元素在stack2中的順序正好和原來在stack1中的順序相反。因此經過3次彈出stack1和壓入stack2操作之後,stack1位空,而stack2中的元素是{c,b,a},這個時候就可以彈出stack2的棧頂a了,此時stack1為空,而stack2的元素為{c,b},其中b在棧頂
如果我們還想繼續刪除佇列的頭部應該怎麼辦呢?剩下的兩個元素是b和c,b比c早進入佇列,因此b應該先刪除。而此時b恰好又在棧頂上,因此直接彈出stack2的棧頂即可。這次彈出操作之後,stack1中仍然為空,而stack2位{c}。
從上面分析中我們可以總結出刪除一個元素的步驟:當stack2中不為空時,在stack2中的棧頂元素是最先進入佇列的元素,可以彈出。如果stack2為空時,我們把stack1中的元素逐個彈出並壓入stack2.由於先進入佇列的元素被壓到stack1的底端,經過彈出和壓入之後就處於stack2的頂端了,又可以直接彈出。接下來在插入一個元素d。我們還是把它壓入stack1,這樣會不會有問題呢?我們考慮下一次刪除佇列的頭部stack2不為空,直接彈出它的棧頂元素c。而c的確是比d先進入佇列,應該在d之前從佇列中刪除,因此不會出現任何矛盾。
程式碼如下:
template <typename T>void CQueue::appendTail(const T& element)
{
stack1.push(element);
}
template <typename T>T CQueue::deleteHead()
{
if(stack2.size() <= 0)
{
while(stack1.size() > 0)
{
T& data = stack1.top();
stack1.pop();
stack2.push(data);
}
}
if(stack1.size() == 0)
{
throw new exception("queue is empty");
}
T head = stack2.top();
stack2.pop();
return head;
}