前言:
上一遍文章,博主讲了顺序栈,今天博主讲一下链式栈,链式栈专业术语:链式栈是一种数据存储结构,可以通过单链表的方式来实现,使用链式栈的优点在于它能够克服用数组实现的顺序栈空间利用率不高的特点,但是需要为每个栈元素分配额外的指针空间用来存放指针域。讲人话就是:就是有一个栈顶指针,指向了一个单链表,单链表存数据,栈顶指针取,放数据。
每日一遍,心情愉悦
(图片是博主在家拍的,其实还有一个非常带感的视频,上传不了,有机会给网友看一下)
1.理解逻辑,知道什么是链式栈。
链式栈,其实和单链表很相似,进栈可以理解为单链表的头插法,出栈可以理解为带头结点的单链表输出,只不过它的头结点就是我们的栈顶,栈顶用来输入和输出,链式栈比顺序栈好一点它比较的灵活,不想顺序栈要限定大小,链式栈不用限制大小,很灵活。放一张逻辑图:
(这个图是链式栈和顺序栈对比,链式栈的逻辑就是利用 malloc 生成新的结点然后再用 next 连接)
2.理解链式栈逻辑之后我们要认识一下代码
typedef struct node
{
int data; //数据域
struct node * next; //指针域
}LinkStack; //定义栈,是不是发现和链表很像,你猜对了
p=(LinkStack *)malloc(sizeof(LinkStack));//分配空间
LinkStack *top //栈顶指针
p->data=x; //设置新结点的值
p->next=top; //将新元素插入栈中
p=top; //指向被删除的栈顶
*e =p->data;//返回我们出栈的值
top=top->next; //修改栈顶指针
free(p);//释放已经出栈的结点
复制代码
上面就是整个链式栈的核心代码,我们只要理解这些代码我们就学会一半了,另外一半就是逻辑,程序就是代码+算法,而算法就是我们的逻辑思维。
3.链式栈判断栈空,获取栈顶
int StackEmpty(LinkStack *top)// 判断链栈栈空
{
return (top?0:1) ;//栈空返回 1
}
int GetTop(LinkStack *top)//获取栈顶的值
{
if(!top)//判断栈顶是不是为空
{
printf("/n链表是空的!");
return 0;
}
return top->data;//返回栈顶的值
}
复制代码
我们的形参都是栈顶指针,如果我们栈为空就会返回 1,有栈顶是会返回 0 的,而我们的获取栈顶的值就是直接用 top 取值就可以了
3.链式栈的简单进栈操作
进栈其实很容易的,只要之前看过博主的链表篇就会了,博主把简单的逻辑步骤写了出来,大家可以看图理解一下有点抽象,时间有限往大家理解。
LinkStack *Push(LinkStack *top,int x)//入栈
{
LinkStack *p;
p=(LinkStack *)malloc(sizeof(LinkStack));//分配空间
p->data=x; //设置新结点的值
p->next=top; //将新元素插入栈中
top=p; //将新元素设为栈顶
return top;
}
复制代码
博主采用的是主函数用循环,一个一个的入栈,当然你们也可以改一下,比如传数组过来,在实现函数里面用循环进栈,其实都差不多啦
4.链式栈的简单出栈操作
栈的出栈和单链表的用头结点输出很像,真的只要我们知道链表,栈就真的不难
LinkStack *Pop(LinkStack *top,int *e)//出栈
{
LinkStack *p;
if(!top)
{
printf("/n链栈是空的!");
return NULL;
} //判断是否为空栈n
p=top; //指向被删除的栈顶
*e =p->data;//返回我们出栈的值
top=top->next; //修改栈顶指针
free(p);//释放已经出栈的结点
return top;
}
复制代码
5.链式栈的整体演示效果和整体代码
#include <stdio.h>
#include <malloc.h>
typedef struct node
{
int data; //数据域
struct node * next; //指针域
}LinkStack;
int StackEmpty(LinkStack *top)// 判断链栈栈空
{
return (top?0:1) ;//栈空返回 1
}
int GetTop(LinkStack *top)//获取栈顶的值
{
if(!top)//判断栈顶是不是为空
{
printf("/n链表是空的!");
return 0;
}
return top->data;//返回栈顶的值
}
LinkStack *Push(LinkStack *top,int x)//入栈
{
LinkStack *p;
p=(LinkStack *)malloc(sizeof(LinkStack));//分配空间
p->data=x; //设置新结点的值
p->next=top; //将新元素插入栈中
top=p; //将新元素设为栈顶
return top;
}
LinkStack *Pop(LinkStack *top,int *e)//出栈
{
LinkStack *p;
if(!top)
{
printf("/n链栈是空的!");
return NULL;
} //判断是否为空栈n
p=top; //指向被删除的栈顶
*e =p->data;//返回我们出栈的值
top=top->next; //修改栈顶指针
free(p);//释放已经出栈的结点
return top;
}
int main(){
LinkStack *L;
int n, num, m;
int i;
if(StackEmpty(L))//判断是不是空栈
{
printf("栈为空\n");
}
else{
printf("初始化完成,有栈顶\n");
}
printf("请输入入栈元素个数:\n");
scanf("%d", &n);
printf("请输入要入栈的%d个元素:\n", n);
for(i = 0; i < n; i++){
scanf("%d", &num);
L=Push(L,num);
}
printf("栈顶的值:%d \n",GetTop(L));
printf("请输入要出栈的元素个数(不能超过%d个):\n", n);
scanf("%d", &n);
printf("依次出栈的%d个元素:\n", n);
for(i = 0; i < n; i++){
L=Pop(L, &m);
printf("%3d",m);
}
return 0;
}
复制代码
总结:
栈博主基本上就讲完了,其实栈需要和之前学过的知识一起联想一下,才会学的很明白,用博主用自己的话总结一下,顺序栈就是一个带有下标的数组,这个下标一直往后面走,输出就往前面走,这个下标就是栈的栈顶,链式栈呢就是一个带头结点的指针的单链表,进栈就相当于单链表使用头插法建立链表,链式栈出栈就用头结点出单链表,而这个头结点就相当于我们的栈顶。栈就这样了,下一篇就是我们的队列了,想看的童鞋记得关注哦,创作不易,希望大家,点赞,评论,收藏。谢谢大家,不喜勿喷。
评论