前言
在上次单链表的实现之后,由于为期末考试所累,暂停了,回家后电脑又坏了,由于系统崩溃重装了系统,之前写的循环链表的东西都没了,之后休息了几天,决定先搞栈这个东西吧。由于我是照程杰老师的书学习的,所以很多思想方法都是继承程杰老师的
1.栈的作用
栈和链表其实有很多共通之处,那么为什么还要链表呢。这就像明明你可以两条腿走路,干嘛还要乘坐火车和飞机呢。栈的特点是先进后出,浏览器的后退键,还有其他软件的撤销键,都用到了栈。而且链栈不存在栈满的情况。
2.栈的定义
栈还是用结构体来定义,但是和单链表不同的是,栈用了两个结构体来定义,多出来的那一个结构体我管他叫“管理者”,他的作用是控制插入和删除。而且在链栈中我们是不需要头结点的,而且只有压栈是才会新创建一个结点,所以没有必要把新创建结点的函数单独拿出来作为一个独立模块,我们需要的是高聚合度,低耦合度。栈的定义代码如下:
//定义结点(普通链表)
typedef struct StackNode
{
SElemType data;
struct StackNode* next;
}StackNode,*LinkStackPtr;
//定义栈(管理者)
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
3.内容布局
本篇文章所涉及的主要操作有:
1.压栈:
p->next = s->top;
s->top = p;
s->count++;
2.出栈:
*e = s->top->data;
p = s->top;
s->top = s->top->next;
free(p);
s->count--;
4.操作的一些图解
代码如下
/*
程序名称:链栈的建立与基本操作
编译环境:vs2010
最后修改:2019.7.31
作者:许安
*/
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef int Status;
typedef int SElemType;
//定义结点(普通链表)
typedef struct StackNode
{
SElemType data;
struct StackNode* next;
}StackNode,*LinkStackPtr;
//定义栈(管理者)
typedef struct LinkStack
{
LinkStackPtr top;
int count;
}LinkStack;
Status InitStack(LinkStack *s);//初始化栈
Status ClearStack(LinkStack *s);//清空栈
Status StackElem(LinkStack *s);//判断栈是否为空
Status GetTop(LinkStack *s,SElemType *e);//取栈顶元素
Status Push(LinkStack *s);//压栈
Status Pop(LinkStack *s,SElemType *e);//出栈
Status OutStack(LinkStack *s);//读栈
int main()
{
LinkStack s;
SElemType e;
int i,x=0,n=0;
if(InitStack(&s))
printf("初始化成功!\n");
else
printf("初始化失败!\n");
if(StackElem(&s))
printf("栈为空!\n");
else
printf("栈非空!\n");
while(n != 7)
{
printf("----------------------------\n");
printf("$1.压栈 $2.出栈 $3.清空栈 $\n");
scanf("%d",&n);
switch(n)
{
case 1:
i = Push(&s);
if(i == ERROR)
printf("压入失败\n");
else
printf("操作后的栈\n");
OutStack(&s);
break;
case 2:
i = Pop(&s,&e);
if(i == ERROR)
printf("出栈失败\n");
else
printf("成功,出栈的数:%d\n",e);
printf("操作后的栈:\n");
OutStack(&s);
break;
case 3:
i = ClearStack(&s);
if(i == ERROR)
printf("清空失败\n");
else
printf("操作后的栈\n");
OutStack(&s);
break;
}
}
}
Status InitStack(LinkStack *s)
{
s->top = NULL;
s->count = 0;
return OK;
}
Status ClearStack(LinkStack *s)
{
LinkStackPtr p,q;
p = s->top;
while(p)
{
q = p;
p = p->next;
free(q);
}
s->top = NULL;
s->count = 0;
return OK;
}
Status StackElem(LinkStack *s)
{
if(s->count == 0)
return OK;
else
return ERROR;
}
Status GetTop(LinkStack *s,SElemType *e)
{
if(s->top == NULL)
return ERROR;
else
*e = s->top->data;
return OK;
}
Status Push(LinkStack *s)
{
int i,x=0;
printf("输入您要压进去的数,-1时停止\n");
for(i = 0;x!=-1;i++)
{
scanf("%d",&x);
if(x!=-1)
{
LinkStackPtr p = (LinkStackPtr)malloc(sizeof(StackNode));
if(!p)
return ERROR;
p->data = x;
p->next = s->top;
s->top = p;
s->count++;
}
}
return OK;
}
Status Pop(LinkStack *s,SElemType *e)
{
LinkStackPtr p;
if(s->top == NULL)
return ERROR;
*e = s->top->data;
p = s->top;
s->top = s->top->next;
free(p);
s->count--;
return OK;
}
Status OutStack(LinkStack *s)
{
LinkStackPtr p = s->top;
printf("栈内容为:\n");
while(p)
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
printf("栈的长度为:%d \n",s->count);
return OK;
}
运行结果
后记
可能有同学发现了,链栈是把头结点的那一段当作了栈顶,那是因为在单链表中本身就有一个头结点,为了方便就用头结点代替栈指针。
上述代码把链表
栈的各种操作柔和到一个方程里面,以致于代码有些庞大,但是在实际操作中还可以适当加减操作
以上就是链栈的表示和各种操作,喜欢的多多支持哦~