数据结构-栈

大家好,今天带来的是关于数据结构初阶中的栈和队列的内容,一起来看看吧!!!

1.栈的概念

  • 栈:一种特殊的线性表 ,其只允许在固定的一端 进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
  • 入栈:栈的插入叫做入栈/压栈/进栈,入数据在栈顶。
  • 出栈:栈的删除叫做出栈,出数据也在栈顶。

类比:只有一端开口的羽毛球桶

2.栈的实现

栈的实现一般可以用数组或链表实现,相较而言,数组的结构实现更优一点,因为数组在尾上插入数据的代价比较小。因此,以下用数组实现栈。

2.1初始化和销毁

初始化的一个难题就是top的赋值问题,以及对应的哪种情况。

分两种情况,采用假设法+画图,很快就能理解!

1.top=-1,假设入栈一个数据1后,top++,此刻top=0,栈顶数据为1,在数组中a0表示数组首元素,即top指向栈顶数据。

2.top=0,假设入栈一个数据1后,top++,此刻top=1,栈顶数据为a0, a1表示数组第二个数据,即top指向栈顶数据的下一个数据。

考虑到我想用top代表有效数据个数,因此我这里用的是方法2,令ps->top=0,top指向的是栈顶数据的下一个数据,也同时代表了栈内数据个数。


2.2入栈

之前我们学习了有关顺序表的知识,这里的代码理解起来就很容易了。

插入数据之前,要判断当前内存是否足够,若不够,要扩容。

2.3出栈

出栈就是删除元素,因为栈内数据只能从栈顶入,栈顶出。所以,出栈一次,只用删除一次栈顶数据即可。

2.4获取栈顶元素

之前初始化根据我的赋值是:top=0;因此top指向的是栈顶元素的下一个数据。那么要获取栈顶元素,就是获取top的前一个元素,也就是ps->atop-1.

2.5获取栈有效元素个数

之前根据初始化赋值我的设置,令top=0,因此top也恰好代表了栈中的有效数据个数。

故直接返回ps->top即可。

2.6判空

复制代码
当栈为空时,表示栈中没有任何元素。当栈非空时,表示栈中至少有一个元素。
因此只需要判断栈中有效数据个数是否不为0即可。
这里1 0 我们想到了用bool函数来表示。

3.总结

写到这里,我们就实现了一个栈,有了前面顺序表的基础,是不是感觉代码写起来还是比较简单的。这里给出总代码。

3.1 test.c

cpp 复制代码
//test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include"Stack.h"

int main()
{
	ST ps;

	STInit(&ps);
	STPush(&ps, 1);
	STPush(&ps, 2);
	STPush(&ps, 3);
	STPush(&ps, 4);
	//printf("%d\n",STTop(&ps));
	
	//访问栈中所有元素
	while (!STEmpty(&ps))
	{
		printf("%d ", STTop(&ps));
		STPop(&ps);
	}

	STDestroy(&ps);
	return 0;
}

3.2 Stack.c

cpp 复制代码
//Stack.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

//初始化 
void STInit(ST* ps)
{
	assert(ps);
	ps->a = NULL;
	ps->capacity = 0;

	ps->top = 0;//top指向栈顶的下一个数据,可画图理解

	//ps->top=-1;//top指向栈顶数据,画图理解
}


//销毁
void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = ps->capacity = 0;
}


//入栈
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	//插入之前判断内存够不够
	if (ps->top == ps->capacity)
	{
		//扩容
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDataType* tmp =(STDataType*) realloc(ps->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
		}
		ps->a = tmp;
		ps->capacity = newcapacity;
	}

	//插入数据
	ps->a[ps->top]=x;//根据初始化阶段,我这里的top指向的是栈顶数据的下一个数据,因此直接插入数据即可
	ps->top++;
}

//出栈
void STPop(ST* ps)
{
	assert(ps);
	ps->top--;
}

//获取栈顶元素
STDataType STTop(ST* ps)
{
	assert(ps);
	assert(ps->top > 0);

	return ps->a[ps->top - 1];
}

//获取栈中有效数据个数
int STSize(ST* ps)
{
	assert(ps);

	return ps->top - 1;
}

//判空
bool STEmpty(ST* ps)
{
	assert(ps);

	return ps->top == 0;
	//等价于
	/*if(ps->top==0)
	{
		return true;
	}
	else
	{
		return false;
	}*/
}

3.3 Stack.h

cpp 复制代码
//Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

//定义一个动态的栈
typedef int STDataType;

typedef struct Stack
{
	STDataType* a;
	int top;//栈顶
	int capacity;//容量
}ST;

//初始化
void STInit(ST* ps);//传的参数是结构体指针,指向栈
//销毁
void STDestroy(ST* ps);
//入栈
void STPush(ST* ps, STDataType x);//传的参数是结构体指针和数据
//出栈
void STPop(ST* ps);//传的参数是结构体指针和数据
//获取栈顶元素
STDataType STTop(ST* ps);//栈中元素的类型是STDataType,所以函数返回值的数据类型是STDataType
//获取栈中有效数据个数
int STSize(ST* ps);
//判空
bool STEmpty(ST* ps);

以上就是数据结构中栈的有关内容,谢谢观看!

相关推荐
峥嵘life7 小时前
Android16 311Y3 EAP-TLS 网络连接失败分析与修复总结
android·开发语言·人工智能·php
M-Robots echo7 小时前
轻量化裁剪方案解析:M-Robots 模块化构建,适配高低端各类机器人硬件平台
java·机器人·ros·开源社区·atomgit·m-robots
不可求~8 小时前
多模型路由怎么落地:把任务分流写进项目的最小实现
java·前端·数据库
Kapaseker8 小时前
破坏性更新 - 解读 Jetpack Compose 1.12
android·kotlin
雨白9 小时前
我的 UML 学习笔记:结合 Android 实例看懂 4 种常用图表
android·架构
mldong9 小时前
用 DDD 设计工作流引擎:聚合根与充血模型
java·架构
怣疯knight9 小时前
快速判断apk有没有支持16kb页面标准
android
风流 少年10 小时前
Spring AI 2.0:Advisor
android·人工智能·spring
mqiqe10 小时前
AgentScope Java Harness:4. 双层记忆系统 让 Agent 拥有真正的“长期大脑“
java·开发语言
伍一5110 小时前
03-文件管理模块-一个看似简单的模块藏着多少细节
java·ruoyi·若依