zoukankan      html  css  js  c++  java
  • 【剑指offer】面试题七:用两个栈实现队列

    题目:用两个栈实现一个队列,队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。

    队列的声明如下:

    template<typename T> class Queue
    {
    public:
        Queue();
        ~Queue();
    
        void appendTail(const T&);
        T deleteHead();
        bool empty()const;
    
    private:  
        stack<T> stack1;
        stack<T> stack2;
    };

     性质:

    栈:在一端进行进栈弹栈操作,遵循后进先出原则;
    队列:在一端进行进队操作,而在另一端进行出队操作,遵循先进先出原则。

     从上述队列的声明中可以看出,一个队列包含了两个栈 stack1 和 stack2,因此要求我们操作这两个“先进后出”的栈实现一个“先进先出”的队列。

     我们通过一个例子来分析往该队列Queue插入和删除元素的过程,假设待办操作为 push a、push b、push c、pop(a)、push d、pop(b)。

    1、首先先插入一个元素 a,先将 a 插入到 stack1, 此时 stack1 中的元素有{a},stack2 为空。再压入两个元素 b 和 c,还是插入到 stack1 中,此时 stack1 中的元素有{a,b,c},其中 c 位于栈顶,而 stack2 仍然是空的。

    2、这时我们试着从队列 Queue 中删除一个元素。按照队列先进先出的规则。由于 a 比 b、c 先插入到队列中,最先被删除(pop)的元素应该是 a。但是元素 a 存储在 stack1 的底部,因此不能直接进行删除。注意到 stack2 还没有使用过,因此我们可以借助 stack2 实现删除(pop)操作。

    3、现在将 stack1 中的元素逐个弹出并压入 stack2,元素在 stack2 中的顺序恰好和原来在 stack1 中的顺序相反。因此经过 3 次弹出 stack1 和压入 stack2 操作之后,stack1 为空,而 stack2 中的元素为 {c,b,a},这个时候就可以弹出 stack2 的栈顶元素 a 了。

    4、如果还要继续删除队列的头部,因为 b 先于 c 进队列,而 stack2 中的元素为{b,c},b 位于栈顶,因此只要 stack2 非空,我们就可以一直做删除操作。

    5、如果此时要进行进队操作(push d),我们只需将 d 直接压入 stack1 即可。 

    总结上面的分析可以得出:

    1、删除元素时:
        当 stack2 中不为空时,在 stack2 中的栈顶元素是最先进入队列的元素,可以直接弹出。
        当 stack2 为空,stack1 不为空时,我们把 stack1 中的元素逐个弹出并压入 stack2 中,由于先进入队列的元素被压到 stack1 的底部,经过弹出和压入之后就处于 stack2 的顶端了,此时,也可以直接弹出
    
    2、增加元素时:
        直接压入 stack1 即可。

    具体代码如下:

    .hpp 文件

     1 // Queue.hpp
     2 #ifndef QUEUE_HPP
     3 #define QUEUE_HPP
     4 
     5 #include <stack>
     6 #include <stdexcept>
     7 
     8 template <typename T>
     9 class Queue
    10 {
    11 public:
    12     Queue()
    13     { }
    14     ~Queue()
    15     { }
    16 
    17     bool empty()const;
    18     void appendTail(const T &);
    19     T deleteHead();
    20 
    21 private:
    22     std::stack<T> st1;
    23     std::stack<T> st2;
    24 };
    25 
    26 template <typename T>
    27 bool Queue<T>::empty()const
    28 {
    29     return (st1.empty() && st2.empty());
    30 }
    31 
    32 template <typename T>
    33 void Queue<T>::appendTail(const T &value)
    34 {
    35     st1.push(value); // 压入st1中
    36 }
    37 
    38 template <typename T>
    39 T Queue<T>::deleteHead()
    40 {
    41     if(empty())
    42         throw std::out_of_range("out of range.");
    43 
    44     if(st2.empty()) // 如果st2为空,则需要先进行将st1中的元素逐个压入st2栈中
    45     {
    46         while(!st1.empty())
    47         {
    48             st2.push(st1.top());
    49             st1.pop();
    50         }
    51     }
    52 
    53     T val = st2.top();
    54     st2.pop();
    55 
    56     return val;
    57 }
    58 
    59 #endif/*QUEUE_HPP*/
    View Code

    测试文件 main.cpp

     1 // main.cpp
     2 #include "Queue.hpp"
     3 #include <iostream>
     4 #include "stdlib.h"
     5 
     6 using namespace std;
     7 
     8 int main(int argc, char const *argv[])
     9 {
    10     Queue<int> q;
    11 
    12     cout << "isEmpty: " << q.empty() << endl;
    13 
    14     int i = 0;
    15     cout << "push elements: ";
    16     while(i++ < 10)
    17     {
    18         int val = rand()%100;
    19         q.appendTail(val);
    20         cout << val << " ";
    21     }
    22     cout << endl;
    23 
    24     i = 0;
    25     while(i++ < 5)
    26     {
    27         int val = q.deleteHead();
    28         cout << val << " ";
    29     }
    30     cout << endl;
    31 
    32     return 0;
    33 }
    View Code

    本文完。

  • 相关阅读:
    Setting up a Reverse Proxy using IIS, URL Rewrite and ARR
    Compare xml files using C# LINQ
    ABAP术语-Authorization Object
    ABAP术语-Authorization Check
    ABAP术语-Authorization
    ABAP术语-Application Server
    ABAP术语-Application
    ABAP术语-APO (Advanced Planner and Optimizer)
    ABAP术语-ALE
    ABAP术语-Accounting Document
  • 原文地址:https://www.cnblogs.com/xfxu/p/4576841.html
Copyright © 2011-2022 走看看