栈的简单理解

顺序栈

  • 数据结构(c语言)
  • 基本概念
  • 常见操作

基本概念:

栈stack是限定只在表尾进行插入和删除操作的线性表

栈stack是一种LIFO(后进先出)或者说FILO(先进后出)的结构,可以想象成一叠摆放好的餐盘,最上面的餐盘是最后放上去的但是要最先拿出来。

顺序栈有两种定义方式,分别是

typedef struct
{Selemtype data[MAXSIZE];
  int top;
}SqStack;

typedef struct
{Selemtype *bottom;
  Selemtype*top;
  int stack_size;

}SqStack;

提问:最先入栈的一定最后出栈吗?
让1 2 3三个数字按照大小顺序入栈,则出栈的顺序可能会
①1 2 3(入1出1,入2出2,入3出3);
②1 3 2 (入1 出1,入2、3出3 、2)
③2 3 1(入1、2出2,入3出3)
④2 1 3(入1、2出2、1)
⑤3 2 1
所以最先入栈的不一定是最后出栈的,因为不一定一次就把所有元素入栈,有可能出现入栈出栈交错进行的这种状况

常见操作:
栈本身是一种线性表,所以它的实现分为顺序栈(基于顺序表),和链栈(基于链表)。常见的操作有
1判空、判满
第一种

empty_sqstack(SqStack*p)
{
    if(p->top==-1)
        printf("\n此栈为空\n");
    else
        printf("\n此栈不空\n");
}

full_sqstack(SqStack*p)
{
    if(p->top==MAXSIZE-1)
        printf("栈满");
}

思考题

怎么理解判空条件

一般认为p->top= =n,就是p[n]存在,p的数组里面最小下标是p->top==0,所以没有元素就初始化为-1,判空条件也因此是-1;

第二种

empty_sqstack(SqStack*p)
{
    if(p->bottom==p->top)
        printf("\n此栈为空\n");
    else
        printf("\n此栈不空\n");
}

full_sqstack(SqStack*p)
{
    if(p->top-(p->bottom)==p->stack_size)
        printf("栈满");
}

思考题
为什么判满条件不是为什么这里不是p->top-(p->bottom)==p->stack_size-1?(明明->stack_size-1才是它们之间的元素间隔个数呀)

栈的最后一个元素是*(p->top-1),也就是说最后一位元素的下一位才是top指针

2压栈(push)
线性表的表尾称为栈顶,压栈(插入元素)和出栈(删除元素)都是发生在栈顶。

第一种

push(SqStack*p)
{ Selemtype e;
    printf("请输入压栈的元素:姓名 学号");
   scanf("%s %d",e.name,&(e.stu_num));
    p->data[++p->top]=e;

}

第二种

push(SqStack*p)
{ Selemtype e;
    printf("请输入压栈的元素:姓名 学号");
   scanf("%s %d",e.name,&(e.stu_num));
    *(++p->top)=e;

}

3出栈(pop)

第一种

pop(SqStack*p,Selemtype*e )
{
    *e=p->data[p->top--];
}

第二种

Selemtype pop(SqStack*p)
{Selemtype e;
    e=*((p->top)--);
    return e;
}

思考题(总代码在最后)

为什么代码块换成

pop(SqStack*p,Selemtype*e )
{
    e=(p->top)--;
}
···
int main()
{···
pop(&st,&b);
···}

输出的弹栈结果是
在这里插入图片描述
但真实结果应该是
在这里插入图片描述

答案:(暂时没想到答案)
2019.10.19:两个指针之间只能够进行值的赋值,因为指针本身表示储存空间的位置,如果对指针进行赋值可能会出现两个储存空间不同,但是在系统中表示地址的值一样的错误,所以不能够对指针本身赋值(猜想)。
4总代码
第一种建栈方式代码

整形数组的栈使用方法

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef int Selemtype;
typedef struct/*注释1:栈的顺序表结构这里是利用静态数组,所以也就不需要分配内存空间,但是,如果这里不是一个int数组呢,是否需要分配内存空间?*/
{Selemtype data[MAXSIZE];/*注释2:在链表,动态数组里面都有一个指针,我猜这里的数组也可以换成指针*/
  int top;/*注释3:用于data->top表示栈顶,也就是所谓的栈顶指针*/
}SqStack;
init_sqstack(SqStack*p)
{
    p->top=-1;/*注释4:一般认为p->top==n,就是p[n]存在,p的数组里面最小下标是p->top==0,所以没有元素就初始化为-1;*/
}
empty_sqstack(SqStack*p)
{
    if(p->top==-1)
        printf("\n此栈为空\n");
    else
        printf("\n此栈不空\n");
}
full_sqstack(SqStack*p)
{
    if(p->top==MAXSIZE-1)
        printf("栈满");
}
pop(SqStack*p,int*e )
{
    *e=p->data[p->top--];
}
push(SqStack*p,int *e)//注释5:这里第二个形参可以是int e,但是必须有返回值。但是也可以直接传入e的地址
{p->data[++p->top]=*e;//注释6:i++返回i的值,++i返回i+1之后的值;
}
print(SqStack*p)
{
    while(p->top!=-1)
        printf("\n%d",p->data[p->top--]);
}
int main()
{
int a=100,b=99;/*注释7:a用来压栈,b用来弹栈*/
SqStack st={{1,2,3,4},3};/*注释8:top其实是数组的下角标,所以这里的值是3;*/
//print(&st);注释9
//init_sqstack(&st);注释10
/*注释11:以上两个注释让我明白了①见思考题1②st类型的数据在定义的时候就已经给赋值,所以这里的init_sqstack并没有实际的作用*/
empty_sqstack(&st);
push(&st,&a);
printf("压栈后栈顶元素为:%d",st.data[st.top]);
pop(&st,&b);
printf("\n打印依次出栈的元素");
printf("\n");
print(&st);
printf("\nb的值是:%d\n",b);//注释12:栈的缺点,他只能够全部直接输出栈内的元素只一次,如果要输出多次的话就只能事先存储好st->top值的大小
}

结果图:结果图
思考题
1
如果注释9去掉//和"注释9"字样,栈会正常输出吗?
不会,因为输出之后st->top==-1,然而后续的弹栈,压栈操作又会对st->top进行增减,所以实际的结果就输出无限循环(请实操)

2
结合注释12,思考能不能将print函数变成这样,以便实现注释9中不能够多次输出的问题?

print(SqStack*p)
{ int i;
i=p->top;
    while(i!=-1)
        printf("\n%d",p->data[i--]);
}

最开始以为:这样能够避免栈只能够输出一次的这个缺点(()伦家想要输出多少次都可以实操啦)
然而:这是一个栈不是一个数组,栈里面的元素当然只能够出一次。而且p->top表示的栈顶指针,如果像上面的代码块一样实施,p->top的值始终都是3,出栈这个操作也就名不副实了。

为了解决注释1中能否分配空间问题,写了如下代码:
结构体数组的栈使用方法

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef struct
{char name[3];
int stu_num;
}Selemtype;
typedef struct
{Selemtype *data;/*注释1:在链表,动态数组里面都有一个指针,这里的数组也可以换成指针*/
  int top;

}SqStack;
init_sqstack(SqStack*p)
{
    p->top=-1;
   p->data=(Selemtype*)malloc(MAXSIZE*sizeof(Selemtype));/*注释2:初始化的时候进行分配空间和栈顶指针赋值*/
}
empty_sqstack(SqStack*p)
{
    if(p->top==-1)
        printf("\n此栈为空\n");
    else
        printf("\n此栈不空\n");
}
full_sqstack(SqStack*p)
{
    if(p->top==MAXSIZE-1)
        printf("栈满");
}
pop(SqStack*p,Selemtype*e )
{
    *e=p->data[p->top--];
}
push(SqStack*p)
{ Selemtype e;
    printf("请输入压栈的元素:姓名 学号");
   scanf("%s %d",e.name,&(e.stu_num));
    p->data[++p->top]=e;

}
print(SqStack*p)
{
      for(;p->top>=0;p->top--)
        printf("\n%s %d\n",p->data[p->top].name,p->data[p->top].stu_num);
}
int main()
{
Selemtype b;
SqStack st;//={{1,2,3,4},3}
//print(&st);
init_sqstack(&st);
printf("%d\n",st.top);
while(st.top<3)
{
 push(&st);
}/*注释3:想压栈3个既定元素*/
empty_sqstack(&st);
push(&st);/*注释4:再输入一个元素进行压栈,这一步很无聊,也可以直接忽略*/
pop(&st,&b);
printf("输出");
print(&st);
printf("被弹栈的元素是");
printf("\n%s %d\n",b.name,b.stu_num);
}


结果图在这里插入图片描述
思考题:
如果将注释1前的代码Selemtype *data;变成Selemtype data[5];即将指针变成一个结构体数组那么

   scanf("%s %d",e.name,&(e.stu_num));

还能够正常编译出吗?
不行
不能够直接在指针没有指向的基础上进行赋值,或者malloc一类的运算。
2019.10.19
否定原因:如果是指针没有指向的问题的话换成Selemtype *data后传入pop函数的还是st的地址,指针依旧没有确切的指向?
依旧没有答案

第二种建栈方式代码

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef struct
{char name[3];
int stu_num;
}Selemtype;
typedef struct
{Selemtype *bottom;
  Selemtype*top;
  int stack_size;

}SqStack;
init_sqstack(SqStack*p)
{
   p->bottom=(Selemtype*)malloc(MAXSIZE*sizeof(Selemtype));/*注释2:初始化的时候进行分配空间和栈顶指针赋值*/
   p->top=p->bottom;
   p->stack_size=MAXSIZE;
}
empty_sqstack(SqStack*p)
{
    if(p->bottom==p->top)
        printf("\n此栈为空\n");
    else
        printf("\n此栈不空\n");
}
full_sqstack(SqStack*p)
{
    if(p->top-(p->bottom)==p->stack_size)/*注释1:为什么这里不是=p->stack_size+1,猜想:链表的最后一个元素是*(p->top-1),也就是说最后一位元素的下一位才是top指针,这也就解释了为什么没有给top开辟空间*/
        printf("栈满");
}
Selemtype pop(SqStack*p )
{
    Selemtype e;
    e=*(p->top--);
    return e;
}
push(SqStack*p)
{ Selemtype e;
    printf("请输入压栈的元素:姓名 学号");
   scanf("%s %d",e.name,&(e.stu_num));
    *(++p->top)=e;

}
print(SqStack*p)
{
      for(;p->top>p->bottom;p->top--)
        printf("\n%s %d\n",p->top->name,p->top->stu_num);
}
int main()
{
Selemtype b;
SqStack st;//={{1,2,3,4},3}
//print(&st);
init_sqstack(&st);
while(st.top-st.bottom<3)
{
 push(&st);
}/*注释3:想压栈3个既定元素*/
empty_sqstack(&st);
push(&st);/*注释4:再输入一个元素进行压栈*/
b=pop(&st);
printf("输出");
print(&st);
printf("被弹栈的元素是");
printf("\n%s %d\n",b.name,b.stu_num);
}

结果图
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值