数据结构---栈和队列详解(上)

一、栈的定义

1、栈是限定仅在表尾进行插入删除操作的线性操作。

(栈类似于子弹弹夹中的子弹一样,先进去的后出来,后进去的要先出来。)

在我们软件应用中,栈这种后进先出的数据结构是非常普。比如你用浏览器上网时,不管用什么浏览器,都有一个"后退键",你单击后可以按访问顺序的逆序加载浏览过的网页。再一个撤销操作也是用栈这样的方式实现的。

2、我们把允许插入和删除的一端称之为栈顶(top),另一端称作栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出(Last in First Out)的线性表,简称:LIFO结构。

3、栈是一个线性表,也就是说,栈元素具有线性关系 ,即前驱后继关系。只不过它是一种特殊的线性表而已。定义中说是在线性表尾进行插入和删除操作,这里表尾是指栈顶,而不是栈底。

它的特殊之处就在于限制了这个线性表的的插入和删除位置,它始终只在栈顶进行,这也就使得:栈底是固定的,最先进栈的只能在栈底。

4、栈的插入操作,叫做进栈,也称为压栈,入栈;栈的删除操作,叫做出栈,也有的叫弹栈。

二、栈的实现

(这里我们用数组来实现,链表空间开销更大)

1、栈的初始化:

先定义栈的结构:

cpp 复制代码
//定义栈的结构
typedef int STDatatype;
typedef struct Stack
{
	STDatatype* arr;
	int top;
	int capacity;

}ST;
cpp 复制代码
//初始化
void StackInit(ST* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

这里top用来标记栈顶元素在数组中的位置。

2、入栈

cpp 复制代码
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;
}

3、销毁栈

cpp 复制代码
//销毁
void StackDestroy(ST* ps)
{
	if (ps->arr)
		free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

4、判断栈是否为空

cpp 复制代码
//判断栈是否为空
bool StackEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

5、出栈

cpp 复制代码
//出栈
void StackPop(ST* ps)
{
	assert(!StackEmpty(ps));
	--ps->top;
}

6、取栈顶元素

cpp 复制代码
//取栈顶元素
STDatatype StackTop(ST* ps)
{
	assert(!StackEmpty(ps));
	return ps->arr[ps->top - 1];
}

7、取栈顶有效元素

cpp 复制代码
//获取栈中的有效元素
int StackSize(ST* ps)
{
	return ps->top;
}

三、栈的作用

栈的引入简化了程序设计的问题,划分了不同关注层次,使得思考范围缩小,更加聚焦于我们要解决的问题核心。

四、栈的应用

后缀(逆波兰)表示法的定义:

逆波兰表示法,也称为后缀表示法,是一种数学表达式的表示方法。在这种表示法中,运算符位于其操作数之后,与我们常见的中缀表示法(如 a + b )不同,它的结构更利于计算机进行表达式求值(无需处理括号和运算符优先级)。

核心特点

  • 无括号:通过运算符的位置天然体现运算顺序,无需括号来指定优先级。
  • 运算顺序明确:从左到右扫描表达式,遇到运算符时,对其前面最近的若干个操作数执行运算。

示例

  • 中缀表达式 3 + 4 ,对应的逆波兰表示为 3 4 + 。

  • 中缀表达式 (3 + 4) * 5 ,对应的逆波兰表示为 3 4 + 5 * 。

  • 中缀表达式 3 + 4 * 5 ,对应的逆波兰表示为 3 4 5 * + (因为乘法优先级高于加法,先算 4*5 )。

求值逻辑(以栈实现)

  1. 初始化一个空栈。

  2. 从左到右扫描逆波兰表达式的每个元素:

  • 若为操作数,将其压入栈中。

  • 若为运算符,从栈中弹出两个操作数(先弹出的是右操作数,后弹出的是左操作数),执行该运算符的运算,再将结果压入栈中。

  1. 扫描结束后,栈中仅剩的元素即为表达式的结果。

例如,对 3 4 5 * + 求值:

  • 压入 3 →压入 4 →压入 5 ;

  • 遇到 * ,弹出 5 和 4 ,计算 4*5=20 ,压入 20 ;

  • 遇到 + ,弹出 20 和 3 ,计算 3+20=23 ,最终结果为 23 。

相关推荐
大飞记Python几秒前
【2026更新】Python基础学习指南(AI版)——04数据类型
开发语言·人工智能·python
Alice-YUE40 分钟前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
云泽8081 小时前
C++11 核心特性全解:列表初始化、右值引用与移动语义实战
开发语言·c++
froginwe111 小时前
DOM 加载函数
开发语言
Hello eveybody1 小时前
介绍一下背包DP(Python)
开发语言·python·动态规划·dp·背包dp
AI进化营-智能译站2 小时前
ROS2 C++开发系列12-用多态与虚函数构建可扩展的ROS2机器人行为模块
开发语言·c++·ai·机器人
iCxhust2 小时前
微机原理实践教程(C语言篇)---A002流水灯
c语言·开发语言·单片机·嵌入式硬件·51单片机·课程设计·微机原理
Morwit2 小时前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
qeen872 小时前
【数据结构】建堆的时间复杂度讨论与TOP-K问题
c语言·数据结构·c++·学习·
莎士比亚的文学花园2 小时前
Linux驱动开发(3)——设备树
开发语言·javascript·ecmascript