数据结构初阶:栈

发布于:2025-04-15 ⋅ 阅读:(25) ⋅ 点赞:(0)

本篇博客主要介绍栈的概念与结构等内容。

1.栈

1.1 概念与结构

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

压栈:栈的插入操作叫作进栈/压栈/入栈,入数据在栈顶。

出栈:栈的删除操作叫作出栈。出数据也在栈顶。

栈底层结构选型 

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

1.2 栈的实现

Stack.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>


//定义栈的结构
typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;      //指向栈顶的位置
	int capacity; //容量
}ST;

void STInit(ST* ps);
void STDestroy(ST* ps);


//入栈---栈顶
void StackPush(ST* ps, STDataType x);
//出栈---栈顶
void StackPop(ST* ps);
//取栈顶数据
STDataType StackTop(ST* ps);

bool StackEmpty(ST* ps);
//获取栈中有效元素个数
int STSize(ST* ps);
1.3  定义栈的结构
//定义栈的结构
typedef int STDataType;
typedef struct Stack
{
	STDataType* arr;
	int top;      //指向栈顶的位置
	int capacity; //容量
}ST;

代码逻辑:

首先,通过typedef定义了一个整数类型STDataType,这里实际上是将int类型取了一个别名STDataType

然后,定义了一个结构体Stack,这个结构体包含了三个成员:

  • STDataType* arr:一个指向整数类型的指针,用于存储栈的元素。
  • int top:用于指向栈顶的位置。
  • int capacity:表示栈的容量。
1.4  栈的初始化
void STInit(ST* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

代码逻辑: 

函数的参数是一个指向ST结构体的指针ps。在函数内部,将结构体中的成员进行了如下初始化:

  • ps->arr被初始化为NULL,表示栈的元素数组为空。
  • ps->topps->capacity都被初始化为0,分别表示栈顶位置和栈的容量为0

这样,通过调用这个函数,可以将一个栈结构体初始化为一个空栈的状态。

1.5 栈的销毁 
void STDestroy(ST* ps)
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

 代码逻辑:

函数的参数是一个指向ST结构体的指针ps。在函数内部,进行了以下操作:

首先,检查ps->arr是否不为NULL。如果不为NULL,则使用free函数释放ps->arr所指向的内存空间,以避免内存泄漏。

然后,将ps->arr再次设置为NULL,并将ps->topps->capacity都设置为0,将栈结构体的相关成员恢复到初始状态。

这样,通过调用这个函数,可以释放栈所占用的内存资源,并将栈结构体的成员进行清理和重置。

1.6 入栈
//入栈----栈顶
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		//空间不够---增容
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}

代码逻辑: 

用于实现向栈中入栈的操作。

函数的参数包括一个指向栈结构体的指针ps和一个要入栈的元素x

在函数内部,首先使用assert函数检查ps是否有效。然后,通过判断栈顶位置ps->top是否等于栈的容量ps->capacity来确定是否需要进行扩容操作。

如果需要扩容,会根据当前容量的情况计算新的容量(如果当前容量为0,则新容量为4;否则新容量为当前容量的2倍),然后使用realloc函数对栈的元素数组进行扩容。如果扩容失败(tmpNULL),则会输出错误信息并退出程序。

如果空间足够,直接将元素x放入栈顶位置(ps->arr[ps->top] = x),然后将栈顶位置加1ps->top++)。

总的来说,这个函数实现了在栈空间不足时进行自动扩容,并将元素成功入栈的功能。

 1.7 判空和出栈
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

//出栈----栈顶
void StackPop(ST* ps)
{
	assert(!StackEmpty(ps));
	--ps->top;
}

代码逻辑: 

  • bool StackEmpty(ST* ps)这个函数用于判断栈是否为空。它首先使用assert函数检查ps是否有效,然后通过判断栈顶位置ps->top是否为0来确定栈是否为空。如果ps->top0,则表示栈为空,函数返回true;否则,函数返回false
  • void StackPop(ST* ps)这个函数用于实现出栈操作。它首先使用assert函数和StackEmpty函数来检查栈是否为空,如果栈为空则会产生断言错误。如果栈不为空,那么将栈顶位置ps->top1,实现出栈操作。
 1.8 取栈顶数据
//取栈顶数据
STDataType StackTop(ST* ps)
{
	assert(!StackEmpty(ps));
	return ps->arr[ps->top - 1];
}
1.9  获取栈中数据有效个数
//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

代码逻辑:

函数的参数是一个指向栈结构体的指针 ps 。在函数内部,首先使用 assert 函数检查 ps 是否有效。然后,直接返回栈顶位置 ps->top 的值,将其作为栈中有效元素的个数。因为栈顶位置的值就表示了栈中当前元素的数量。

 2.源代码(Stack.c)

#define _CRT_SECURE_NO_WARNINGS
#include"Stack.h"

void STInit(ST* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
void STDestroy(ST* ps)
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//入栈----栈顶
void StackPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		//空间不够---增容
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}


bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

//出栈----栈顶
void StackPop(ST* ps)
{
	assert(!StackEmpty(ps));
	--ps->top;
}
//取栈顶数据
STDataType StackTop(ST* ps)
{
	assert(!StackEmpty(ps));
	return ps->arr[ps->top - 1];
}
//获取栈中有效元素个数
int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

3.小结 

 以上便是本篇博客的所有内容,如果诸君学到知识的话,还请诸君点点赞,支持博主。