您的位置:首页 > 编程语言 > C语言/C++

我的C++实践(1):Stack的实现

2016-07-29 00:00 441 查看
(1)基本的Stack:以std::deque为内部容器。方法有入栈、出栈、返回栈顶元、判断栈空。

//stack1.h:栈的基本实现
#ifndef __STACK1_H__
#define __STACK1_H__
#include <deque>
#include <stdexcept>
template<typename T>
class Stack{
private:
std::deque<T> elems; //包含元素的容器
public:
void push(T const&); //压入元素
void pop(); //弹出元素
T top() const;  //返回栈顶元素
bool empty() const{  //判断栈是否为空
return elems.empty();
}
};
template<typename T>
void Stack<T>::push(T const& elem){
elems.push_back(elem); //把元素的拷贝添加到末端
}
template<typename T>
void Stack<T>::pop(){
if(elems.empty()){
throw std::out_of_range("Stack<T>::pop(): empty stack");
}
elems.pop_back(); //删除末端元素
}
template<typename T>
T Stack<T>::top() const{
if(elems.empty()){
throw std::out_of_range("Stack<T>::top(): empty stakc");
}
return elems.back(); //返回末端元素的拷贝
}
#endif


测试程序:

//stack1test.cpp:测试Stack
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack1.h"
int main(){
try{
Stack<int> intStack; //元素类型为int的栈
Stack<std::string> stringStack; //元素类型为string的栈
intStack.push(7);
std::cout<<intStack.top()<<std::endl;
stringStack.push("hello");
std::cout<<stringStack.top()<<std::endl;
stringStack.pop();
stringStack.pop(); //会抛出std::out_of_range异常
}catch(std::exception const& ex){ //捕捉到这个异常并打印出来
std::cerr<<"Exception: "<<ex.what()<<std::endl;
return EXIT_FAILURE;
}
}


(2)改进1:指定栈的容量,要用到非类型模板参数。由于栈的容量固定,可以用数组来存放元素。

//stack2.h:容量受限的栈
#ifndef __STACK2_H__
#define __STACK2_H__
#include <stdexcept>
template<typename T,int size>
class Stack{
T elems[size]; //由于容量受限,可用换成用数组来管理元素
int numElems;  //元素的当前总个数
public:
Stack();  //构造函数
void push(T const&); //压入元素
void pop();  //弹出元素
T top() const; //返回栈顶元素
bool empty() const{ //判断栈是否为空
return numElems==0;
}
bool full() const{  //判断栈是否已满
return numElems==size;
}
};
template<typename T,int size>
Stack<T,size>::Stack():numElems(0){ //初始时不含元素
//不做任何事
}
template<typename T,int size>
void Stack<T,size>::push(T const& elem){
if(numElems==size)
throw std::out_of_range("Stack<T,size>::push(): stack is full");
elems[numElems]=elem; //附加元素
++numElems; //增加元素个数
}
template<typename T,int size>
void Stack<T,size>::pop(){
if(numElems<=0)
throw std::out_of_range("Stack<T,size>::pop(): empty stack");
--numElems; //减少元素个数
}
template<typename T,int size>
T Stack<T,size>::top() const{
if(numElems<=0)
throw std::out_of_range("Stack<>::top(): empty stack");
return elems[numElems-1]; //返回末端元素
}
#endif


测试程序:

//stack2test.cpp:测试容量受限的Stack
#include <iostream>
#include <string>
#include <cstdlib>
#include "stack2.h"
int main(){
try{
Stack<int,20> int20Stack; //可存储20个int元素的栈
Stack<int,40> int40Stack;
Stack<std::string,40> stringStack;
int20Stack.push(7);
std::cout<<int20Stack.top()<<std::endl;
int20Stack.pop();
stringStack.push("hello");
std::cout<<stringStack.top()<<std::endl;
stringStack.pop();
stringStack.pop();
}catch(std::exception const& ex){
std::cerr<<"Exception: "<<ex.what()<<std::endl;
return EXIT_FAILURE;
}
return 0;
}


(3)改进2:可以指定栈内部使用的容器,还可以使 不同类型的栈之间能赋值。要用到模板模板参数。要定义一个赋值运算符的成员模板,它并不会覆盖缺省赋值运行符,对于相同类型栈之间的赋值,仍然会调用缺省的赋值运行符。由于容器有两个模板参数,一个是元素类型,一个是分配器类型,因此定义Stack的内部容器这个模板模板参数时,必须两个模板参数都要有。若只定义一个元素类型的参数,你传入容器(如vector,deque)时,并不能匹配。总之我们定义的模板模板参数必须与我们传入的模板精确匹配。

//stack3.hpp:可以指定内部容器,并且不同类型的栈之间可以赋值的栈
#ifndef STACK_HPP
#define STACk_HPP
#include <deque>
#include <stdexcept>
#include <memory>
template<typename T,template<typename ELEM,typename ALLOC=std::allocator<ELEM> >
class CONT=std::deque>
class Stack{
CONT<T> elems; //存放元素的窗口
public:
void push(T const&); //压入元素
void pop(); //弹出元素
T top() const; //返回栈顶元素
bool empty() const{ //判断栈是否为空
return elems.empty();
}
/* 这个赋值运算符是一个独立的成员模板,它可以把Stack<T2,CONT2<ELEM2> >类型的栈赋值Stack<T,CONT<ELEM> >型的栈,
只要ELEM2型可以隐式转换成ELEM型。它并没有覆盖缺省赋值运行符,对于相同类型栈之间的赋值,仍然会调用缺省的赋值运行符
*/
template<typename T2,template<typename ELEM2,typename ALLOC=std::allocator<ELEM2> >
class CONT2>
Stack<T,CONT>& operator=(Stack<T2,CONT2> const&);
};
/* 由于并不需要用到参数ELEM和ALLOC,故可以省略 */
template<typename T,template<typename,typename> class CONT>
void Stack<T,CONT>::push(T const& elem){
elems.push_back(elem); //把元素的拷贝添加到末端
}
template<typename T,template<typename,typename> class CONT>
void Stack<T,CONT>::pop(){
if(elems.empty())
throw std::out_of_range("Stack<>::pop(): empty stack");
elems.pop_back(); //删除末端元素
}
template<typename T,template<typename,typename> class CONT>
T Stack<T,CONT>::top() const{
if(elems.empty())
throw std::out_of_range("Stack<>::top(): empty stack");
return elems.back(); //返回末端元素的拷贝
}
template<typename T,template<typename,typename> class CONT>
template<typename T2,template<typename,typename> class CONT2>
Stack<T,CONT>& Stack<T,CONT>::operator=(Stack<T2,CONT2> const& rhs){
if((void*)this==(void*)&rhs) //如果是自我赋值
return *this;
Stack<T2,CONT2> tmp(rhs);
elems.clear();  //删除所有现存的元素
while(!tmp.empty()){
//把rhs栈中元素拷贝到本栈中,并且元素的顺序不变
elems.push_front(tmp.top());
tmp.pop();
}
return *this;
}
#endif


测试程序:

//stack3test.cpp:测试改进型栈的功能
#include <iostream>
#include <string>
#include <cstdlib>
#include <vector>
#include "stack3.hpp"
int main(){
try{
Stack<int> intStack;  //int栈
Stack<float> floatStack; //float栈

intStack.push(42);
intStack.push(7);
floatStack.push(7.7);
floatStack=intStack; //不同类型的栈之间的赋值
std::cout<<floatStack.top()<<std::endl;
floatStack.pop();
std::cout<<floatStack.top()<<std::endl;
floatStack.pop();
std::cout<<floatStack.top()<<std::endl;
floatStack.pop();
}catch(std::exception const& ex){
std::cerr<<"Exception: "<<ex.what()<<std::endl;
}
Stack<int,std::vector> vStack; //使用vector作为内部容器的int栈
vStack.push(42);
vStack.push(7);
std::cout<<vStack.top()<<std::endl;
vStack.pop();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: