劍指offer - 兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)棧

題目

兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)棧

思路1

兩個(gè)隊(duì)列queue1, queue2。不管是插入還是彈出纳本,保證總有一個(gè)隊(duì)列為空窍蓝。

  • 入棧操作:總是往有數(shù)據(jù)的列隊(duì)插入,默認(rèn)兩個(gè)列隊(duì)空繁成,插入queue1
  • 出棧操作:從非空列隊(duì)中刪除數(shù)據(jù)并插入空列隊(duì)吓笙,一直到非空列隊(duì)剩下一個(gè)元素,該元素就是出棧的元素

分析:

1.png

如圖所示巾腕,先往棧內(nèi)壓入一個(gè)元素a面睛。由于兩個(gè)隊(duì)列現(xiàn)在都是空的,可以選擇把a插入兩個(gè)隊(duì)列的任意一個(gè)祠墅。

不妨把a插入queue1侮穿。接下來繼續(xù)往棧內(nèi)壓入b、c兩個(gè)元素毁嗦,把它們也都插入queue1亲茅。這個(gè)時(shí)候queue1包含3個(gè)元素a、b狗准、c克锣,其中a位于隊(duì)列的頭部、c位于隊(duì)列的尾部

現(xiàn)在考慮從棧內(nèi)彈出一個(gè)元素腔长,根據(jù)棧的后入先出原則袭祟,最后被壓入棧的c應(yīng)該先彈出。由于c位于queue1的尾部捞附,而每次只能從隊(duì)列的頭部刪除元素巾乳,因此可以先從queue1中因此刪除a您没、b并插入queue2,再從queue1中刪除c胆绊。這就相當(dāng)于從棧中彈出元素c了氨鹏。可以使用同樣的方法從棧內(nèi)彈出元素b压状。

接下來再考慮往棧內(nèi)壓入一個(gè)元素d仆抵。此時(shí)queue1已經(jīng)有一個(gè)元素,就把d插入queue1的尾部种冬,如果再從棧內(nèi)彈出一個(gè)元素镣丑,同樣先從頭刪除queue1的元素并插入queue2,直到queue1遇到d再直接把它刪除

算法實(shí)現(xiàn)

  • 定義棧
template<typename T>
class QueueStack
{
public:
    void push(const T& data);
    T pop();
    int size();
    QueueStack()
    {
        count = 0;
    }

private:
    queue<T> q1;
    queue<T> q2;
    int count;
};
  • Push操作
// 進(jìn)棧
template<typename T>
void QueueStack<T>::push(const T& data)
{
    if (q1.size()==0 && q2.size() ==0) // 默認(rèn)情況下都為空娱两,插入q1
    {
        q1.push(data);
    }
    else if (q1.size()>0) // q1非空插入q1
    {
        q1.push(data);
    }
    else if(q2.size()>0) // q2非空插入q2
    {
        q2.push(data);
    }
    ++count; // 元素加1
}
  • Pop操作
// 出棧
template<typename T>
T QueueStack<T>::pop()
{
    if (q1.size()==0 && q2.size() ==0) // 列隊(duì)為空莺匠,拋出異常
    {
        logic_error ex("stack is empty");
        throw exception(ex);
    }

    T element;
    if (q2.size() == 0) // q2為空
    {
        while(q1.size() != 1) // 遍歷q1,將元素添加到q2谷婆,只留一個(gè)元素
        {
            q2.push(q1.front());
            q1.pop();
        }
        element = q1.front(); // 即最后一個(gè)入列隊(duì)的元素出棧
        q1.pop(); // 刪除元素
    }
    else
    {
        while(q2.size() != 1) // q2不為空慨蛙,并且個(gè)數(shù)不止一個(gè)
        {
            q1.push(q2.front());
            q2.pop();
        }
        element = q2.front();
        q2.pop();
    }
    --count; // 元素減1
    return element;
}
  • 棧大小
template<typename T>
int QueueStack<T>::size()
{
    return count;
}

簡(jiǎn)單使用

void test() {
    QueueStack<string> stack;
    stack.push("a");
    stack.push("b");
    stack.push("c");

    cout<<"current size: "<<stack.size()<<endl; // 3
    cout<<stack.pop()<<endl; // c
    cout<<"current size: "<<stack.size()<<endl; // 2
    cout<<stack.pop()<<endl; // b
    stack.push("d");
    cout<<"current size: "<<stack.size()<<endl; // 2
    cout<<stack.pop()<<endl; // d
}

思路2

兩個(gè)隊(duì)列queue1, queue2辽聊。不管是插入還是彈出纪挎,保證總有一個(gè)隊(duì)列為空。

  • 隊(duì)列入棧:將元素插入空隊(duì)列跟匆,同時(shí)將非空隊(duì)列的元素依次插入到空隊(duì)列异袄。此時(shí)之前的非空隊(duì)列變?yōu)榭贞?duì)列,空隊(duì)列變?yōu)榉强贞?duì)列玛臂。

  • 隊(duì)列出棧:將非空隊(duì)列的隊(duì)首彈出即可烤蜕。

分析:

執(zhí)行下述操作:先將1、2迹冤、3入棧讽营,接著3出棧,然后4入棧泡徙。兩個(gè)隊(duì)列元素的變化情況如下:

1橱鹏、 初始情況下:queue1 , queue2都為空,先將1壓入queue1堪藐。此時(shí)queue1為非空莉兰,queue2為空。
2礁竞、元素2入棧 糖荒,因?yàn)?code>queue2為空所以壓入。之前queue1非空模捂,將1彈出壓入queue2捶朵。此時(shí)queue1為空 queue2為2 蜘矢、1。
3综看、元素3入棧 硼端,queue1為空所以壓入。之前queue2非空寓搬,將2珍昨、1依次彈出壓入queue1。此時(shí)queue2為空 句喷,queue1為3镣典、2、1唾琼。
4兄春、元素3出棧 queue1非空 3出棧。queue1為2 1 queue2為空锡溯。
5赶舆、元素4入棧 queue2為空所以壓入。之前queue1非空祭饭,將2芜茵、1依次彈出壓入queue2。此時(shí)queue1為空 queue2為4倡蝙、2九串、1。

說白了就是將插入的數(shù)據(jù)直接排好序寺鸥,后插入的數(shù)據(jù)在列隊(duì)的頭部猪钮,先插入的數(shù)據(jù)在列隊(duì)尾部

算法實(shí)現(xiàn)

  • 定義棧
#include <iostream>
#include <queue>
#include <exception>

using namespace std;

class QueueStack {
public:
    void push(int x);
    void pop();
    int top();
    bool empty();
    unsigned long size();

private:
    queue<int> q1;
    queue<int> q2;
};
  • Push操作
// 保證每個(gè)時(shí)刻都有一個(gè)隊(duì)列為空隊(duì)列
void QueueStack:: push(int x) {
    if (q1.empty()) // 列隊(duì)1為空
    {
        q1.push(x); // 向列隊(duì)1插入元素
        while (!q2.empty()) // 隊(duì)列2不為空
        {
            q1.push(q2.front()); // 獲取隊(duì)列2的首元素添加到隊(duì)列1
            q2.pop(); // 去除隊(duì)列首元素
        }

    }
    else // 列隊(duì)1不為空
    {
        q2.push(x); // 將元素t入隊(duì)列2
        while (!q1.empty()) // 同理在隊(duì)列1不為空的情況下,將隊(duì)列1的元素添加到隊(duì)列2
        {
            q2.push(q1.front());
            q1.pop();
        }
    }
}
  • Pop操作
// 從棧頂去除元素
void QueueStack:: pop() {
    if (empty()) { // 為空拋出異常
        logic_error ex("stack is empty");
        throw exception(ex);
    }
    if (q1.empty()) {
        q2.pop();
    }
    else
    {
        q1.pop();
    }
}
  • Top操作
// 獲取頂部元素
int QueueStack:: top() {
    if (empty()) {
        logic_error ex("stack is empty");
        throw exception(ex);
    }
    if (q1.empty()) {
        return q2.front();
    }
    else
    {
        return q1.front();
    }
}
  • Empty胆建、棧數(shù)量操作
// 是否為空
bool QueueStack:: empty() {
    return q1.empty() && q2.empty();
}

// 個(gè)數(shù)
unsigned long QueueStack:: size() {
    return q1.size() + q2.size();
}

簡(jiǎn)單使用

void test() {
    QueueStack stack;
    stack.push(1);
    stack.push(2);
    stack.push(3);

    cout<<"current size: "<<stack.size()<<endl; // 3
    cout<<stack.top()<<endl; // 3
    stack.pop(); // 去除元素3
    cout<<"current size: "<<stack.size()<<endl; // 2
    cout<<stack.top()<<endl; // 2
    stack.pop(); // 去除元素2
    stack.pop(); // 去除元素1
    cout<<"is empty: "<<stack.empty()<<endl; // 1
}

參考

《劍指offer》
利用兩個(gè)隊(duì)列實(shí)現(xiàn)一個(gè)棧(C++版)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末烤低,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子笆载,更是在濱河造成了極大的恐慌扑馁,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宰译,死亡現(xiàn)場(chǎng)離奇詭異檐蚜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沿侈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門闯第,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缀拭,你說我怎么就攤上這事咳短√蠲保” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵咙好,是天一觀的道長(zhǎng)篡腌。 經(jīng)常有香客問我,道長(zhǎng)勾效,這世上最難降的妖魔是什么嘹悼? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮层宫,結(jié)果婚禮上杨伙,老公的妹妹穿的比我還像新娘。我一直安慰自己萌腿,他們只是感情好限匣,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著毁菱,像睡著了一般米死。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贮庞,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天峦筒,我揣著相機(jī)與錄音,去河邊找鬼贸伐。 笑死勘天,一個(gè)胖子當(dāng)著我的面吹牛怔揩,可吹牛的內(nèi)容都是我干的捉邢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼商膊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼伏伐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起晕拆,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赡鲜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體睬塌,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年昆庇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了末贾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡整吆,死狀恐怖拱撵,靈堂內(nèi)的尸體忽然破棺而出辉川,到底是詐尸還是另有隱情,我是刑警寧澤拴测,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布乓旗,位于F島的核電站,受9級(jí)特大地震影響集索,放射性物質(zhì)發(fā)生泄漏屿愚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一务荆、第九天 我趴在偏房一處隱蔽的房頂上張望渺鹦。 院中可真熱鬧,春花似錦蛹含、人聲如沸毅厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吸耿。三九已至,卻和暖如春酷窥,著一層夾襖步出監(jiān)牢的瞬間咽安,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國打工蓬推, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妆棒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓沸伏,卻偏偏與公主長(zhǎng)得像糕珊,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子毅糟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容