栈,也是线性表(n个元素e1,e2….en组成的有限序列),顺序表,链表都是线性表,不过栈只能在一端(栈顶)插入和删除,称为”入栈”和“出栈”,(早期教材叫做“压栈”和“弹栈”);这就好比弹夹装子弹,栈
又分为顺序栈和链栈
1:顺序栈
1)结构
typedef struct sStack
{
ElementType data[MAXLEN]; //栈元素
int top; //栈顶指示器
}seqStack;
栈顶指示器是为了表示栈顶元素的位置,规定空栈的栈顶指示器为-1
2) 初始化栈
void InitialStack(seqStack &s)
{
s.top=-1;
}
3)判断栈是否为空
bool StackEmpty(seqStack s)
{
if(-1==s.top)
return true;
return false;
}
4)取栈顶元素
void StackTop(seqStack s,ElementType &x)
{
if(StackEmpty(s))
cout<<"栈空,不能取栈顶元素\n";
x=S.data[s.top];
}
5) 判断栈满
bool StackFull(seqStack s)
{
if(MAXLEN-1==s.top)
return true;
return false;
}
6)入栈
void PushStack(seqStack &s,ElementType x)
{
if(StackFull(s))
cout<<"栈满,不能入栈\n";
s.top++;
s.data[s.top]=x;
}
7)出栈
void PopStack(seqStack &s,ElementType x)
{
if(StackEmpty(s))
cout<<"栈空,不能出栈\n";
x=s.data[s.top];
s.top--;
}
2:链栈
链栈即采用链式存储,由于是一端操作,而且栈顶指针每次入栈出栈后都要改变,故不用带头节点
1)结构
typedef struct lsNode
{
ElementType data;
struct lsNode *next;
}sNode;
2)初始化
void InitialStack(sNode *&top)
{
top=NULL;
}
3)入栈
void PushStack(sNode *&top,ElementType x)
{
sNode *s=new sNode;
s->data=x;
s->next=top; //链表一般不用考虑栈满
top=s;
}
4)出栈
void PopStack(sNode *&top,ElememtType x)
{
if(NULL==top)
cout<<"栈空,不能出栈\n";
sNode *u;
x=top.data;
u=top;
top=top->next;
delete u;
u=NULL;
}
顺便说一下栈就地逆置吧,就是将栈各节点的后驱指针倒置指向前驱的节点,e1变为最后一个节点,最后一个节点变为第一个节点
void Reveser(sNode &top)
{
node *p=NULL;
node *u;
while(top!=NULL)
{
u=top; //将u指向待分离的表头节点,u和top指向了未逆置部分的第一个节点
top=top->next; //未逆置部分表头后移一位
u->next=p; //本来这是第一个节点,指向p所指向节点后就为null了,显然符合逻辑
p=u; //以逆置部分的表头指针指向新分离出的节点
}
top=p; //原来的表头指针指向心的镖头指针
}