这里介绍两种实现栈的方式:“顺序栈”和“链式栈”,各有各的优缺点。
不管是“顺序栈”还是“链式栈”,我们可以先定义一个栈的ADT(抽象数据类型),如下面的“stack.h”
#ifndef STACK_H
#define STACK_H
const int maxSize=50;
template <class T>
class Stack{
public:
Stack(){};
virtual void Push(const T& x)=0;
virtual bool Pop(T& x)=0;
virtual bool getTop(T& x)const=0;
virtual bool isEmpty()const=0;
virtual bool isFull()const=0;
virtual int getSize() const=0;
};
#endif
关于模版类“template”的使用可以参考网上的教程,这里定义了栈的几个基本操作:构造栈,进栈,退栈,获取栈顶元素,判断栈空,判断栈满,获取栈的元素个数
1、“顺序栈”的实现
创建“seqstack.h”,并在里面实现顺序栈
/*
** 顺序栈的模板类及其成员函数的实现,创建“seqstack.h”
*/
#ifndef SEQSTACK_H
#define SEQSTACK_H
#include <assert.h>
#include <iostream>
#include "stack.h"
using namespace std;
const int stackIncreament=20;
template <class T>
class SeqStack :public Stack<T>{
public:
/*
** 建立一个空栈
*/
SeqStack(int sz=50);
/*
** 析构函数
*/
~SeqStack(){delete[]elements;}
/*
** 进栈
*/
void Push(const T& x);
/*
** 退栈
*/
bool Pop(T& x);
/*
** 获取栈顶元素
*/
bool getTop(T& x)const;
/*
** 判断栈是否为空
*/
bool isEmpty()const {return(top == -1)?true:false;}
/*
** 判断栈是否为满
*/
bool isFull()const {return(top == maxSize-1)?true:false;}
/*
** 获取栈的元素个数
*/
int getSize()const {return top+1;}
/*
** 清空栈
*/
void MakeEmpty(){top=-1;}
/*
** 输出栈中元素的重载操作<<
*/
friend ostream& operator << (ostream& os,SeqStack<T>& s);
private:
/*
** 存放栈中元素的栈数组
*/
T* elements;
/*
** 栈顶元素
*/
int top;
/*
** 栈最大可容纳的元素个数
*/
int maxSize;
/*
** 栈溢出的处理
*/
void overflowProcess();
};
//由于编译器的关系,模板类成员函数必须和申明在一个同一个“.h”文件里
template<class T>
SeqStack<T>::SeqStack(int sz/* =50 */):top(-1),maxSize(sz){
elements=new T[maxSize];
assert(elements!=NULL);
};
template<class T>
void SeqStack<T>::overflowProcess(){
T * newArray = new T[maxSize+stackIncreament];
if (newArray==NULL){cerr<<"add stack area failed!"<<endl;exit(1);}
for (int i=0;i<=top;i++)
{
newArray[i]=elements[i];
}
maxSize=maxSize+stackIncreament;
delete[]elements;
elements=newArray;
};
template<class T>
void SeqStack<T>::Push(const T& x){
if (isFull()==true)
{
overflowProcess();
}
elements[++top]=x;
};
template<class T>
bool SeqStack<T>::Pop(T& x)
{
if (isEmpty()==true)
{
return false;
}
x=elements[top--];
return true;
};
template<class T>
bool SeqStack<T>::getTop(T& x)const
{
if (isEmpty()==true)
{
return false;
}
x=elements[top];
return true;
};
template<class T>
ostream& operator<<(ostream& os,SeqStack<T>& s){
os<<"top=="<<s.top<<endl;
for (int i=0;i<=s.top;i++)
{
os<<i<<":"<<s.elements[i]<<endl;
}
return os;
};
#endif
2、“链式栈”的实现
首先先定义一个结点结构体“LinkedList.h”
/*
** 单链表结点的结构体定义
*/
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
template <class T>
struct LinkNode{
/*
** 数据域
*/
T data;
/*
** 链指针域
*/
LinkNode<T> *link;
/*
** 仅初始化指针成员的构造函数
*/
LinkNode(LinkNode<T> *ptr = NULL){link=ptr;}
/*
** 初始化数据和指针成员的构造函数
*/
LinkNode(const T& item,LinkNode<T> *ptr=NULL)
{
data=item;
link=ptr;
}
};
#endif
接着实现“链式栈”“LinkedStack.h”
/*
** 链式栈的模板类及其成员函数的实现
*/
#ifndef LINKEDSTACK_H
#define LINKEDSTACK_H
#include "LinkedList.h"
#include "stack.h"
#include "stdafx.h"
#include "seqstack.h"
#include <iostream>
template<class T>
class LinkedStack:public Stack<T>{
public:
/*
** 构造函数,置空栈
*/
LinkedStack():top(NULL){};
/*
** 析构函数
*/
~LinkedStack(){makeEmpty();};
/*
** 进栈
*/
void Push(const T& x);
/*
** 退栈
*/
bool Pop(T& x);
/*
** 读取栈顶元素
*/
bool getTop(T& x)const;
/*
** 判断是否栈为空
*/
bool isEmpty()const{return(top==NULL)?true:false;}
/*
** 链式表不需要判断是否栈满,但必须将虚函数实例化,这里默认返回为true
*/
bool isFull()const{return true;}
/*
** 求栈的元素个数
*/
int getSize()const;
/*
** 清空栈
*/
void makeEmpty();
/*
** 输出栈中元素的重载操作<<
*/
friend ostream& operator<<(ostream& os,SeqStack<T>& s);
private:
/*
** 栈顶指针,即链头指针
*/
LinkNode<T> *top;
};
template<class T>
void LinkedStack<T>::makeEmpty(){
LinkNode<T> *p;
while(top !=NULL)
{
p=top;
top=top->link;
delete p;
}
};
template<class T>
bool LinkedStack<T>::Pop(T& x)
{
if (isEmpty()==true)
{
return false;
}
LinkNode<T> *p=top;
top=top->link;
x=p->data;
delete p;
return true;
};
template<class T>
void LinkedStack<T>::Push(const T& x){
top=new LinkNode<T>(x,top);
assert(top !=NULL);
};
template<class T>
bool LinkedStack<T>::getTop(T& x)const{
if (isEmpty()==true)
{
return false;
}
x=top->data;
return true;
};
template<class T>
int LinkedStack<T>::getSize()const{
int k=0;
LinkNode<T> *p=top;
while (p !=NULL)
{
p=p->link;
k++;
}
/*
**一个成员函数声明为const,则这个成员函数不修改数据成员,这个书里面写错了
*/
/*while (top !=NULL)
{
top=top->link;
k++;
}*/
return k;
};
template<class T>
ostream& operator<<(ostream& os,LinkedStack<T>& s){
os<<"get stack size is"<<s.getSize()<<endl;
LinkNode<T> *p=s.top;
int i=0;
while(p!=NULL)
{
os<<++i<<":"<<p->data<<endl;
p=p->link;
}
return os;
};
#endif
3、Main函数调用
#include "stdafx.h"
#include "seqstack.h"
#include "stack.h"
#include "LinkedStack.h"
#include "LinkedList.h"
void _tmain(int argc, _TCHAR* argv[])
{
//申明一个int型的顺序栈
SeqStack<int>inArray(maxSize);
//申明一个int型的链式栈
LinkedStack<int>linkArray;
int seqtop,linktop;
for (int i=0;i<50;i++)
{
//进栈
inArray.Push(i);
linkArray.Push(i);
//获取栈顶元素,获取不会进行出栈操作,可以对比下面的Pop操作对比
inArray.getTop(seqtop);
linkArray.getTop(linktop);
//输出栈顶元素
cout<<seqtop<<" "<<linktop<<endl;
}
int size=inArray.getSize();
cout<<"the seqstack current size is "<<size<<endl;
size=linkArray.getSize();
cout<<"the linkstack current size is "<<size<<endl;
//清空栈
linkArray.makeEmpty();
size=linkArray.getSize();
cout<<"the linkstack current size is "<<size<<endl;
while(!inArray.isEmpty())
{
inArray.Pop(seqtop);
//输出出栈元素,验证栈是“LIFO(后进先出)”
cout<<seqtop<<endl;
cout<<"the stack current size is "<<inArray.getSize()<<endl;
}
//房子窗口退出
cin>>size;
}