一、什么是堆和栈?
举个例子,算术表达式是由两类对象构成的:运算数和运算符号,不同运算符号优先级不一样
- 中缀表达式:运算符号位于两个运算数之间。如a+b*c-d/e
- 后缀表达式:运算符号位于两个运算数之后。如abc*+de/-
- 前缀表达式:运算符号位于两个运算数之前。如-+a*bc/de
后缀表达式求值策略:从左向右扫描,逐个处理运算数和运算符号,当碰到运算数的时候,把它记住。当碰到运算符号的时候,就把最近记住的两个运算数来进行对应的计算
**启示:**需要有种存储方法,能顺序存储运算数,并在需要时能“倒序”输出
对于后缀表达式 62/3-42+*
重复上面的步骤,直到
运算后得到8,放回去,那么运算结束,最顶上的那个数就是我们最后的结果
时间复杂度是线性的,T(N)=O(N)
二、堆栈的抽象数据类型描述
堆栈(Stack):具有一定操作约束的线性表,只能在一端(栈顶,Top)做插入和删除
- 插入数据:入栈(push)
- 删除数据:出栈(pop)
- 后入先出:Last In First Out(LIFO)
类型名称:堆栈(Stack)
数据对象集:一个有0个或多个元素的有穷线性表
操作集:长度为MAXSIZE的堆栈S∈Stack,堆栈元素item∈ElementType
- 栈的顺序存储实现
栈的顺序存储结构通常由一个一维数组和一个记录栈顶元素位置的变量组成
-
1)入栈
-
2)出栈
例子:用一个数组实现两个堆栈,要求最大地利用数组空间,使数组只要有空间入栈操作就可以成功
注意并不是top1+top2=n就表示栈满,因为top代表的是数组的下标,应当是两个栈的栈顶指针相遇时,表示两个栈都满了
- 对应的Push操作
- 对应的Pop操作
- 栈的链式存储实现
栈的链式存储结构实际上就是一个单链表,叫做链栈。插入和删除只能在链栈的栈顶进行。
栈顶指针Top一定是在单链表的头上,而不能是尾部。对插入是没问题的,对删除就有问题了。删了之后,它的前一个结点在哪里?因为这是单向链表,找不到前面一个结点,所以链尾是不能做Top的。
- 1)堆栈初始化(建立空栈)
- 2)判断堆栈是否为空
- 3)插入
就是在堆栈的头上插入一个结点
- S是一个指针,它指向堆栈的头结点。
- 4)删除
三、堆栈应用:表达式求值
中缀表达式如何转换为后缀表达式
从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。
- 1)运算数,直接输出;
- 2)左括号,压入堆栈;
- 3)右括号,将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
- 4)运算符:①若优先级大于栈顶运算符时,则把它压栈。②若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈
- 5)若各对象处理完毕,则把堆栈中存留的运算符一并输出