栈的应用-四则运算求值
后缀表达式(逆波兰)
从左到右遍历表达式,若遇到数字则直接输出。若遇到符号,则与符号栈中的栈顶元素进行对比(乘除优先于加减),若优先级低于栈顶元素或为右括号,则依次出栈,直到不低于栈顶元素的优先级或者匹配到左括号,此符号进栈。若优先级高于栈顶元素,则直接进栈。最终表达式不包含左右括号
后缀表达式计算结果
从左到右遍历后缀表达式,若遇到数字则进栈,遇到符号,则将栈顶的两个数字出栈进行计算,并将结果进栈,依次计算直到最后,即为结果
示例程序
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> Author: xiaojunyu/LunaW
> Mail : xiaojunyu@lunaw.cn
> Gmail : lunaw.cn@gmail.com
> Blog : http://blog.csdn.net/lunaw
> Web : http://lunaw.cn
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Number 1
#define Symbol 2
#define True 1
#define False 0
typedef struct Node {
double number;
char symbol;
char type;
struct Node *next;
} Node, *NodePtr;
typedef struct LinkNode {
NodePtr head;
} LinkNode;
int CheckExp(char *exp); // 粗略检查字符串
int IsEmpty(LinkNode * headP); // 判断栈链是否为空
int Push(LinkNode * headP, Node e); // 入栈
int Pop(LinkNode * headP, NodePtr e); // 出栈
int TailInsert(LinkNode * headP, Node e); // 尾插
int PrintList(LinkNode * headP); // 输出栈
int FreeList(LinkNode * headP); // 释放
int ComparePriority(LinkNode * headP, char symbol); // 比较优先级
int PostfixExpression(LinkNode * headP, char *exp); // 变后缀表达式
double Cal(LinkNode * postfix); // 后缀表达式计算结果
double Math(double A, double B, char C); // 加减乘除
int main(void)
{
double result;
LinkNode postfix;
char expC[512];
printf("Please Input (+-*/) : ");
fgets(expC, sizeof(expC), stdin);
if (!CheckExp(expC)) {
printf("Expression error !\n");
return -1;
}
postfix.head = NULL;
// 变后缀表达式
PostfixExpression(&postfix, expC);
// 输出后缀表达式
printf("Postfix Expression : ");
PrintList(&postfix);
// 计算后缀表达式
result = Cal(&postfix);
FreeList(&postfix);
printf("Result : %g\n", result);
return 0;
}
int CheckExp(char *exp)
{
int i, status;
for (i = 0, status = 0; i < (int)strlen(exp); i++) {
if ((exp[i] >= '0' && exp[i] <= '9') || exp[i] == '+' || exp[i] == '-' || exp[i] == '*' || exp[i] == '/'
|| exp[i] == '(' || exp[i] == ')' || exp[i] == ' ' || exp[i] == '.' || exp[i] == '\n') {
status++;
}
}
if (status == (int)strlen(exp)) {
return True;
} else {
return False;
}
}
double Math(double A, double B, char C)
{
double result;
switch (C) {
case '+':
result = A + B;
break;
case '-':
result = A - B;
break;
case '*':
result = A * B;
break;
case '/':
result = A / B;
break;
default:
result = 0;
}
return result;
}
int PostfixExpression(LinkNode * postfix, char *expC)
{
char number[16];
double num;
int i, n;
Node tmp;
// 符号栈
LinkNode symbolexp;
symbolexp.head = NULL;
memset(number, '\0', sizeof(number));
for (i = 0, n = 0; i < (int)strlen(expC); i++) {
// 遇到空格跳过
if (expC[i] == ' ') {
continue;
}
// 遇到数字存入临时字符数组中
if ((expC[i] >= '0' && expC[i] <= '9') || expC[i] == '.') {
number[n] = expC[i];
n++;
} else {
// 字符数组转换为数字,然后插入到后缀表达式
if (n) {
memset(&tmp, 0, sizeof(Node));
num = strtod(number, NULL);
tmp.type = Number;
tmp.number = num;
tmp.next = NULL;
TailInsert(postfix, tmp);
memset(number, '\0', sizeof(number));
n = 0;
}
// 处理符号
while (True) {
// 若为表达式最后,全部出栈,插入到后缀表达式
if (expC[i] == '\n') {
while (True) {
if (Pop(&symbolexp, &tmp)) {
TailInsert(postfix, tmp);
} else {
break;
}
}
break;
}
// 与栈顶符号比较优先级
if (ComparePriority(&symbolexp, expC[i])) {
// 若优先级低于栈顶符号,输出栈顶元素,插入到后缀表达式
if (Pop(&symbolexp, &tmp)) {
TailInsert(postfix, tmp);
}
} else {
// 若优先级高于栈顶符号,进栈
// 遇到 ')' 则 '(' 出栈, 且 ')' 不进栈
if (expC[i] == ')') {
Pop(&symbolexp, &tmp);
} else {
memset(&tmp, 0, sizeof(Node));
tmp.type = Symbol;
tmp.symbol = expC[i];
tmp.next = NULL;
Push(&symbolexp, tmp);
}
// 显示符号栈的过程
// PrintList(&symbolexp);
break;
}
}
}
}
return 0;
}
double Cal(LinkNode * postfix)
{
double result = 0;
double A, B, C;
NodePtr tmp;
Node tmpx;
LinkNode numbexp;
// 数字栈
numbexp.head = NULL;
tmpx.next = NULL;
for (tmp = postfix->head; tmp != NULL; tmp = tmp->next) {
if (tmp->type == Number) {
// 如果遇到数字,进栈
Push(&numbexp, *tmp);
} else {
// 如果遇到符号,栈顶两个数字出栈
if (Pop(&numbexp, &tmpx)) {
A = tmpx.number;
}
if (Pop(&numbexp, &tmpx)) {
B = tmpx.number;
}
// 计算结果,然后结果进栈
C = Math(B, A, tmp->symbol);
memset(&tmpx, 0, sizeof(Node));
tmpx.type = Number;
tmpx.number = C;
tmpx.next = NULL;
Push(&numbexp, tmpx);
}
// 显示符号栈的过程
// PrintList(&numbexp);
}
// 取出栈顶结果
if (Pop(&numbexp, &tmpx)) {
result = tmpx.number;
} else {
result = 0;
}
return result;
}
int PrintList(LinkNode * headP)
{
NodePtr tmp;
for (tmp = headP->head; tmp != NULL; tmp = tmp->next) {
if (tmp->type == Number) {
printf("%g ", tmp->number);
} else {
printf("%c ", tmp->symbol);
}
}
printf("\n");
return 0;
}
int ComparePriority(LinkNode * headP, char symbol)
{
if (IsEmpty(headP)) {
return False;
}
char tsym = headP->head->symbol;
// 这样是相同优先级从右向左计算,根据交换律,不影响结果
if ((symbol == ')' || (symbol == '+' || symbol == '-')) && tsym != '(') {
return True;
} else {
return False;
}
}
int FreeList(LinkNode * headP)
{
NodePtr tmpA, tmpB;
for (tmpA = headP->head; tmpA != NULL; tmpB = tmpA->next, free(tmpA), tmpA = tmpB) ;
return 0;
}
int Pop(LinkNode * headP, NodePtr e)
{
NodePtr tmp;
if (IsEmpty(headP)) {
return False;
}
memset(e, '\0', sizeof(Node));
memcpy(e, headP->head, sizeof(Node));
tmp = headP->head;
headP->head = headP->head->next;
free(tmp);
return True;
}
int TailInsert(LinkNode * headP, Node e)
{
NodePtr p;
NodePtr tmp = (NodePtr) calloc(sizeof(Node), 1);
memcpy(tmp, &e, sizeof(Node));
if (IsEmpty(headP)) {
headP->head = tmp;
headP->head->next = NULL;
} else {
for (p = headP->head; p->next != NULL; p = p->next) ;
p->next = tmp;
p->next->next = NULL;
}
return 0;
}
int Push(LinkNode * headP, Node e)
{
NodePtr tmp = (NodePtr) calloc(sizeof(Node), 1);
memcpy(tmp, &e, sizeof(Node));
tmp->next = headP->head;
headP->head = tmp;
return 0;
}
int IsEmpty(LinkNode * headP)
{
if (headP->head == NULL) {
return True;
} else {
return False;
}
}