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

一、栈的定义

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 。

相关推荐
froginwe112 小时前
Rust 基础语法
开发语言
hqwest2 小时前
QT肝8天15--左侧静态菜单
开发语言·数据库·qt·qt开发·ui控件
Light602 小时前
LinkedList 头尾插入与随机访问的隐蔽陷阱—— 领码课堂|Java 集合踩坑指南(6):
java·开发语言·性能优化·deque·双向链表·linkedlist·fail-fast
小苏兮2 小时前
【C++】list的使用与模拟实现
开发语言·c++·list
数字化顾问3 小时前
AI自动化测试:接口测试全流程自动化的实现方法——技术深度与行业实践剖析
开发语言·php
心之伊始3 小时前
深入理解 AbstractQueuedSynchronizer(AQS):构建高性能同步器的基石
java·开发语言
小胖xiaopangss3 小时前
栈的压入弹出序列--牛客
数据结构·c++·算法
Shimmer_ocean3 小时前
P1420 最长连号
c++·模拟
程序员莫小特3 小时前
老题新解|求三角形面积
开发语言·数据结构·c++·算法·信息学奥赛一本通