剑指offer算法题之栈和队列--面试题7:用两个栈实现队列(补充知识点:类模板)

16 篇文章 9 订阅
10 篇文章 1 订阅
  • 关于栈和队列的介绍,在上一篇文章里已经介绍过了,话不多说直接上题目了。
  • 题目如下:
    这里写图片描述

  • 队列的声明如下:

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;  
}  

注意:只有类模板被申明后,可以特化成员函数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值