hello 友友们🤗🤗🤗
今天我们要开始进入栈和队列的学习啦~
你们准备好了吗?🧐🧐
下面我们开始吧~GO!
1.栈的概念及结构
栈:一种特殊的线性表,其只允许在
固定的一端
进行插入
和删除
元素操作。
进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。(后进先出特性)
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
实现栈建议用什么结构?
数组
在实现之前我们先做两道题叭
- 一个栈的初始状态为空。现将元素1、2、3、4、5、A、B、C、D、E
依次入栈
,然后再依次出栈
,则元素出栈的顺序是( B )
A 12345ABCDE
B EDCBA54321
C ABCDE12345
D 54321EDCBA
后进先出 1 2 3 4 5 A B C D E进了那就E 依次出来
- 若进栈序列为 1,2,3,4 ,进栈过程中可以出栈,则下列
不可能
的一个出栈序列
是( C )
A 1,4,3,2
B 2,3,4,1
C 3,1,4,2
D 3,4,2,1
A.1先进了然后出来,2 3 4依次进入,然后4 3 2依次出来符合出栈序列
B.1 2进2出,3进3出,4进4出,然后再1出(符合)
C.1 2 3进,3出,然后选项中要1出,不可能,因为1出之前2要先出
D.1 2 3进,3出,4进4出,然后2 1出
2.栈的实现
2.1接口实现
#pragma once
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
typedef int STDataType;
//定义一个栈
typedef struct Stack
{
STDataType* _a;//带_表示成员(数组)
int _top;//表示栈顶下标(也就是数据个数)
int _capacity;//动态增长(容量大小)
}Stack;
//初始化
void StackInit(Stack* pst);
//销毁
void StackDestory(Stack* pst);
//入栈(栈顶推入数据)
void StackPush(Stack* pst, STDataType x);
//出栈(栈顶出数据)
void StackPop(Stack* pst);
// 获取栈中数据个数
int StackSize(Stack* pst);
//返回1是空,返回0是非空
int StackEmpty(Stack* pst);
// 获取栈顶的数据
STDataType StackTop(Stack* pst);
2.2初始化
//初始化
void StackInit(Stack* pst)
{
assert(pst);
pst->_a = malloc(sizeof(STDataType) * 4);
pst->_top = 0;//表示栈顶是最后一个数据的下一个位置,初始化为-1表示栈顶就是最后一个数据位置
pst->_capacity = 4;
}
2.3销毁
//销毁
void StackDestory(Stack* pst)
{
assert(pst);
free(pst->_a);
pst->_a = NULL;
pst->_top = pst->_capacity = 0;
}
2.4入栈
//入栈(栈顶推入数据)
void StackPush(Stack* pst, STDataType x)
{
assert(pst);
//容量满了(空间不够)要增容
if (pst->_top == pst->_capacity)
{
pst->_capacity *= 2;
STDataType* tmp = (STDataType*)realloc(pst->_a, sizeof(STDataType)*pst->_capacity);
if (tmp == NULL)
{
printf("内存不足\n");
exit(-1);
}
else
{
pst->_a = tmp;//将扩容后的空间给它
}
}
pst->_a[pst->_top] = x;
pst->_top++;
}
代码分析:
- 内存重新分配:使用
realloc
函数对栈的内存空间进行扩容。realloc
函数会尝试将原有的内存块pst->_a
调整为新的大小sizeof(STDataType)*pst->_capacity
。如果扩容成功,realloc
会返回一个指向新内存块的指针;如果失败,会返回NULL
。这里将返回的指针赋值给临时指针tmp
。 - 元素入栈:将传入的元素
x
存储到栈的当前栈顶位置pst->_a[pst->_top]
,然后将栈顶指针pst->_top
加1
,表示栈顶位置向上移动了一个位置。
注意:
解释 sizeof(STDataType) * pst->_capacity 的作用
sizeof(STDataType):
sizeof
是C
语言中的一个操作符,它会返回其操作数所占用的字节数。STDataType
是栈中元素的数据类型,sizeof(STDataType)
就表示一个栈元素所占用的字节数。
pst->_capacity:pst->_capacity 代
表栈当前的容量,也就是栈能够容纳的元素数量。
sizeof(STDataType) * pst- > _capacity :二者相乘就得到了栈扩容后总共需要的内存字节数。
举例来说,若 STDataType 是 int 类型,pst->_capacity 为 8,那么 sizeof(STDataType)*pst->_capacity 就等于 4 * 8 = 32 字节,这就是扩容后栈需要的内存大小。
2.5出栈
//出栈(栈顶出数据)
void StackPop(Stack* pst)
{
assert(pst);
assert(pst->_top > 0);
--pst->_top;
}
2.6获取栈中数据个数
// 获取栈中数据个数
int StackSize(Stack* pst)
{
assert(pst);
return pst->_top;//返回下标
}
代码解释:
在栈的实现里,_top
变量一般用于标记栈顶元素的下一个位置。栈是从下标0
开始存储数据的,那么当栈中有n
个元素时,_top
的值就为 n
。所以直接返回pst->_top
就可以得到栈中数据的个数。
2.7检测栈是否为空
//返回1是空,返回0是非空
int StackEmpty(Stack* pst)
{
assert(pst);
return pst->_top == 0 ? 1 : 0;//注意这里不要写成=0 否则会出现严重错误
//如果是空栈也就是=0为真 返回1,如果非空!=0也就是返回0
}
2.8获取栈顶的数据
// 获取栈顶的数据
STDataType StackTop(Stack* pst)
{
assert(pst);
assert(pst->_top > 0);
//不为空才能调用
return pst->_a[pst->_top - 1];
//这里为什么要-1呢??
//因为top表示栈顶位置,而存储的有效元素个数在栈顶前面
}
2.9如何打印栈
void TestStack()
{
Stack st; // 定义栈变量
StackInit(&st); // 初始化栈
StackPush(&st, 1); // 压入 1
StackPush(&st, 2); // 压入 2
StackPush(&st, 3); // 压入 3
StackPush(&st, 4); // 压入 4
while (!StackEmpty(&st)) // 只要栈不为空
{
printf("%d ", StackTop(&st)); // 打印栈顶元素
StackPop(&st); // 弹出栈顶元素
}
printf("\n");
StackDestory(&st); // 销毁栈
}
int main()
{
TestStack();
return 0;
}
注意:这里要先读取再移除 也就是StackTop(&st) 和 StackPop(&st) 的顺序不可颠倒
-
StackTop(&st)
只是读取栈顶元素,不会改变栈结构。 -
StackPop(&st)
才会真正移除栈顶元素。
最后打印结果:
🎉🎉🎉
在这里本章就结束啦~
我们下期见~