(说明:本博客中的题目题目详细说明参考代码均摘自 “何海涛《剑指Offer:名企面试官精讲典型编程题》2012年”)

题目

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

template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void); void appendTail(const T& node);
T deleteHead();
};

进一步详细说明:

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

算法设计思想

  因为栈是后进先出的数据结构,当将数据依次压入第一个栈后,再依次从这个栈弹出,压入第二个栈,如果此时从第二个栈中获取数据,表现正好像一个 “先进先出” 的队列数据结构。

  具体来说,使用两个栈实现一个队列,可以考虑用第一个栈(stack1)存放输入的元素(队尾元素),从第二个栈(stack2)获取队头元素。当第一栈(stack1)为空时,将第二个栈(stack2)中的全部元素依次弹出,再依次压入第一个栈中。其过程如图 2.8 所示,

C++ 实现

#include <iostream>
#include <stack>
#include <exception> template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void); void appendTail(const T& node);
T deleteHead(); private:
std::stack<T> stack1;
std::stack<T> stack2;
}; // Declare queue empty exception when try to pop when the queue is empty.
class QEmptyException: public std::exception {
virtual const char* what() const throw()
{
return "Error: Queue is empty!";
}
} popException; // stack1 as input stack, stack2 as output stack
template <typename T>
void CQueue<T>::appendTail(const T& node)
{
stack1.push(node);
} template <class T>
T CQueue<T>::deleteHead()
{
// Check if there are elements in stack2
if (stack2.empty())
{
// Pop all the elements from stack1, then push them onto stack2
if (stack1.size() > )
{
while (!stack1.empty())
{
T elem = stack1.top();
stack1.pop();
stack2.push(elem);
}
}
else
throw popException;
} // Get the top element from stack2, then delete it from stack2
T elem = stack2.top();
stack2.pop(); return elem;
} template <typename T>
CQueue<T>::CQueue(void)
{
} template <typename T>
CQueue<T>::~CQueue(void)
{
} void unitest()
{
CQueue<int> que; std::cout << "Push 1, 2, 3 successively into CQueue." << std::endl;
que.appendTail();
que.appendTail();
que.appendTail();
std::cout << "Pop the head of the queue: " << que.deleteHead() << std::endl;
std::cout << "Pop the head of the queue: " << que.deleteHead() << std::endl;
std::cout << "Push 4, 5, 6 successively into CQueue." << std::endl;
que.appendTail();
que.appendTail();
que.appendTail();
// Pop the rest elements in the queue, until the queue empty exception happens
for (int i = ; i < ; ++i)
{
std::cout << "Pop the head of the queue: " << que.deleteHead() << std::endl;
} } int main()
{
unitest(); return ;
}

Python 实现

#!/usr/bin/python
# -*- coding: utf8 -*- class CQueue:
def __init__(self):
self.stack1 = []
self.stack2 = [] def append_tail(self, elem):
self.stack1.append(elem) def delete_head(self):
if not self.stack2:
if self.stack1:
while self.stack1:
elem = self.stack1.pop()
self.stack2.append(elem)
else:
raise Exception("Queue is empty.") elem = self.stack2.pop()
return elem def unitest():
# Create an instance of class CQueue
que = CQueue()
print "Push 1, 2, 3 successively into CQueue."
for i in range(1, 4):
que.append_tail(i)
print "Pop the head of the queue:", que.delete_head()
print "Pop the head of the queue:", que.delete_head()
print "Push 4, 5, 6 successively into CQueue."
for i in range(4, 7):
que.append_tail(i)
# Pop the rest elements in the queue
for i in range(4):
print "Pop the head of the queue:", que.delete_head() if __name__ == '__main__':
unitest()

参考代码

1. targetver.h

#pragma once

// The following macros define the minimum required platform.  The minimum required platform
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
// your application. The macros work by enabling all features available on platform versions up to and
// including the version specified. // Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif

2. stdafx.h

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
// #pragma once #include "targetver.h" #include <stdio.h>
#include <tchar.h> // TODO: reference additional headers your program requires here

3. stdafx.cpp

// stdafx.cpp : source file that includes just the standard includes
// QueueWithTwoStacks.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H
// and not in this file

4. Queue.h

#pragma once
#include <stack>
#include <exception> using namespace std; template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void); // 在队列末尾添加一个结点
void appendTail(const T& node); // 删除队列的头结点
T deleteHead(); private:
stack<T> stack1;
stack<T> stack2;
}; template <typename T> CQueue<T>::CQueue(void)
{
} template <typename T> CQueue<T>::~CQueue(void)
{
} template<typename T> void CQueue<T>::appendTail(const T& element)
{
stack1.push(element);
} template<typename T> T CQueue<T>::deleteHead()
{
if(stack2.size()<= )
{
while(stack1.size()>)
{
T& data = stack1.top();
stack1.pop();
stack2.push(data);
}
} if(stack2.size() == )
throw new exception("queue is empty"); T head = stack2.top();
stack2.pop(); return head;
}

5. Queue.cpp

#include "StdAfx.h"
#include "Queue.h"
#include <queue>

6. QueueWithTwoStacks.cpp

// QueueWithTwoStacks.cpp : Defines the entry point for the console application.
// // 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛 #include "stdafx.h"
#include "Queue.h" void Test(char actual, char expected)
{
if(actual == expected)
printf("Test passed.\n");
else
printf("Test failed.\n");
} int _tmain(int argc, _TCHAR* argv[])
{
CQueue<char> queue; queue.appendTail('a');
queue.appendTail('b');
queue.appendTail('c'); char head = queue.deleteHead();
Test(head, 'a'); head = queue.deleteHead();
Test(head, 'b'); queue.appendTail('d');
head = queue.deleteHead();
Test(head, 'c'); queue.appendTail('e');
head = queue.deleteHead();
Test(head, 'd'); head = queue.deleteHead();
Test(head, 'e'); return ;
}

7. 参考代码下载

项目 07_QueueWithTwoStacks 下载: 百度网盘

何海涛《剑指Offer:名企面试官精讲典型编程题》 所有参考代码下载:百度网盘

参考资料

[1]  何海涛. 剑指 Offer:名企面试官精讲典型编程题 [M]. 北京:电子工业出版社,2012. 58-62.

用两个栈实现队列(C++ 和 Python 实现)的更多相关文章

  1. 剑指Offer面试题:6.用两个栈实现队列

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

  2. 剑指OFFER之用两个栈实现队列(九度OJ1512)

    题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作.队列中的元素为int类型. 输入: 每个输入文件包含一个测试样例.对于每个测试样例,第一行输入一个n(1<=n<=100 ...

  3. 九度OJ 1512 用两个栈实现队列 【数据结构】

    题目地址:http://ac.jobdu.com/problem.php?pid=1512 题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 输入: 每 ...

  4. 两个栈实现队列+两个队列实现栈----java

                                               两个栈实现队列+两个队列实现栈----java 一.两个栈实现一个队列 思路:所有元素进stack1,然后所有出s ...

  5. Algorithm --> 两个栈实现队列和两个队列实现栈

    两个栈实现队列和两个队列实现栈 队列(queue)先进先出的线性表:栈(stack)先进后出的线性表. 两个栈实现队列 法一思路: s1是入栈的,s2是出栈的. 入队列:直接压入s1即可: 出队列:如 ...

  6. 二、 编写一个类,用两个栈实现队列,支持队列的基本操作(add,poll,peek)

    请指教交流! package com.it.hxs.c01; import java.util.Stack; /* 编写一个类,用两个栈实现队列,支持队列的基本操作(add,poll,peek) */ ...

  7. 两个队列实现栈&两个栈实现队列(JAVA)

    1,两个栈实现队列 题目描述 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 思路:栈的特点时先进后出,队列的特点是先进先出. 若此时有两个队列stack1,st ...

  8. 剑指offer【05】- 用两个栈实现队列(java)

    题目:用两个栈实现队列 考点:栈和队列 题目描述:用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 解题思路:每次psuh是时先将stack2清空放入stck1(保 ...

  9. C++版 - 剑指offer 面试题7:用两个栈实现队列 题解

    用两个栈实现队列 提交网址:  http://www.nowcoder.com/practice/54275ddae22f475981afa2244dd448c6?tpId=13&tqId=1 ...

  10. 《剑指offer》用两个栈实现队列

    本题来自<剑指offer> 用两个栈实现队列 题目: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 思路: 队列定义:先进先出 栈定义:先进后出 要 ...

随机推荐

  1. 正则基础之——NFA引擎匹配原理

    记录一下一篇很好的博文:https://blog.csdn.net/lxcnn/article/details/4304651

  2. linux curl post/put请求

    案列: -X: 请求方式 --header: 请求header -d: 请求的数据 最后跟上请求的地址 curl -X PUT --header 'Content-Type: application/ ...

  3. C# LINQ学习笔记

    LINQ,语言集成查询: LINQ TO SQL,同EF,NHibernate一样,也是一种ORM框架: 1. 入门应用示例: static public void LinqBasic() { var ...

  4. android webview 中 js 模板引擎的使用

    最近在项目中要求用 webview 展示几个界面, 而后台返回的不是 html 而是 json 数据. 起初用 StringBuilder 一个一个拼 html, 后来感觉太繁琐,拼一个还行,拼多了就 ...

  5. java.security.MessageDigest的使用之生成安全令牌!

    时候,我们需要产生一个数据,这个数据保存了用户的信息,但加密后仍然有可能被人使用,即便他人不确切的了解详细信息... 好比,我们在上网的时候,很多网页都会有一个信息,是否保存登录信息,以便下次可以直接 ...

  6. 基于URL权限拦截的实现

    一.实现原理 1.实现原理   本示例采用SpringMVC的拦截器来实现一个基于URL的权限拦截. 2.权限管理流程 二.数据库搭建 1.用户表(sys_user) (1)表结构 (2)表字段说明 ...

  7. jmeter(2)——元件简介、作用域及执行顺序

    上一篇主要介绍了一下 jmeter还有安装配置,这一篇来说一下它的目录组成和元件 1.目录组成 1>bin目录是可执行文件,双击jmeter.bat启动工具,也可以编辑这个批处理文件,设置jvm ...

  8. Azure 上 Linux 虚拟机 Mac 地址的持久化

    有些用户在使用 Azure Linux 虚拟机安装软件时,有些软件的 license 会和当前系统的 mac 地址绑定,那么在 Azure VM 重启,reszie(改变尺寸大小),停止然后再启动的时 ...

  9. 【转】.NET 4.5 使用async和await关键字调用异步方法

    async和await关键字是.NET 4.5新增加的异步编程方式,通过使用这两个关键字可以轻松便捷的编写异步方法.使用async关键字声明异步方法,使用await关键字等待和获取异步方法返回的结果. ...

  10. [android] 练习使用ListView(一)

    练习使用ListView,BaseAdapter,先展示文字的,再练习图片的 MainActivity.java package com.android.test; import android.ap ...