目录
栈的概念
画图理解栈
栈的实现
fun.h
fun.c
main.c
栈的概念
栈(Stack)是一种基本的数据结构,其特点是只允许在同一端进行插入和删除操作,这一端被称为栈顶。遵循后进先出(Last In, First Out, LIFO)原则,即最后存入栈中的元素最先被取出。形象地讲,栈就像是生活中堆放盘子的架子,我们总是把新的盘子放在最上面,而需要拿盘子时也是从最上面开始拿。
生活中就有栈的一些例子比如这些图片:
栈的基本操作包括:
- 压栈(Push):向栈顶添加一个元素。相当于在堆叠的顶部放入一个新的物品。
- 出栈(Pop):从栈顶移除一个元素,并可选择返回这个元素。这类似于从堆叠顶部移走最上面的物品。
- 查看栈顶元素(Peek/Top):获取栈顶的元素但不移除它,用于检查或获取栈顶的信息。
- 判断栈是否为空(IsEmpty):检查栈中是否有元素。
- 获取栈的大小(Size):返回栈中元素的数量
画图理解栈
首先我们栈有一个原理:先进后出,后进先出,于是我们得得到这么个图
开始压栈,压栈的同时我们的p指针也要同时往后面走
最总
出栈
依次出栈后
这里为什么会1 2 3 4压栈出栈后变成了4321?
其实正确的压栈出栈我们需要边压栈边出栈就不会出现这种情况了,所以我main函数中是这样写的
int main1() {
Stack p;
STInit(&p);//初始化栈
StackPush(&p, 1);//压栈
StackPop(&p);//出栈
printf("%d\n", p.a[p.top]);
StackPush(&p, 2);
StackPop(&p);
printf("%d\n", p.a[p.top]);
StackPush(&p, 3);
StackPop(&p);
printf("%d\n", p.a[p.top]);
}
栈的实现
接下来我们用代码实现栈,这里我用了三个文件,解析都在注释中
fun.h
这个文件里有我实现了栈的一些功能
#pragma once
//头文件
#include<stdlib.h>
#include<stdbool.h>
#include<stdio.h>
#include<assert.h>
typedef int STDataType;
//栈的结构
typedef struct Stack
{
STDataType* a;//指针
int top;//栈顶
int capacity;//容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
fun.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"fun.h"
//扩容函数
void Exp(Stack* p) {
if (p->capacity == p->top)
{
//利用三目运算来判断是否
int New_cap = p->capacity == 0 ? 4 : p->capacity * 2;
STDataType* tmp = (STDataType*)realloc(p->a, New_cap * sizeof(STDataType));
if (tmp == NULL)
{
assert("realloc");
return;
}
//将开辟空间给给原来的变量
p->a = tmp;
p->capacity = New_cap;
}
}
//初始化
void StackInit(Stack* p) {
assert(p);
p->a = NULL;
p->capacity = p->top = 0;
}
// 入栈
void StackPush(Stack* p, STDataType data){
assert(p);
//判断空间
Exp(p);
//入栈
p->a[p->top] = data;
//入栈后栈顶向上移动
p->top++;
}
//出栈
void StackPop(Stack* p) {
assert(p);
assert(p->top > 0);//确保不为空
//判断是否元素是否为0,避免越界
/*if (p->top == 0)
{
return;
}*/
p->top--;
}
// 获取栈顶元素
STDataType StackTop(Stack* p) {
//判断是否为0
if (p->top == 0)
{
return (STDataType)0;//由于返回类型是 STDataType,所以需要强制转换
}
return p->a[p->top - 1];
}
// 获取栈中有效元素个数
int StackSize(Stack* p) {
return p->top;
}
//判空
bool StackEmpty(Stack* p) {
// 使用逻辑非操作符(!)来检查栈顶指针(top)是否为0(即栈是否为空)
// 如果top为0,说明栈中没有任何元素,因此栈是空的
// 在C语言中,逻辑非操作符会将0转换为1(true),非0转换为0(false)
// 所以当栈顶指针top为0时,!p->top的结果为true(非零值),表示栈为空
// 反之,如果栈中有元素(top非0),则!p->top的结果为false(0),表示栈非空
return !p->top;
}
// 销毁栈
void StackDestroy(Stack* p) {
if (p->a)
{
free(p->a);
p->a = NULL;
p->capacity = p->top = 0;
}
}
main.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"fun.h"
//
//int main1() {
// Stack p;
// STInit(&p);
// StackPush(&p, 1);
// StackPop(&p);
// printf("%d\n", p.a[p.top]);
// StackPush(&p, 2);
// StackPop(&p);
// printf("%d\n", p.a[p.top]);
// StackPush(&p, 3);
// StackPop(&p);
// printf("%d\n", p.a[p.top]);
//
//
//}
int main() {
Stack s1;
StackInit(&s1);
StackPush(&s1, 1);
StackPush(&s1, 2);
printf("栈中元素个数:%d个\n", StackSize(&s1));
while (!StackEmpty(&s1))
{
printf("%d\n", StackTop(&s1));
StackPop(&s1);
}
printf("栈中元素个数:%d个", StackSize(&s1));
StackDestroy(&s1);
}
这个数据结构比较简单,里面的很多方法,都是和顺序表差不多,不懂得铁铁可以去看一下我前面的博客
数据结构:顺序表-CSDN博客文章浏览阅读838次,点赞18次,收藏9次。数据是计算机科学中的基本概念,它代表了在计算机程序中处理的一切信息内容。https://blog.csdn.net/2302_78381559/article/details/137435691这边可能你还是不是很理解栈,我们可以试着做一道Leetcode的题,来感受一下栈
题的链接
20. 有效的括号 - 力扣(LeetCode)https://leetcode.cn/problems/valid-parentheses/description/
我对这道题理解之后写的一篇博客,供大家观看
20. 有效的括号 - 力扣(LeetCode)https://leetcode.cn/problems/valid-parentheses/description/