二、栈
栈是一种“发育不良”的线性表,它具有与线性表相同的存储结构(基于数组的或基于链于的),但栈的“缺陷”---不能像线性表那样具有插入、删除操作---反而给了它独有的特色。在后面将会发现,递归,可以用栈来实现。
在时间复杂度上,基于数组的栈AStack和链式栈LStack,在push()、pop()操作上,都是一个时间常数1。在我的测试中,10万次push()和10万次pop()后,基于数组的栈只比链式栈快一秒。但要注意AStack需要预先指定栈元素的最大个数,而LStack是动态分配的,元素个数在理论上不受限。
经常思考,我发现昨天在线性表那篇文章中,有一个设计错误,就是不应该把结点类Node与List类放在一个文件中,这是违反模块化思想的。当我今天的栈中要用到结点时,应该可以很轻松的通过头文件的方式把结点类引到我的代码中。以下是一个最简单的结点类界面(事实上可以采用可用空间表freelist的方式来定义结点类):
/*
定义常用于链表中的各种结点界面
文件名:NodeInterface.h
*/
#ifndef NODEINTERFACE_H
#define NODEINTERFACE_H
template<class T> class Node //单端结点,只含有一个指针
{
public:
T element;
Node * next;
public:
Node(const T &eVal, Node * nVal = NULL)
{
element = eVal;
next = nVal;
}
Node(Node * nVal = NULL)
{
element = 0;
next = nVal;
}
};
#endif
定义常用于链表中的各种结点界面
文件名:NodeInterface.h
*/
#ifndef NODEINTERFACE_H
#define NODEINTERFACE_H
template<class T> class Node //单端结点,只含有一个指针
{
public:
T element;
Node * next;
public:
Node(const T &eVal, Node * nVal = NULL)
{
element = eVal;
next = nVal;
}
Node(Node * nVal = NULL)
{
element = 0;
next = nVal;
}
};
#endif
以下是栈的界面及两种实现的代码:
/*
文件名:StackInterface.h
*/
#ifndef STACKINTERFACE_H
#define STACKINTERFACE_H
#include "NodeInterface.h"
//定义栈的界面
template<class T> class Stack
{
public:
virtual bool push(const T&) = 0; //入栈
virtual bool pop(T&) = 0; //出栈
virtual bool topValue(T&) =0; //栈顶元素值
};
/////////////////////////////////////
//基于数组的栈Array_based Satck
/////////////////////////////////////
template<class T> class AStack :public Stack<T>
{
private:
int maxSize; //栈最多能容纳的元素个数
int top; //指示栈中元素的实际个数,由于数组从0开始,(top-1)才指示了栈顶元素的下标
T * listArray; //array holding stack elements
public:
AStack(int size = 100)
{
maxSize = size;
top = 0;
listArray = new T[maxSize];
}
~AStack()
{
delete [] listArray;
}
bool push(const T &);
bool pop(T &);
bool topValue(T &);
int length() const
{
return top;
}
};
template<class T> bool AStack<T>::push(const T & element)
{
if (top == maxSize) //stack is full.
{
return false;
}
listArray[top] = element;
++top;
return true;
}
template<class T> bool AStack<T>::pop(T & ref_elem)
{
if (top == 0) //no element in stack
{
return false;
}
ref_elem = listArray[--top];
return true;
}
template<class T> bool AStack<T>::topValue(T & ref_elem)
{
if (top == 0) //no element in stack
{
return false;
}
ref_elem = listArray[top-1];
return true;
}
///////////////////////////////////
//链式栈 Linked Stack
///////////////////////////////////
template<class T> class LStack :public Stack<T>
{
private:
int listSize; //the number of elements,and that is the number of nodes
Node<T> * top; //与AStack栈不同,这里,top指向栈顶元素
public:
LStack() //不必限定元素的最大值
{
listSize = 0;
top = NULL;
}
~LStack()
{
}
bool push(const T &);
bool pop(T &);
bool topValue(T &);
void clear();
int length() const
{
return listSize;
}
};
template<class T> bool LStack<T>::push(const T &element)
{
Node<T> *tmp = new Node<T>(element,top);
top = tmp;
++listSize;
return true;
}
template<class T> bool LStack<T>::pop(T &ref_elem)
{
if (top == NULL)
{
return false; //栈中没有元素
}
Node<T> *tmp = top;
top = top->next;
ref_elem = tmp->element;
delete tmp;
--listSize;
return true;
}
template<class T> bool LStack<T>::topValue(T & ref_elem)
{
if (top == NULL)
{
return false; //none element in stack
}
ref_elem = top->element;
return true;
}
template<class T> void LStack<T>::clear()
{
Node<T> * tmp;
while (top != NULL)
{
tmp = top;
top = top->next;
delete tmp;
}
}
#endif
文件名:StackInterface.h
*/
#ifndef STACKINTERFACE_H
#define STACKINTERFACE_H
#include "NodeInterface.h"
//定义栈的界面
template<class T> class Stack
{
public:
virtual bool push(const T&) = 0; //入栈
virtual bool pop(T&) = 0; //出栈
virtual bool topValue(T&) =0; //栈顶元素值
};
/////////////////////////////////////
//基于数组的栈Array_based Satck
/////////////////////////////////////
template<class T> class AStack :public Stack<T>
{
private:
int maxSize; //栈最多能容纳的元素个数
int top; //指示栈中元素的实际个数,由于数组从0开始,(top-1)才指示了栈顶元素的下标
T * listArray; //array holding stack elements
public:
AStack(int size = 100)
{
maxSize = size;
top = 0;
listArray = new T[maxSize];
}
~AStack()
{
delete [] listArray;
}
bool push(const T &);
bool pop(T &);
bool topValue(T &);
int length() const
{
return top;
}
};
template<class T> bool AStack<T>::push(const T & element)
{
if (top == maxSize) //stack is full.
{
return false;
}
listArray[top] = element;
++top;
return true;
}
template<class T> bool AStack<T>::pop(T & ref_elem)
{
if (top == 0) //no element in stack
{
return false;
}
ref_elem = listArray[--top];
return true;
}
template<class T> bool AStack<T>::topValue(T & ref_elem)
{
if (top == 0) //no element in stack
{
return false;
}
ref_elem = listArray[top-1];
return true;
}
///////////////////////////////////
//链式栈 Linked Stack
///////////////////////////////////
template<class T> class LStack :public Stack<T>
{
private:
int listSize; //the number of elements,and that is the number of nodes
Node<T> * top; //与AStack栈不同,这里,top指向栈顶元素
public:
LStack() //不必限定元素的最大值
{
listSize = 0;
top = NULL;
}
~LStack()
{
}
bool push(const T &);
bool pop(T &);
bool topValue(T &);
void clear();
int length() const
{
return listSize;
}
};
template<class T> bool LStack<T>::push(const T &element)
{
Node<T> *tmp = new Node<T>(element,top);
top = tmp;
++listSize;
return true;
}
template<class T> bool LStack<T>::pop(T &ref_elem)
{
if (top == NULL)
{
return false; //栈中没有元素
}
Node<T> *tmp = top;
top = top->next;
ref_elem = tmp->element;
delete tmp;
--listSize;
return true;
}
template<class T> bool LStack<T>::topValue(T & ref_elem)
{
if (top == NULL)
{
return false; //none element in stack
}
ref_elem = top->element;
return true;
}
template<class T> void LStack<T>::clear()
{
Node<T> * tmp;
while (top != NULL)
{
tmp = top;
top = top->next;
delete tmp;
}
}
#endif
晚一些时候,我把用栈实现递归的方法,写到这里来。