天天看點

劍指offer面試題7:用兩個棧實作隊列&用兩個隊列實作棧

用兩個棧實作一個隊列

1、要求:一個隊列包含兩個棧stack1和stack2,用這兩個“先進後出”的棧實作一個“先進先出”的隊列queue,主要實作appendTail和deleteHead函數。

2、思路:首先向stack1壓入元素a、b和c,則stack1中元素有{a,b,c},其中c位于棧頂,而stack2是空的。

這時,要從隊列中删除一個元素,按照隊列先入先出的規則,由于a比b、c先插入到隊列中,最先被删除的元素應該是a。元素a在stack1中,但并不在棧頂,是以不能直接删除。如果把stack1中的元素逐個彈出并壓入stack2,元素在stack2中的順序正好和原來在stack1中的順序相反。是以經過3次彈出stack1和壓入stack2操作結束之後,stack1為空,而stack2中的元素為{c,b,a},這個時候就可以彈出stack2的棧頂元素a了。

如果要繼續删除隊列的頭部,剩下的兩個元素b和c,b比c早進入隊列,是以b先删除,而此時b恰好在棧頂上,是以直接彈出stack2的棧頂即可。這次彈出操作之後,stack1中任然為空,而stack2為{c}。

接下來再插入一個元素d,還是把它壓入stack1,如果下一次要删除隊列頭部的元素,因為stack2不為空,可以直接彈出它的棧頂元素c,而串的确是比d先進入隊列,應該在d之前在隊列中删除,是以不會出現任何沖突。

具體的插入和删除操作如圖所示:

劍指offer面試題7:用兩個棧實作隊列&用兩個隊列實作棧

小結:隊列中插入元素隻插入到stack1的棧頂,删除元素隻從stack2的棧頂删除,當stack2中不為空時,在stack2中的棧頂元素是最先進入隊列的元素,可以彈出。如果stack2為空時,先把stack1中元素逐個壓入stack2.由于先進入隊列的元素被壓入到stack1的低端,經過彈出和壓入之後就處于stack2的頂端了,則可以直接彈出。

代碼實作:

//尾插
void appendTail(stack<int> *stack1,int data)
{
    stack1->push(data);
}
//頭删
void deleteHead(stack<int> *stack1,stack<int> *stack2,int *val)
{
    if (stack2->size()<=)
    {
        while (s1->size()>)
        {
            int data = stack1->top();
            stack1->pop();
            stack2->push(data);
        }
    }
    if (stack2->size()==)
    {
        printf("queue is empty\n");
        return;
    }
    *val = stack2->top();
    stack2->pop();
}
           

用兩個隊列實作一個棧

1、要求:一個棧包含兩個隊列queue1和queue2,用這兩個“先進先出”的隊列實作一個“先進後出”的棧stack,主要實作Top、Push和Pop三個函數。

2、思路:先往一個棧内壓入一個元素a。由于兩個隊列現在都是空的,可以把a插入兩個隊列中的任意一個。不妨插入queue1.接下來繼續往棧内壓入b、c兩個元素,把它們都插入queue1。這時,queue1包含3個元素a、b和c,其中a位于隊列的頭部,c位于隊列的尾部。

然後從棧内彈出一個元素。根據棧的先入後出原則,最後被壓入棧的c應該最先被彈出。由于c位于queue1的尾部,而每次隻能從隊列的頭部删除元素,是以可以先從queue1中依次删除元素a、b并插入到queue2中,再從queue1中删除元素c。這就相當于從棧中彈出元素c了。可以用同樣的方法從棧内彈出元素b。

接下來再往棧内壓入一個元素d。此時queue1已經有一個元素a,就把d插入queue1的尾部。如果再從棧内彈出一個元素,此時被彈出的應該是最後被壓入的d。由于d位于queue1的尾部,隻能先從頭部删除queue1的元素a并壓入到隊列queue2中,直到queue1中遇到d再直接把它删除。

具體的插入和删除算法如圖所示:

劍指offer面試題7:用兩個棧實作隊列&amp;用兩個隊列實作棧

小結:往棧頂插入元素時,如果有一個隊列中有元素,則插入該隊列的尾部,如果沒有,可以任選一個插入;從棧頂删除元素時,如果有一個隊列中元素不為空,則依次先将隊頭元素删除并插入另一個隊列中,直到該隊列中留下最後一個元素,則擷取該元素的值,并将它出隊。

代碼實作:

//壓棧
void Push(queue<int> *queue1,queue<int> *queue2,int data)
{
    if(queue1->size() ==  && queue2->size() != )
    {
        queue<int> *temp = queue1;
        queue1 = queue2;
        queue2 = temp;
    }
    queue1->push(data);
}
//出棧
void Pop(queue<int> *queue1,queue<int> *queue2,int *val)
{
    if (queue1->size()+queue2->size()==)
    {
        printf("stack is empty\n");
        return;
    }
    else if(queue1->size()==)
    {
        queue<int> *temp = q1;
        q1 = q2;
        q2 = temp;
    }
    //将先進去的元素順序壓入另一個隊列,并出隊,最後隻剩下一個元素,然後出隊
    while (queue1->size()>)
    {
        int temp = queue1->front();//擷取隊首元素
        queue2->push(temp);
        queue1->pop();
    }
    *val = queue1->front();
    queue1->pop();
}
//擷取棧頂元素
void Top(queue<int> queue1,queue<int> queue2,int *val)
{
    if (queue1.size()+queue2.size()==)
    {
        printf("stack is empty\n");
        return;
    }
    else if(q1.size()==)
    {
        *val = q1.back();//擷取隊列的隊尾元素
    }
    else
    {
        *val = q2.back();//擷取隊列的隊尾元素
    }
}
           

測試代碼:

#include <stdio.h>
#include <stack>
#include <queue>
using namespace std;

int main()
{
    //兩個棧實作一個隊列
    stack<int> s1,s2;
    int i;
    for (i=;i<;++i)
    {
        appendTail(&s1,i+);
    }
    appendTail(&s1,);
    printf("queue--------size:%d\n",s1.size()+s2.size());
    int data;
    deleteHead(&s1,&s2,&data);
    printf("delete_data-------%d\n",data);
    printf("queue--------size:%d\n",s1.size()+s2.size());

    //兩個隊列實作一個棧
    queue<int> q1,q2;
    for (i=;i<;++i)
    {
        Push(&q1,*i+);
    }
    int val;
    Pop(&q1,&q2,&val);
    Pop(&q1,&q2,&val);
//  Pop(&q1,&q2,&val);
    Top(q1,q2,&val);
    printf("length:%d\n",q1.size()+q2.size());
    printf("val:%d\n",val);
}
           

繼續閱讀