【数据结构——栈】

目录

一、栈

1.栈的概念

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

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

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

2.栈的实现选择

数组、单链表、双向链表都能实现栈

数组实现:

优点:内存连续,CPU缓存命中率高,访问速度更快

缺点:扩容不便,存在内存拷贝开销

单链表:

优点:无扩容消耗,更节省空间

缺点:内存分散,缓存效率低;仅支持单向遍历,好入数据,但是不好出数据

双向链表:

优点:支持双向遍历,底层结构易于拓展为双端队列

缺点:需要维护的指针较多,内存开销大,指针维护逻辑复杂

考虑到扩容自身也会有消耗,并且存在同地和异地扩容不同的问题,因此数组扩容缺点的影响对于栈的实现其实很小。相对于单链表来说数组的高速缓存效率更高,且双向链表栈只在一端操作,前驱指针闲置,性价比低。因此下面我们采用数组来实现栈

二、栈的实现

我们采用头文件、源文件、测试文件多文件的形式来实现栈

1.头文件

(1)所需的头文件

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>//断言所需头文件

(2)栈的定义

静态:

预先定义固定大小数组,容量固定,极易溢出

c 复制代码
#define N 10
struct Stack
{
	int a[N];
};

动态:

使用realloc动态扩展,容量自动增长,更灵活

c 复制代码
typedef int STDataType;//便于替换数据类型
typedef struct Stack
{
	STDataType* a;//指向栈的指针
	int top;//指向栈顶的变量
	int capacity;//当前数组总容量
}ST;//重命名

2.源文件

(1)初始化

这里的主要思路是将栈传址(因为要对栈进行修改),判断传入指针是否为空,对指向栈的指针、指向栈顶的变量、初始空间大小进行初始化

对指向栈的指针进行初始化:

  1. 方式一:用malloc先开辟一块空间,再让a指向它
  2. 方式二:先不开,a指向NULL

对top的初始化:

这里也有两种方式:

  1. 指向栈顶元素,无元素时为-1
  2. 指向最后一个栈顶元素的下一个位置,无元素时为0
c 复制代码
void STInit(ST* pst)
{
	assert(pst);//传入指针不得为空
	pst->a=NULL;
	pst->top=0;//top指向栈顶元素的下一个位置
	//pst->top=-1; top指向栈顶数据
	pst->capacity=0;
}

(2)销毁

c 复制代码
void STDestroy(ST* pst)
{
	assert(pst);//判断传入指针是否为空
	free(pst->a);
	pst->a=NULL;
	pst->top=pst->capacity=0;
}

(3)入栈

初始化里对top的不同处理方式决定了这里插入数据的方式

  • 指向栈顶元素:先top++,再放数据
  • 指向栈顶元素的下一个位置:先放数据,再top++

判满:

  • 指向栈顶元素:top+1==capacity
  • 指向栈顶元素的下一个位置:top==capacity

对于capacity的处理:

由于capacity初始化为0,这里不能直接扩容(因为后面涉及到capacity的乘法运算)。这里采用三元运算符的处理方式,若为0则给capacity4个字节,若不为0则capacity*2

c 复制代码
void STPush(ST* pst,STDataType x)
{
	assert(x);
	//扩容
	if(pst->top==pst->capacity)
	{
		int newcapacity=pst->capacity==0?4:pst->capacity*2;
		STDataType* tmp=(STDataType*)realloc(pst->a,newcapacity * sizeof(STDataType));
		if(tmp==NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a=tmp;
		pst->capacity=newcapacity;
	}
	pst->a[pst->top]=x;
	pst->top++;
}

(4)出栈

c 复制代码
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top>0);//栈不为空才能出栈
	pst->top--;
}

(5)取栈顶元素

c 复制代码
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top>0);
	return pst->a[pst->top-1];
}

(6)判空

c 复制代码
bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top==0;
}

如果上面采用的是top指向栈顶元素的话,这里是pst->top==-1为空

(7)获取元素个数

c 复制代码
int STSize(ST* pst)
{
	assert(pst);
	return pst->top;//相当于size
}

三、完整代码

Stack.h

c 复制代码
#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* pst);//初始化
void STDestroy(ST* pst);//销毁
void STPush(ST* pst, STDataType x);//入栈
void STPop(ST* pst);//出栈
STDataType STTop(ST* pst);//取栈顶
bool STEmpty(ST* pst);//判空
int STSize(ST* pst);//获取元素个数

Stack.c

c 复制代码
#include"Stack.h"
//初始化
void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top = 0;
	pst->capacity = 0;
}
//销毁
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->top = pst->capacity = 0;
}
//入栈
void STPush(ST* pst, STDataType x)
{
	assert(x);
	if (pst->top == pst->capacity)
	{
		int newcapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
		STDataType* tmp = (STDataType*)realloc(pst->a, newcapacity * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
//出栈
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top -- ;
}
//取栈顶
STDataType STTop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);
	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;
}

test.c

c 复制代码
#include"Stack.h"
int main()
{
	ST s;
	STInit(&s);
	STPush(&s,1);
	STPop(&s);
	//访问栈的所有元素
	while(!STEmpty((&s))
	{
		printf("%d ",STTop(&s));
		STPop(&s);//要把当前栈顶的元素拿掉才能访问到下一个元素
	}//但是这也就导致访问一次栈就空了
}
相关推荐
GrowthDiary0071 小时前
算法题:寻找二维数组top k问题
数据结构·python·算法
阿米亚波2 小时前
【C++ STL】std::unordered_multiset
开发语言·数据结构·c++·笔记·stl
-dzk-3 小时前
【链表】LC 160.相交链表
数据结构·链表
AKA__Zas4 小时前
芝士算法(前缀和2.0)
java·数据结构·算法·leetcode·哈希算法·学习方法
mifengxing4 小时前
Java 集合进阶(一)
java·开发语言·数据结构·复习笔记
risc1234566 小时前
序列化框架
数据结构
MIngYaaa5206 小时前
2026暑期牛客多校1 2026-7-17
数据结构·算法
wabs6666 小时前
关于图论【卡码网107.寻找存在的路线的思考】
数据结构·算法·图论
冻柠檬飞冰走茶8 小时前
PTA基础编程题目集 7-34 通讯录的录入与显示(C语言实现)
c语言·开发语言·数据结构·算法