栈的链式存储结构(指针)以及栈的常用操作(入栈、出栈、遍历、统计栈的元素个数、取栈顶元素) c语言 数据结构 超详细~~

/本程序中包含对栈的入栈、出栈、遍历、统计栈的元素个数、取栈顶元素等基本常用操作/
#include<stdio.h>
#include<stdlib.h>
typedef int Elemtype;
typedef struct node
{
Elemtype data;
struct node* next;
}node;
typedef struct stack
{
struct node* top;//栈顶指针
struct node* bottom;//栈底指针
}stack;
void initstack(stack*);//栈的初始化
void pushstack(stack*,int);//入栈
bool popstack(stack*,int*);//出栈
//出栈的第二个参数可以要,可以不要,如果想查看出栈的元素的数据的话
//就可以用指针先修改它的值,之后在其他地方也是可以访问的
void traverse(stack* );//遍历栈的所有元素
void clear(stack* );//清空
bool empty(stack* );//判断栈是否为空
void calculate(stack* );//计算栈的长度
int main(void)
{
stack s;
int val;
initstack(&s);
pushstack(&s, 1);
pushstack(&s, 2);
pushstack(&s, 3);
pushstack(&s, 4);
traverse(&s);
popstack(&s,&val);
traverse(&s);
calculate(&s);
clear(&s);
calculate(&s);
system(“pause”);
return 0;
}
void initstack(stackps)
{
ps->top = (node
)malloc(sizeof(node));
if (!ps->top)
{
printf(“分配内存空间失败\n”);
exit(-1);
}
else
{
ps->bottom = ps->top;
//刚开始栈顶指针和栈底指针都指向同一块内存
/(注意这块内存知识作为一个标志使用,该内存一般是不用来存储数据的,如果要存储数据的话,那么就是该栈元素的个数)/
ps->top->next = NULL;//一定要将ps的下一个节点
//也就是链表中的头节点的指针域指向尾空
//也可以这样写
//ps->bottom->next = NULL;
printf(“栈的初始化已完成\n”);
}
}
void pushstack(stackps,int val)
{
//由于入栈不需要判断栈满,所以不需要返回值进行标识
//先生成一个节点,再将数据域进行赋值,然后再进行指针的连接
//再将栈的栈顶指针指向这个新生成的节点
node
p = (node*)malloc(sizeof(node));
if (!p)
{
printf(“分配内存空间失败\n”);
return;
}
else
{
p->data = val;
p->next = ps->top;
ps->top = p;//一定要将新插入的结构作为栈顶结点,所以要将新增加的p结点的地址赋值给该栈的栈顶指针top
printf(“入栈成功\n”);
}
}
bool empty(stack* ps)
{
if (ps->bottom == ps->top)
{
return true;
}
else
{
return false;
}
}
bool popstack(stackps, intval)
{//将出栈元素的值保存在val这个变量中
if (!empty(ps))//这个地方就不用传入ps的地址了,因为ps本身就是一个指针
{
//如果栈不为空
node* p = ps->top;
val = p->data;
ps->top = p->next;
free§;
p = NULL;
printf("%d已出栈成功\n",val);
return true;
/注意不要直接free掉栈的top指针,因为一旦直接free掉的话,那么下一次寻找该栈顶元素就找不到了,必须将该该的栈顶元素的下一个元素的地址进行一个保存,那么在free掉栈顶元素之后,我们还可以通过保存的地址,找到新的栈顶元素的地址,从而访问栈顶元素 /
}
else
{
return false;
}
}
void traverse(stack
ps)
{
/注意在遍历的时候,不能改变栈中原先的栈顶指针的位置/
node
p = ps->top;
if (empty(ps))//栈为空
{
printf(“栈为空,无法进行遍历操作\n”);
return;
}
else
{
while (p!=ps->bottom)
{
printf("%d\t", p->data);
p = p->next;
//栈顶指针是指向最后一个有数据的元素
//栈底指针是指向第一个有数据的元素的前一个数据(相当于链表的头节点)
//所以可以通过这个方式将栈内的所有元素都打印出来
}
printf("\n");
}
}
void clear(stack
ps)
{
node
p = ps->top,q=NULL;
while (p!=ps->bottom)
{
q = p;
p = p->next;
free(q);//知道q指向栈底指针的上一个数据元素(就相当于那个无用的头节点)
//不用将p指向NULL,因为p还要指向下一个有数据的节点(即将被删除的)
}
ps->top = ps->bottom;//注意最后还要将栈顶指针置为栈底指针的地址
//让他们指向同一块内存区域
printf(“栈已经被清空\n”);
}
void calculate(stack
ps)
{
node* p = ps->top;
//我们为什么要将栈顶指针赋值给一个变量
//因为我们只是单纯的计算栈的长度,是不允许修改栈的栈顶指针和栈顶指针的指向的
int count = 0;
while (p!=ps->bottom)//注意不能用栈是否为空来表示,
//因为用栈是否为空的条件来表示的话,栈顶指针永远不会移动
{
count++;
p = p->next;
}
printf(“栈的长度尾%d\n”, count);
}

/*注意链栈中一般是不会出现栈满的情况的,因为它是通过指针来指向的,改变指针的指向就可以进行插入和删除元素等操作,可以通过动态分配内存来给增加的元素分配内存空间,所以一般情况下是不会发生栈满的情况的,如果这种情况发生,那么内存中的空间就一定不够了,电脑也会面临卡顿死机的状况了!

但是对于线性存储结构,是利用数组来存放的,由于数组是预先就分配好空间的,所以就会存在栈满的情况。

所以我们在用线性存储结构的时候通常会有一个检验栈满的操作,但是在链式存储结构中就没有*/

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值