1. 程式人生 > >用兩個棧來實現一個佇列

用兩個棧來實現一個佇列

題目:用兩個棧實現一個佇列。佇列宣告如下,請實現它的兩個函式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;
}