用两个栈实现队列

题目:某队列的声明如下:

 

 1 template<typename T> class CQueue
 2 {
 3 public:
 4       CQueue() {}
 5       ~CQueue() {}
 6 
 7       void appendTail(const T& node);  // append a element to tail
 8       void deleteHead();               // remove a element from head 
 9 
10 private:
11      T> m_stack1;
12      T> m_stack2;
13 };

 

分析:从上面的类的声明中,我们发现在队列中有两个栈。因此这道题实质上是要求我们用两个栈来实现一个队列。相信大家对栈和队列的基本性质都非常了解了:栈是一种后入先出的数据容器,因此对队列进行的插入和删除操作都是在栈顶上进行;队列是一种先入先出的数据容器,我们总是把新元素插入到队列的尾部,而从队列的头部删除元素。

我们通过一个具体的例子来分析往该队列插入和删除元素的过程。首先插入一个元素a,不妨把先它插入到m_stack1。这个时候m_stack1中的元素有{a}m_stack2为空。再插入两个元素bc,还是插入到m_stack1中,此时m_stack1中的元素有{a,b,c}m_stack2中仍然是空的。

这个时候我们试着从队列中删除一个元素。按照队列先入先出的规则,由于abc先插入到队列中,这次被删除的元素应该是a。元素a存储在m_stack1中,但并不在栈顶上,因此不能直接进行删除。注意到m_stack2我们还一直没有使用过,现在是让m_stack2起作用的时候了。如果我们把m_stack1中的元素逐个pop出来并push进入m_stack2,元素在m_stack2中的顺序正好和原来在m_stack1中的顺序相反。因此经过两次poppush之后,m_stack1为空,而m_stack2中的元素是{c,b,a}。这个时候就可以popm_stack2的栈顶a了。pop之后的m_stack1为空,而m_stack2的元素为{c,b},其中b在栈顶。

这个时候如果我们还想继续删除应该怎么办呢?在剩下的两个元素中bcbc先进入队列,因此b应该先删除。而此时b恰好又在栈顶上,因此可以直接pop出去。这次pop之后,m_stack1中仍然为空,而m_stack2{c}

从上面的分析我们可以总结出删除一个元素的步骤:当m_stack2中不为空时,在m_stack2中的栈顶元素是最先进入队列的元素,可以pop出去。如果m_stack2为空时,我们把m_stack1中的元素逐个pop出来并push进入m_stack2。由于先进入队列的元素被压到m_stack1的底端,经过poppush之后就处于m_stack2的顶端了,又可以直接pop出去。

接下来我们再插入一个元素d。我们是不是还可以把它pushm_stack1?这样会不会有问题呢?我们说不会有问题。因为在删除元素的时候,如果m_stack2中不为空,处于m_stack2中的栈顶元素是最先进入队列的,可以直接pop;如果m_stack2为空,我们把m_stack1中的元素pop出来并push进入m_stack2。由于m_stack2中元素的顺序和m_stack1相反,最先进入队列的元素还是处于m_stack2的栈顶,仍然可以直接pop。不会出现任何矛盾。

我们用一个表来总结一下前面的例子执行的步骤:

 

操作

m_stack1

m_stack2

append a

{a}

{}

append b

{a,b}

{}

append c

{a,b,c}

{}

delete head

{}

{b,c}

delete head

{}

{c}

append d

{d}

{c}

delete head

{d}

{}

 

总结完pushpop对应的过程之后,我们可以开始动手写代码了。参考代码如下:

 

 1 ///
 2 // Append a element at the tail of the queue
 3 ///
 4 template<typename T> void CQueue<T>::appendTail(const T& element)
 5 {
 6       // push the new element into m_stack1
 7       m_stack1.push(element);
 8 } 
 9 
10 ///
11 // Delete the head from the queue
12 ///
13 template<typename T> void CQueue<T>::deleteHead()
14 {
15       // if m_stack2 is empty, and there are some
16       // elements in m_stack1, push them in m_stack2
17       if(m_stack2.size() <= 0)
18       {
19             while(m_stack1.size() > 0)
20             {
21                   T& data = m_stack1.top();
22                   m_stack1.pop();
23                   m_stack2.push(data);
24             }
25       }
26 
27       // push the element into m_stack2
28       assert(m_stack2.size() > 0);
29       m_stack2.pop();
30 }

 

扩展:这道题是用两个栈实现一个队列。反过来能不能用两个队列实现一个栈?如果可以,该如何实现?

 

以上转自何海涛博客

 

题目:说明如何用两个队列来实现一个栈,并分析有关栈操作的运行时间。

 

解法:
1.有两个队列q1和q2,先往q1内插入a,b,c,这做的都是栈的push操作。
2.现在要做pop操作,即要得到c,这时可以将q1中的a,b两个元素全部dequeue并存入q2中,这时q2中元素为a,b,对q1再做一次dequeue操作即可得到c。
3.如果继续做push操作,比如插入d,f,则把d,f插入到q2中,
4.此时若要做pop操作,则做步骤2
5.以此类推,就实现了用两个队列来实现一个栈的目的。

 

注意在此过程中,新push进来的元素总是插入到非空队列中,空队列则用来保存pop操作之后的那些元素,那么此时空队列不为空了,原来的非空队列变为空了,总是这样循环。

 

对于push和pop操作,其时间为O(n).

 1 #include <iostream>
 2 #include <stack>
 3 #include <assert.h>
 4 using namespace std;
 5 
 6 // 两个队列实现一个栈
 7 template<typename T> class CStack
 8 {
 9 public:
10     CStack() {}
11     ~CStack() {}
12 
13     void mypush(const T& element);  
14 
15     void mypop();              
16 
17 
18 private:
19     deque <T> m_queue1;
20     deque <T> m_queue2;
21 };
22 
23 template<typename T> void CStack<T>::mypop()
24 {
25     if (m_queue1.size() == 0)
26     {
27         while (m_queue2.size() > 1)
28         {
29             T& data = m_queue2.front();
30             m_queue2.pop_front();
31             m_queue1.push_back(data);
32         }
33         assert(m_queue2.size() == 1); //确保队列2内有一个元素
34         T& result = m_queue2.front();
35         m_queue2.pop_front();
36         cout << result << endl;
37     }
38 
39     else if (m_queue2.size() == 0)
40     {
41         while (m_queue1.size() > 1)
42         {
43             T& data = m_queue1.front();
44             m_queue1.pop_front();
45             m_queue2.push_back(data);
46         }
47         assert(m_queue1.size() == 1); //确保队列1内有一个元素
48         T& result = m_queue1.front();
49         m_queue1.pop_front();
50         cout << result << endl;
51     }
52 }
53 
54 
55 template<typename T> void CStack<T>::mypush(const T& element)
56 {
57     if (m_queue1.size() > 0)
58     {
59         m_queue1.push_back(element);
60     }
61     else if (m_queue2.size() > 0)
62     {
63         m_queue2.push_back(element);
64     }
65     else
66     {
67         m_queue1.push_back(element);
68     }
69 }
70 int main()
71 {
72     CStack<int> myStack;
73     myStack.mypush(1);
74     myStack.mypush(2);
75     myStack.mypush(3);
76     myStack.mypop();
77     myStack.mypush(4);
78     myStack.mypop();
79 
80     cout << "Hello world!" << endl;
81     return 0;
82 }

 

转自http://hi.baidu.com/ozwarld/blog/item/ec9b52d4d48ce1dc50da4b0f.html

转载于:https://www.cnblogs.com/wolenski/archive/2012/07/11/2585763.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值