hello,大家好,又见面了,我是你们的老朋友随 . . .风,今天我们来讲讲链栈的定义,压栈和弹栈
首先,我们需要定义一下头文件,因为用到了malloc函数,所以除了常用的<stdio.h>之外,我们还需要一个<stdlib.h>。
之后,因为我们在之后会用到返回值OK和ERROR,所以可以先预定义一下
#define OK 1
#define ERROR 0
然后还需要转换一下类型
typedef int elemtype;
typedef int status;
其实用int也行,但是这个格式更符合数据结构的样子
1.定义链栈
一个链栈需要定义些什么呢。我们来想一想,栈,先进后出的一种结构,那肯定就会有一个数据,然后怎么确定前后关系呢,
就要用到指针了,也就是我们说的结点。
typedef struct node{
elemtype data; //这个是数据元素
struct node*next; //这个就是我们的结点了
}Snode,*linkstack; //为什么这里会用到两个呢,第一个是真正的链栈称呼,但是我们用第二个就可以使用它的地址了(但愿是这样理解的)
然后我在这里提一下主函数的事情,大家可能看到书上的在定义结点后会出现定义子函数的情况,这肯定是OK的,为什么会直接在这里定义子函数呢,因为你直接写main函数的话,前面不定义,函数运行到main了,它不知道你写的这个函数是什么,它就报错了,所以要么在主函数前面写子函数,要么就先定义。
2.压栈
什么叫压栈,其实就是我们常常说的插入,不过是插入在最前面,也就是我们的 top ,大家想一下,怎么插入,首先,是不是要分配一个地址给我们新定义的 top ,然后就把我们要插进去的值传给 top ,再把 top 和原来的链栈钩起来就好了,然后把地址传给我们最初的栈就好啦
status push(linkstack *S,elemtype e)
{
linkstack top;
top=(linkstack)malloc(sizeof(Snode)); //这个就是内存分配函数
if(!top)return ERROR; //如果电脑没得内存分配给我们,我们就只能默默的退出去了
top->data=e;
top->next=*S;
*S=top; //为什么这里是*S呢,地址传输不是直接等于就好了吗?大家看看我们的函数定义,是不是有一个*S,前面我们说过了linkstack是一个地址,那我们再*S,是不是就变成了二级指针了呢,二级指针的地址转换,就不是一级指针直接等于就好了
return OK;
}
3.弹栈
什么叫弹栈,顾名思义,就是把一个元素弹出来,那是哪个元素呢,大家想一下,我们的栈是先进后出的结构,就像一幅牌,你一张一张的把它放在桌子上,然后只能一张一张的拿,你是不是只能从最后放的那张开始,这就是栈。那我们也就知道我们弹的是哪一个元素了,没错,就是最后放进来的那个。怎么删除一个在最后面的元素呢,可以用p->next一直指下去,直到出现NULL为止,就找到了我们的最后一个元素,也可以一开始就设置一个尾结点,但是,但是,大家看看我们的压栈函数,我们是逆序输入的哦,也就是说我们的头指针一直指向我们最后输入的一个元素,所以就很简单了(函数名我就不写了)
linkstack top;
top=*S;
*e=top->data;
*S=top->next; //让S指向下一个元素,就达到了删除的目的
free(top); //记住要free,不然那个空间就浪费了
return OK;
好了,就到这里结束啦,呸呸呸,再帮你们写一个printf函数,不然一直在主函数里输出,会显得主函数很乱,主函数越简洁越好
4.输出函数
再谈一下我们的压栈,我们是逆序输入的对吧,那怎么做到顺序输出呢,第一可以设置一个尾结点,然后从后面往前找,第二,我们可以利用一个数组,进行他的赋值,然后逆序输出数组,两者复杂度差不多,看自己喜欢哪个吧,下面给大家讲一下数组的(是我太喜欢数组了,哎)
linkstack p;
int i=0,a[10]; //定义一个整型的数组,10也行,100也行,也可以在压栈那里设置一个总元素变量,然后然后把那个值返回出来
p=S;
while(p->next!=NULL) //这里就是给数组赋值了
{
a[i]=p->data;
p=p->next;
++i;
}
i=i-1; //关于这里为什么要i-1,老师说是一开始定义的a[10],那么它就自带了一个地址,逆序的话就会先把地址输出来,我这里取巧的直接给它-1了,哈哈,懂的同学欢迎留言,谢谢
for(;i>=0;--i)
{
printf("%d ",a[i]);
}
printf("
");
好了,链栈的压栈和弹栈就到这里结束了,大家下期再见!!!