一、栈的链式存储结构
栈的链式存储结构,简称为链栈。链栈是没有附加头结点的运算受限的单链表。栈顶指针就是链表的头指针。
栈是用栈顶来做插入和删除操作,那么对于链栈的栈顶放在链表的头部还是尾部呢?
单链表有头指针,而栈顶指针也是必须的,所以比较好的办法是把栈顶放在单链表的头部。另外,都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。
链栈的结构如下:
对于空栈来说,链表原定义是头指针指向空,那么链栈的空其实就是 top=NULL 的时候。
二、实现要点
1、初始化。初始化的目标是要构造一个空栈。空栈的特性:
(1)栈的count = 0
(2)栈的 top 为 null
LinkStack *InitStack(LinkStack *s)
{
s->top = (StackNode*)malloc(sizeof(StackNode));
//空栈的特性(1)(2)
s->top = NULL;//(1)
s->count = 0;//(2)
return s;
}
2、进栈。假设为要插入的元素e开辟的新节点为p,那么插入过程为:首先开辟一个内存空间给 p,然后 p的data就是e,再将新结点sp的后继赋值为当前结点 s->top。最后将栈顶指针指向结点 p。
总结为两步:
(1)处理新结点p的后继,这个后继就是原本的栈顶结点。
(2)将栈顶指针 top 重新指向新结点p。
代码:
LinkStack *Push(LinkStack *s, SElemType e)
{
StackNode *p= (StackNode*)malloc(sizeof(StackNode));//要插入的节点
p->data = e;
//实现入栈
p->next = s->top;//(1)新节点后继为原栈顶节点
s->top = p;//(2)将新的结点p赋值给栈顶指针
s->count++;
return s;
}
3、出栈。大致过程为:假设变量p用来存储要删除 的栈顶结点,将栈顶指针下移一位,最后释放p即可。
代码:
LinkStack *Pop(LinkStack *s)
{
if(s->top == NULL)//栈空的判断!!!
{
cout<<"栈已空,无法执行弹出操作!"<<endl;
}
else
{
StackNode *p= (StackNode*)malloc(sizeof(StackNode));//(1)要弹出的节点
p = s->top;//(2)栈顶节点赋给p
cout<<p->data<<"出栈"<<endl;
s->top = p->next;//(3)栈顶指针下移一位,指向后一结点
free(p);//(4)释放p
s->count--;
}
return s;
}
4、置空链栈。方法是设置两个工作结点,开始循环。在释放p之前,让q成为p的后继。还是那个比喻,在皇帝死之前,册封皇子。free(p); 皇帝死了,p=q; 皇子就成了新皇帝。(类似单链表的置空操作)。
代码:
LinkStack *ClearStack(LinkStack *s)
{
StackNode *p, *q;
p = s->top;
while(p)
{
q = p->next;//(1)让q成为p的后继
free(p);//(2)释放p
p = q;//(3)q赋给p
}
s->top=NULL;//(4)!!!
s->count = 0;
return s;
}
链栈实现代码:
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef int SElemType;
//节点类型
typedef struct StackNode
{
SElemType data;
struct StackNode *next;
}StackNode;
typedef struct
{
StackNode *top;//栈顶指针
int count;//记录栈中元素个数
}LinkStack;
//初始化
LinkStack *InitStack(LinkStack *s)
{
s->top = (StackNode*)malloc(sizeof(StackNode));
//空栈的特性(1)(2)
s->top = NULL;//(1)
s->count = 0;//(2)
return s;
}
//入栈
LinkStack *Push(LinkStack *s, SElemType e)
{
StackNode *p= (StackNode*)malloc(sizeof(StackNode));//要插入的节点
p->data = e;
//实现入栈
p->next = s->top;//(1)新节点后继为原栈顶节点
s->top = p;//(2)将新的结点p赋值给栈顶指针
s->count++;
return s;
}
//出栈
LinkStack *Pop(LinkStack *s)
{
if(s->top == NULL)//栈空的判断!!!
{//count为0也可说明栈为空
cout<<"栈已空,无法执行弹出操作!"<<endl;
}
else
{
StackNode *p= (StackNode*)malloc(sizeof(StackNode));//(1)要弹出的节点
p = s->top;//(2)栈顶节点赋给p
cout<<p->data<<"出栈"<<endl;
s->top = p->next;//(3)栈顶指针下移一位,指向后一结点
free(p);//(4)释放p
s->count--;
}
return s;
}
//置空链栈
LinkStack *ClearStack(LinkStack *s)
{
StackNode *p, *q;
p = s->top;
while(p)
{
q = p->next;//让q成为p的后继
free(p);//释放p
p = q;//q赋给p
}
s->top=NULL;//!!!
s->count = 0;
return s;
}
//打印
void PrintStack(LinkStack *s)
{
StackNode *p;
p = s->top;
while(p)//top为空时链栈为空
{
cout<<p->data<<" ";
p = p->next;
}
cout<<endl;
}
int main()
{
LinkStack *s = InitStack(s);
cout<<"************************"<<endl;
Push(s, 1);
PrintStack(s);
Push(s, 2);
PrintStack(s);
Push(s, 3);
PrintStack(s);
Push(s, 4);
PrintStack(s);//后入先出,逆序打印
cout<<"************************"<<endl;
Pop(s);
PrintStack(s);
Pop(s);
PrintStack(s);
Pop(s);
PrintStack(s);
Pop(s);
PrintStack(s);
cout<<"************************"<<endl;
Pop(s);
cout<<"************************"<<endl;
Push(s, 1);
PrintStack(s);
cout<<"************************"<<endl;
ClearStack(s);
PrintStack(s);
cout<<"************************"<<endl;
return 0;
}
结果:
************************
1
2 1
3 2 1
4 3 2 1
************************
4出栈
3 2 1
3出栈
2 1
2出栈
1
1出栈
************************
栈已空,无法执行弹出操作!
************************
1
************************
************************
Process returned 0 (0x0) execution time : 1.625 s
Press any key to continue.