您现在的位置是:首页 >技术交流 >顺序栈的入栈与出栈-----(c语言)网站首页技术交流

顺序栈的入栈与出栈-----(c语言)

吃椰子不吐壳 2023-07-11 16:00:02
简介顺序栈的入栈与出栈-----(c语言)

栈:是限定仅在表尾进行插入和删除操作的线性表(顺序结构)

栈顶:允许插入跟删除的一端

栈底:固定的一端,不允许在栈底进行插入跟删除

入栈:栈的插入操作

出栈:栈的删除操作


目录

定义栈

创建空栈

 入栈

 出栈

 源代码


定义栈


#include<stdio.h>
#include<malloc.h>
#define ok 1
#define error 0
#define sizemax 10
typedef int ElemType;

typedef struct {
	ElemType *base;//栈底
	ElemType *top;//栈顶
	int sizestack;//分配栈的值
}Sqstack;//定义栈

此处定义栈的最大值为10,当然如果需要后续分配更大的内存空间,可以使用realloc函数增加新的空间(作者还没学会使用)。


创建空栈

int initstack(Sqstack* s) {
	s->base = (ElemType*)malloc(sizeof(ElemType) * SIZEMAX);//给base分配内存空间,返回base的首地址
	if (!s->base) {
		return error;
	}
	s->top = s->base;//出发点为base的首地址,栈顶从底地址开始
	s->sizestack = SIZEMAX;//最大空间
	return ok;
}//创建空栈

创建空栈,就需要给栈底分配一块内存空间,将栈底的首地址返回,就可以通过栈底首地址对栈进行修改。所以将栈底的首地址赋值给栈底(s->top),就可以对栈底进行修改了。

图解:

值得注意的是,栈底的首地址不一定是从0开始的,而是这里为了方便图片的展示而写成0。由于用了malloc函数,编译器给s->base的地址是随机分配的,如果需要查看真正的地址,可以调试监控窗口查看。


 入栈

int push(Sqstack* s, ElemType e) {
	if (s->top - s->base == SIZEMAX ) {
		printf("栈满,无法入栈
");
		return error;
	}
	*(s->top) = e;//(由于s是指针,想要将里面的值赋值,需要带上*号)
	s->top++;
	
	return ok;
}//入栈

入栈前首先要判断栈是否满了,这里可以用s->top-s->base的值判断是否满了(地址的分配原理),将输入的值赋值给栈顶,用指针对地址里面的值修改,必须要用上星号(指针的原理)。那么问题就来了,是先插入在进行栈顶指针的自增呢,还是先栈顶指针自增在插入呢?动动小脑袋瓜来思考一下,在定义栈的时候,博主将栈底的地址赋值给栈顶指针,入栈时,将e的值赋值给此处栈顶指针,如果先进行指针自增,那么执行到插入时,他后面的那一个空栈就会跳过了,此时插入的空间是自增后的那个空间,造成空间浪费,不理解的同学可以上机实践,看看调换这个语句的顺序会发生什么。

 正确的做法是先插入,栈顶指针在自增。


 出栈

int pop(Sqstack* s, ElemType *e) {
	if (s->top == s->base) {
		return error;
	}
	s->top--;//先--是因为输入的最后一个值是非整形的,需要忽略非整形的字符
	*e = *(s->top);
	
	return ok; 
}//出栈

出栈前要判断栈是否为空,判断条件是s->top=s->base                                                                     在动动小脑瓜思考,这里为什么又要先栈顶指针自减在赋值给*e,这就涉及到另一个模块的代码了

int creatstack(Sqstack* s) {
	int e;
	if (initstack(s)) {
		printf("栈创建成功!
");
	}
	else {
		printf("栈创建失败
");
		return error;
	}
	printf("请输入数据
");
	while (scanf("%d", &e)) 
		push(s, e);

		return ok;
}//创建并输入

在这个函数中,我们调用创建栈的函数,创建成功后进行入栈操作

while (scanf("%d", &e)) 
		push(s, e);

我们使用scanf输入要入栈的值,由于我们定义的是整形,输入的也是整形,这里介绍一下scanf的返回值,是成功读入参数的个数,我们都知道,判定条件,0为假,非0为真。当输入多组整数时,按下回车后,这些整数会进入缓冲区中,然后scanf函数会一个个读取缓冲区中的数据,当读取到一个整数时返回值是1,当读到非整数的值时,返回值是0,因此在while中,想要让这个输入循环停止,就要输入一个非整数的值,比如字母a,但是在入栈的时候,输入非整数的值仍然会保持在栈中,因此在出栈中,要错开这个值,所以在出栈函数中,首先要栈顶指针先自减,在将栈存储的值赋值给指针*e。

如果先赋值在自减出栈时就会造成如下错误:

 输出了非整数的值,并且还造成了栈里面的内容丢失

 正确操作是先自减在赋值:

 图解:


 源代码


#include<stdio.h>
#include<malloc.h>
#define ok 1
#define error 0
#define SIZEMAX 10
typedef int ElemType;

typedef struct {
	ElemType *base;//栈底
	ElemType *top;//栈顶
	int sizestack;//分配栈的值
}Sqstack;//定义栈

int initstack(Sqstack* s) {
	s->base = (ElemType*)malloc(sizeof(ElemType) * SIZEMAX);//给base分配内存空间,返回base的首地址
	if (!s->base) {
		return error;
	}
	s->top = s->base;//出发点为base的首地址,栈顶从底地址开始
	s->sizestack = SIZEMAX;//最大空间
	return ok;
}//创建空栈

int push(Sqstack* s, ElemType e) {
	if (s->top - s->base == SIZEMAX ) {
		printf("栈满,无法入栈
");
		return error;
	}
	*(s->top) = e;//(由于s是指针,想要将里面的值赋值,需要带上*号)
	s->top++;
	
	return ok;
}//入栈

int pop(Sqstack* s, ElemType *e) {
	if (s->top == s->base) {
		return error;
	}
	s->top--;//先--是因为输入的最后一个值是非整形的,需要忽略非整形的字符
	*e = *(s->top);
	
	return ok; 
}//出栈

int creatstack(Sqstack* s) {
	int e;
	if (initstack(s)) {
		printf("栈创建成功!
");
	}
	else {
		printf("栈创建失败
");
		return error;
	}
	printf("请输入数据
");
	while (scanf("%d", &e)) 
		push(s, e);

		return ok;
}//创建并输入

int printstack(Sqstack* s) {
	ElemType e;
	while (pop(s, &e)) 
		printf("%3d", e);

		return ok;
}//出栈并且输出

int main() {
	Sqstack s;
	printf("创建并输出
");
	creatstack(&s);
	printf("出栈并且输出
");
	printstack(&s);

	return 0;
}

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。