栈的实现详解

目录

  • [1. 栈](#1. 栈)
    • [1.1 栈的概念及结构](#1.1 栈的概念及结构)
    • [1.2 栈的实现方式](#1.2 栈的实现方式)
    • [1.3 栈的应用场景](#1.3 栈的应用场景)
  • [2. 栈的实现](#2. 栈的实现)
    • [2.1 结构体](#2.1 结构体)
    • [2.2 初始化](#2.2 初始化)
    • [2.3 销毁](#2.3 销毁)
    • [2.4 入栈](#2.4 入栈)
    • [2.5 出栈](#2.5 出栈)
    • [2.6 获取栈顶元素](#2.6 获取栈顶元素)
    • [2.7 判空](#2.7 判空)
    • [2.8 获取个数](#2.8 获取个数)
  • [3. test主函数](#3. test主函数)
  • [4. Stack.c文件](#4. Stack.c文件)
  • [5. Stack.h文件](#5. Stack.h文件)
  • [6. 运行展示](#6. 运行展示)

1. 栈

1.1 栈的概念及结构

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

1.2 栈的实现方式

栈可以通过多种方式实现,包括数组和链表等。使用数组实现的栈具有连续的内存空间,操作效率较高;而使用链表实现的栈则更加灵活,可以在动态环境中调整栈的大小。



实现用的是数据栈。

1.3 栈的应用场景

函数调用:在计算机程序中,函数调用和返回的过程可以用栈来实现。当调用一个函数时,会将函数的返回地址和参数压入栈中;当函数返回时,会从栈中弹出这些信息,并返回到调用点继续执行。

浏览器的前进与后退:在浏览器中,可以使用两个栈来实现前进和后退功能。一个栈记录新访问的页面,另一个栈记录后退弹出的页面。当用户点击前进按钮时,从记录新访问页面的栈中弹出页面;当用户点击后退按钮时,从记录后退页面的栈中弹出页面。

表达式求值:在编译器中,可以使用栈来进行表达式的求值。将运算符和操作数压入栈中,并根据运算符的优先级和结合性进行出栈和计算操作,最终得到表达式的值。

2. 栈的实现

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

2.1 结构体

首先要先把结构体定义出来,一个是数组栈,一个是指向栈顶元素的下一个,还有一个是增容。

javascript 复制代码
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//指向栈顶元素的下一个
	int capaicty;
}ST;

2.2 初始化

top等于0指向栈顶元素的下一个位置,top等于-1指向栈顶元素

javascript 复制代码
//初始化
void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	//pst->top = -1;//指向栈顶元素
	pst->top = 0;//指向栈顶元素的下一个位置
	pst->capaicty = 0;
}

2.3 销毁

防止造成野指针的错误

javascript 复制代码
//销毁
void STDestroy(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->top = 0;
	pst->capaicty = 0;
	free(pst->a);
}

2.4 入栈

先判断容量是否够,再实现动态增容。

javascript 复制代码
//入栈
void STPush(ST* pst, STDataType x)
{
	//扩容
	if (pst->top == pst->capaicty)
	{
		int newCapaicty = pst->capaicty = 0 ? 4 : pst->capaicty * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapaicty * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("STPush");
			return;
		}

		pst->a = tmp;
		pst->capaicty = newCapaicty;
	}

	pst->a[pst->top] = x;
	pst->top++;
}

2.5 出栈

看栈是否空,不是空就不能删,再top减减就行

javascript 复制代码
//出栈
void STPpo(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));

	pst->top--;
}

2.6 获取栈顶元素

因为top指向栈顶元素的下一个,所以top要减1,当然空的时候也要判断一下

javascript 复制代码
//获取栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));

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

2.7 判空

javascript 复制代码
//判空
bool STEmpty(ST* pst)
{
	assert(pst);

	return pst->top == 0;
}

2.8 获取个数

打印之前可以看还有多少个在栈中

javascript 复制代码
//获取个数
int STsize(ST* pst)
{
	assert(pst);

	return pst->top;
}

3. test主函数

javascript 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include "Stack.h"

void TestStack1()
{
	ST st;
	STInit(&st);
	STPush(&st, 1);
	STPush(&st, 2);
	printf("%d ", STTop(&st));
	STPpo(&st);
	STPush(&st, 3);
	STPush(&st, 4);
	printf("size: %d\n", STsize(&st));
	
	//打印
	while (!STEmpty(&st))
	{
		printf("%d ", STTop(&st));
		STPpo(&st);
	}

	STDestroy(&st);
}

int main()
{
	TestStack1();
	return 0;
}

4. Stack.c文件

javascript 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "Stack.h"


//初始化
void STInit(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	//pst->top = -1;//指向栈顶元素
	pst->top = 0;//指向栈顶元素的下一个位置
	pst->capaicty = 0;
}

//销毁
void STDestroy(ST* pst)
{
	assert(pst);

	pst->a = NULL;
	pst->top = 0;
	pst->capaicty = 0;
	free(pst->a);
}

//入栈
void STPush(ST* pst, STDataType x)
{
	//扩容
	if (pst->top == pst->capaicty)
	{
		int newCapaicty = pst->capaicty = 0 ? 4 : pst->capaicty * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newCapaicty * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("STPush");
			return;
		}

		pst->a = tmp;
		pst->capaicty = newCapaicty;
	}

	pst->a[pst->top] = x;
	pst->top++;
}

//出栈
void STPpo(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));

	pst->top--;
}

//获取栈顶元素
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(!STEmpty(pst));

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

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

	return pst->top == 0;
}

//获取个数
int STsize(ST* pst)
{
	assert(pst);

	return pst->top;
}

5. Stack.h文件

javascript 复制代码
#pragma once
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;//指向栈顶元素的下一个
	int capaicty;
}ST;

//初始化
void STInit(ST* pst);

//销毁
void STDestroy(ST* pst);

//入栈
void STPush(ST* pst, STDataType x);

//出栈
void STPpo(ST* pst);

//获取栈顶元素
STDataType STTop(ST* pst);

//判空
bool STEmpty(ST* pst);

//获取个数
int STsize(ST* pst);

6. 运行展示

相关推荐
jmlinux16 分钟前
环形缓冲区(Ring Buffer)在STM32 HAL库中的应用:防止按键丢失
c语言·stm32·单片机·嵌入式硬件
无情大菜刀2 小时前
C# 雷赛运动控制器 SMC304 新建工程
c#
TU^2 小时前
C语言习题~day16
c语言·前端·算法
DdddJMs__1352 小时前
C语言 | Leetcode C语言题解之第461题汉明距离
c语言·leetcode·题解
中杯可乐多加冰2 小时前
【AI驱动TDSQL-C Serverless数据库技术实战】 AI电商数据分析系统——探索Text2SQL下AI驱动代码进行实际业务
c语言·人工智能·serverless·tdsql·腾讯云数据库
代码雕刻家9 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
IT良10 小时前
c#增删改查 (数据操作的基础)
开发语言·c#
yufei-coder10 小时前
掌握 C# 中的 LINQ(语言集成查询)
windows·vscode·c#·visual studio
Kalika0-011 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法