引入:后缀表达式求值
后缀表达式:运算符号位于两个运算数之后
例:62/3-42*+ = 8
求值策略:从左向右“扫描”,逐个处理运算数和运算符号
- 遇到运算数:记住当前运算数
- 遇到运算符:运用对应的运算数进行计算,将计算得到的数记住
- 需要有种存储方法,能顺序存储运算数, 并在需要时“倒序”输出!
一、堆栈的抽象数据类型描述
堆栈(Stack):具有一定操作约束的线性表 ,即只在一端(栈顶,Top)做 插入、删除(后入先出)
二、栈的顺序存储实现
1.定义:栈的顺序存储结构通常由一个一维数组和一个记录 栈顶元素位置的变量组成。
#define MaxSize <储存数据元素的最大个数>
typedef struct SNode *Stack;
struct SNode{
ElementType Data[MaxSize];
int Top;
};
2.操作:
1)入栈
void Push( Stack PtrS, ElementType item )
{
if ( PtrS->Top == MaxSize-1 ) {
printf(“堆栈满”); return;
}else {
PtrS->Data[++(PtrS->Top)] = item;
return;
}
}
2)出栈
ElementType Pop( Stack PtrS )
{
if ( PtrS->Top == -1 ) {
printf(“堆栈空”);
return ERROR; /* ERROR是ElementType的特殊值,标志错误
*/
} else
return ( PtrS->Data[(PtrS->Top)--] );
}
三、栈的链式存储实现
单链表结构表示,为链栈。插入和删除操作只能在链栈的栈顶进行,头结点为栈顶。
1定义:
typedef struct SNode *Stack;
struct SNode{
ElementType Data;
struct SNode *Next;
} ;
2操作:
1)入栈:
void Push( ElementType item, Stack S)
{ /* 将元素item压入堆栈S */
struct SNode *TmpCell;
TmpCell=(struct SNode *)malloc(sizeof(struct SNode));
TmpCell->Element = item;
TmpCell->Next = S->Next;
S->Next = TmpCell;
}
2)出栈:
ElementType Pop(Stack S)
{ /* 删除并返回堆栈S的栈顶元素 */
struct SNode *FirstCell;
ElementType TopElem;
if( IsEmpty( S ) ) {
printf(“堆栈空”); return NULL;
} else {
FirstCell = S->Next;
S->Next = FirstCell->Next;
TopElem = FirstCell ->Element;
free(FirstCell);
return TopElem;
}
}
四、应用
1.后缀表达式求值:
步骤:
- 运算数:入栈;
- 运算符:从堆栈中弹出适当数量的运算数,计算并结果入栈;
- 最后,堆栈顶上的元素就是表达式的结果值。
2.中缀表达式求值:
基本策略:将中缀表达式转换为后缀表达式,然后求值。
中缀表达式转化为后缀表达式:
从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。
① 运算数:直接输出;
② 左括号:压入堆栈;
③ 右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出);
④ 运算符:
• 若优先级大于栈顶运算符时,则把它压栈;
• 若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比 较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然 后将该运算符压栈;
⑤ 若各对象处理完毕,则把堆栈中存留的运算符一并输出。