一、关于链栈的操作,它和链表有很大的相似之处,不同的是,栈只允许在栈顶进行入栈操作,和链表的头插法相同。
二、之所以要用链栈,是因为如果我们用顺序栈的话,需要提前申请一片内存空间,但是如果我们值存入少量的元素,那么这片内存空间难免会造成一定的浪费。如果使用链栈的话,我们只在入栈的时候进行内存的申请,然后再进行元素的存储,既可以进行动态的内存申请。根据实际入栈元素的多少申请所需的空间即可。
三、链栈和顺序栈的基本操作都是一样的,包括:初始化,求长度,判断栈是否为空,入栈,出栈,取栈顶元素。
(1)先定义一个结构体,这个结构体中,包括栈中每个节点的节点值data,和指向下一个栈节点的指针next
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
//定义一个结构体栈
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackList;
typedef StackList *LStack;//声明一个指向这个结构体的指针类型Lstack
(2)进行初始化,将链栈的顶处设置一个指针,用来指向这个栈,这个指针内不存储东西,那么刚开始就把这个栈顶指针设置为NULL即可。
//初始化链栈
void Init(LStack *s)
{
(*s)=(LStack)malloc(sizeof(StackList));
(*s)->next=NULL;
}
(3)判断栈是否为空,只需要判断栈顶指针的指针域是否为空即可。为空返回0,不为空返回1。
//判断栈是否为空
int Empty(LStack s)
{
if(s->next==NULL)
{
return 0;//为空返回0,
}
return 1; //不为空返回1,
}
(4)求栈的长度,即从栈顶的下一个,也就是第一个元素开始,往下遍历,一直遍历到指针指向空,说明遍历完了,没遍历一个,就计数器加一,临时的指针变量往后移动一位p=p->next
//求栈中的元素数量,即长度
int Printf(LStack s)
{
int count=0;
LStack p;
p=s->next;//指向第一个元素
while(p){
count++;
p=p->next;
}
return count;
}
(5)入栈,将值x,压入到栈中,我们首先声明一个指针变量,来存储这个元素值x,当然,因为我们要用这个指针变量存储东西,所以我们要先为这个指针变量申请内存空间malloc,然后存入。
//入栈
void Push(LStack *s,ElemType x)
{
LStack p;//声明一个指针变量
p=(LStack)malloc(sizeof(StackList));//为这个指针变量分配空间
p->data=x; //将入站的元素值存入到这个指针的数据域
p->next=(*s)->next; //这两个步骤和顺序链表的操作相似。
(*s)->next=p;
}
(6)出栈,首先要判断栈是否为空,如果不为空,我们指针p指向栈中的第一个节点,然后用e记录下当前栈顶元素的值,接着将不存东西的栈顶指针的指针域指向指针p的下一个节点处,释放指针p即可。
//出栈
ElemType Pop(LStack *s)
{
LStack p;//声明一个结构体类型的指针变量
ElemType e;
p=(*s)->next;//指向栈中的栈顶元素
if(p==NULL)
{
return 0;
}
(*s)->next=p->next;//不为空的话就让栈顶元素变成当前栈顶p的下一个
e=p->data;//存放以下删除的栈顶元素
free(p); //释放指针
return e; //返回删除的栈顶指针的值
}
(7)获取栈顶元素的值,首先要判断栈是否为空,如果不为空,直接返回栈中的第一个节点的值即可
//取栈顶元素的值
ElemType GetTop(LStack s)
{
if(Empty(s)){//如果栈顶元素不为空的话,则打印出栈顶元素
return s->next->data;
}
return 0;
}
(8)主函数,对上面定义的各个函数进行定义,这一模块的代码块,大家可以根据自己的需求自己进行定义即可,我只给出我所写的一部分
int main()
{
LStack s;
int x;
ElemType e;
//初始化栈
Init(&s);
//判断栈是否为空
x=Empty(s);
if(x)
{
printf("栈空\n");
}
//扫描要入站的元素
Push(&s,5);
Push(&s,4);
Push(&s,6);
Push(&s,8);
Push(&s,2);
//获取栈的长度
x=Printf(s);
printf("栈的长度为%d\n",x);
//获取当前栈的栈顶元素
e=GetTop(s);
if(e){//如果栈不为空的话输出
printf("当前栈顶元素为:%d\n",e);
}
//删除当前栈的栈顶元素
e=Pop(&s);
if(x)//如果栈不为空的话进行出栈操作
{
printf("删除的元素为:%d\n",e);
}
//获取当前的栈顶元素
e=GetTop(s);
if(e){//如果栈不为空的话输出
printf("当前栈顶元素为:%d\n",e);
}
x=Printf(s);
printf("栈的长度为%d\n",x);
return 0;
}
(9)我这个案例的运行结果为:
总结:有一些人在定义一个结构体的指针时,当把它传入到另外一个函数中时,不知道该如何编写,如果你在定义的时候,这个结构体的类型不是一个指针,那么你如果在主函数中定义一个结构体指针变量,传入到其他函数时,要使用双重指针**,才能进行栈的更改,我在这里刚开始就定义了一个指向结构体的指针类型,那我在声明一个结构体类型的指针时,就不需要加*,原理是一样的。如有错误,请大佬留言,如果有更好的方法,欢迎交流。