二、栈
栈是一种“发育不良”的线性表,它具有与线性表相同的存储结构(基于数组的或基于链于的),但栈的“缺陷”---不能像线性表那样具有插入、删除操作---反而给了它独有的特色。在后面将会发现,递归,可以用栈来实现。
在时间复杂度上,基于数组的栈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
晚一些时候,我把用栈实现递归的方法,写到这里来。