- 关于栈和队列的介绍,在上一篇文章里已经介绍过了,话不多说直接上题目了。
题目如下:
队列的声明如下:
template <typename T> class CQueue
{
public:
CQueue(void);
~CQueue(void);
private:
stack<T> stack1;
stack<T> stack2;
};
在上述队列的声明可以看出,一个队列包含了两个栈stack1和stack2, 因此本题的核心想法是利用两个栈的“后进先出”去实现队列的“先进先出”。
我们通过一个具体的例子来分析往该队列插入和删除元素的过程。
1、首先插入一个元素a, 先把它插入到stack1,此时stack1中有元素{a}, stack2 元素为空。再向stack1压入两个元素b,c ,此时stack1中包含的元素有{a, b, c},其中c位于栈顶,形如图a。
2、从stack1中删除第一个元素,根据栈的先进后出的原则,第一个删除的元素是c,然后把c元素压入stack2 中。根据这种操作,再对元素b和a进行操作。完成之后,stack1为空,stack2中的元素是{c, b ,a }。此时可以弹出 stack2中的栈顶元素a了。完成后形如图b。
3、继续删除队列头部元素,就可以删除stack2中的b元素。形如图c。
4、接下来插入一个元素d。我们还是把它压入stack1 中。下次删除队列的头部stack2不为空,直接弹出它的栈顶元素c。因此c确实比d先进入队列中。
总结上述步骤:
1)当stack2中不为空时,在stack2中的栈顶元素是最先进入队列的元素,可以弹出。
2)如果stack2为空时,我们把stack1中的元素逐个弹出并压入stack2.由于先进入队列的元素被压到stack1的底端,进过弹出并压入之后就处于stack2的顶端了。
- 编写代码思路和注意点:
1、关于语句:system(“pause”); 必须包含头文件#include < iostream>
2、由于本题是要求同两个栈模型实现队列的模型,本题使用的是C++里的类模板工具。队列里用到的成员函数:构造,析构,插入元素和删除元素函数。队列里用到的私有成员对象:两个栈对象。
3、因为上面定义了各个成员函数,需要对类模板的成员函数特例化。其中构造函数和析构函数可以声明默认即可。
4、插入元素和删除元素的特例化就是本题核心代码。–但是在构造代码前,需要回顾一下栈和队列的常用操作。
栈的操作:
s.empty() 如果栈为空返回true,否则返回false
s.size() 返回栈中元素的个数
s.pop() 删除栈顶元素但不返回其值
s.top() 返回栈顶的元素,但不删除该元素
s.push() 在栈顶压入新元素
队列的操作多一个:
q.front() 返回队首元素的值,但不删除该元素
5、插入元素:
声明插入操作:
template< typename T> void CQueue< T>::appendTail(const T& element)
- 1、 向第一个栈stack1直接push元素;
- 2、需要考虑两种情况: stack2中若无元素,stack1可以开始把弹出的元素插入stack2;若stack2中有元素,则可以直接进行队列的删除元素操作;
- 3、 若stack2中无元素,stack1弹出一个栈顶元素,记录这个值,并push进入stack2中,循环直至stack1数据全部弹出。代码中需要注意的是:
T& data = stack1.top(); //定义data,类型是T&。因为数据插入操作声明的数据类型就是地址。
6、删除队列元素,并返回头结点。
- 整套代码如下
#include "stdafx.h"
#include <iostream>
#include <stack>
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()<=0)
{
while(stack1.size())
{
T& data=stack1.top();//zhuyi
stack1.pop();
stack2.push(data);
}
}
if(stack2.size()<=0)
throw exception("queue is empty");
T head=stack2.top();
stack2.pop();
return head;
}
void Test(char actualhead,char expectedhead)
{
if(actualhead==expectedhead)
printf("test is passed");
else
printf("test is failed");
}
void Test1()
{
CQueue<char> queue;
queue.appendtail('a');
queue.appendtail('b');
queue.appendtail('c');
char queuehead=queue.deleteHead();
Test(queuehead,'a');
}
int main()
{
Test1();
system("pause");
return 0;
}
- 测试用例的设计
1、往空的队列里添加、删除元素
2、往非空的队列里添加、删除元素
3、直接删除元素,直至队列为空。
- 补充知识点:C++的类模板
C++模板函数
- 1 提供一种模板来减少代码重复。比如:对于同一样函数使用不同的数据类型,int, double, char等。
- 2 支持所有数据类型的函数模板
这里T,可以代表任何类型。用的时候声明即可。
template <class T>
inline T square(T x)
{
T result;
result = x * x;
return result;
};
int i,ii;
ii=square<int>(i)//左边是返回的类型,后边分别表示类型和形参。
注明:模板的关键字可以用class和typename.
- template< class T>
- template< typename T>
- 使用模板函数square< int>(value) or square(value).
- 模板函数的定义中,T代表数据类型。
- 模板的声明和定义必须在同一个 文件中。
- 宏定义也可以实现模板的功能:#define square(x) (x*x)
C++ 类模板
- 类模板定义:
template < typename T>class Tmp{ }; - 类模板特例化:
template< typename T> Tmp< T>::Tmp1(T 参数) { };
例如:
template <class T>
class Matrix2x2
{
public:
//函数的重载:函数名相同,参数列表不同
Matrix2x2(T m11, T m12, T m21, T m22); //constructor
Matrix2x2(T m[2][2]);
Matrix2x2();
int Add(Matrix2x2 x)
int Multiply(Matrix2x2 x)
void Print();
T m[2][2];
};
- 类模板特例化
例如:
template <class T>
Matrix2x2<T>::Matrix2x2(T _m11, T _m12, T _m21, T _m22)
// 类名<T>(域名作用)::函数名(T 参数列表)
{
m[0][0] = _m11;
m[0][1] = _m12;
m[1][0] = _m21;
m[1][1] = _m22;
}
template <class T>
Matrix2x2<T>::Matrix2x2(T _m)
{
m[0][0] = _m[0][0];
m[0][1] = _m[0][1];
m[1][0] = _m[1][0];
m[1][1] = _m[1][1];
}
template <class T>
Matrix2x2<T>::Matrix2x2()
{
m[0][0] = 0;
m[0][1] = 0;
m[1][0] = 0;
m[1][1] = 0;
}
template <class T>
Matrix2x2<T>::Add(Matrix2x2 _x)
{
Matrix2x2<T> sum;
sum.m[0][0] = m[0][0] + _x.m[0][0];
sum.m[0][1] = m[0][1] + _x.m[0][1];
sum.m[1][0] = m[1][0] + _x.m[1][0];
sum.m[1][1] = m[1][1] + _x.m[1][1];
return sum;
}
template <class T>
Matrix2x2<T>::Multiply(Matrix2x2 _x)
{
Matrix2x2<T> sum;
sum.m[0][0] = m[0][0] * _x.m[0][0] + m[0][1] * _x.m[1][0];
sum.m[0][1] = m[0][0] * _x.m[0][1] + m[0][1] * _x.m[1][1];
sum.m[1][0] = m[1][0] * _x.m[0][0] + m[1][1] * _x.m[1][0];
sum.m[1][1] = m[1][0] * _x.m[0][1] + m[1][1] * _x.m[1][1];
return sum;
}
template <class T>
Matrix2x2<T>::Print()
{
cout << "|" << m[0][0] << " " << m[0][1] << "|" << endl;
cout << "|" << m[1][0] << " " << m[1][1] << "|" << endl;
}
注意:只有类模板被申明后,可以特化成员函数。