用顺序和链式实现了线性表,这次要从顺序和链式实现栈了。
栈:限定仅在表尾进行插入和删除操作的线性表。
允许插入和删除的一端称为栈顶,另一端称为栈底。
操作特性:后进先出
注意:栈只是对表插入和删除操作的位置进行了限制,并没有限定插入和删除操作进行的时间。
栈的顺序存储结构及实现
顺序栈——栈的顺序存储结构
进栈:top加1
出栈:top减1
栈空空:top= -1
栈满:top= MAX_SIZE-1
//顺序栈类的声明:
const int MAX_SIZE=100;
template <class T>
class seqStack
{
public:
seqStack();
~seqStack();
void Push(T x);
T Pop();
T GetTop();
bool Empty();
private:
T data[MAX_SIZE];
int top;
}
//入栈
template <class T>
void seqStack<T>::Push(T x)
{
if (top==MAX_SIZE-1) throw “溢出”;
top++;
data[top]=x;
}
//判断是否是空栈
template <class T>
bool seqStack<T>::Empty()
{
if (top==-1)
return true;
return false;
}
//取栈顶
template <class T>
T seqStack<T>::GetTop()
{
if (Empty()) throw ”空栈” ;
return data[top];
}
//—出栈
template <class T>
T seqStack<T>:: Pop()
{
if (top==-1) throw “溢出”;
x=data[top];
top--;
return x;
}
在一个程序中需要同时使用具有相同数据类型的两个栈,如何顺序存储这两个栈?
解决方案1:
直接解决:为每个栈开辟一个数组空间。
两栈共享空间:使用一个数组来存储两个栈,让一个栈的栈底为该数组的始端,另一个栈的栈底为该数组的末端,两个栈从各自的端点向中间延伸。
解决方案2:
顺序栈单向延伸——使用一个数组来存储两个栈。
栈1的底固定在下标为0的一端;
栈2的底固定在下标为StackSize-1的一端。
top1和top2分别为栈1和栈2的栈顶指针;
Stack_Size为整个数组空间的大小。
栈1为空top1== -1
栈2为空top2== Stack_Size
栈满top2=top1+1
//两栈共享空间类的声明:
const int Stack_Size=100;
template <class T>
class BothStack
{
public:
BothStack();
~BothStack();
void Push(int i, T x);
T Pop(int i);
T GetTop(int i);
bool Empty(int i);
private:
T data[Stack_Size];
int top1, top2;
};
//两栈共享空间的实现——插入
template <class T>
void BothStack<T>::Push(int i, T x )
{
if (top1==top2-1) //如果栈满,则抛出上溢异常;
throw "上溢";
/*若在栈1插入,则
top1加1;
在top1处填入x;*/
if (i==1)
data[++top1]=x;
/*若在栈2插入,则
top2减1;
在top2处填入x;*/
if (i==2)
data[--top2]=x;
}
//两栈共享空间的实现——删除
template <class T>
T BothStack<T>::Pop(int i){
/*若是在栈1删除,则
若栈1为空栈,抛出下溢异常;
删除并返回栈1的栈顶元素;*/
if (i==1)
{
if (top1== -1) throw "下溢";
return data[top1--];
}
/*若是在栈2删除,则
若栈2为空栈,抛出下溢异常;
删除并返回栈2的栈顶元素;*/
if (i==2)
{
if (top2==StackSize) throw "下溢";
return data[top2++];
}
}
//判断某个栈空算法
template <class T>
bool BothStack<T>::Empty(int i)
{
if(i==1){
if(top1==-1) return 1;
else return 0;
}
if(i==2) {
if(top2==StackSize) return 1;
else return 0;
}
}
//取某个栈栈顶的算法
template <class T>
T BothStack<T>::GetTop(int i)
{
if(i==1){
if(top1!=-1) return data[top1];
}
if(i==2){
if(top2!=StackSize) return data[top2];
}
}
链栈——栈的链接存储结构
//链栈的类声明:
struct Node
{
int data;
Node *next;
};
template <class T>
class LinkStack
{
public:
LinkStack() {top=NULL;};
~LinkStack();
void Push(T x);
T Pop();
T GetTop();
bool Empty();
private:
Node<T> *top;
}
//插入:
template <class T>
void LinkStack<T>::Push(T x)
{
s=new Node<T>;
s->data=x;
s->next=top;
top=s;
}
//删除:
template <class T>
T LinkStack<T>::Pop()
{
if (top==NULL)
throw "下溢";
x=top->data;
p=top;
top=top->next; //不能用top++,链式存储地址不连续
delete p;
return x;
}
//析构
template <class T>
LinkStack<T>::~LinkStack()
{
while (top)
{
Node<T> *p;
p=top->next;
delete top;
top=p;
}
}
顺序栈和链栈的比较:
时间性能相同
空间性能:
顺序栈:有元素个数的限制和空间浪费的问题。
链栈:没有栈满的问题,只有当内存没有可用空间时才会出现栈满,但是每个元素都需要一个指针域,从而产生了结构性开销。
结论:当栈的使用过程中元素个数变化较大时,用链栈是适宜的,反之,应该采用顺序栈。