需求描述:使用一个双向栈实现一个简易计算器,可以计算加减乘除,带小括号(),如 3+2*(3-4)+2=
基本实现方法:双向栈的top端存运算数字,base端存运算符。读取数学运算式,若遇到数字,直接压栈;若遇到运算符,比较运算优先级。若后面的运算符优先级大于前一个运算符(即栈头运算符),运算符压栈,否则,数字出栈进行计算,再把计算结果压栈,后面继续读取字符计算,直到遇到=字符运算结束。
特别声明,下文提供的源码在VC6.0上验证通过。
///
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
// 定义双向栈大小
#define DSTACK_SIZE 40
// 定义双向栈数据结构
typedef struct dStack_s
{
int data[DSTACK_SIZE];
unsigned top; // 指向数据侧栈顶
unsigned base; // 指向运算符侧栈顶
}dStack_t;
// 函数声明
int expr(const char *); // 计算函数
void stackInit(dStack_t **); // 初始化函数
void operate(dStack_t *); // 计算函数
int IsOpr(char); // 判断输入字符是否运算符
char Precede(char, char); // 判断运算符的优先级
void PushNum(dStack_t *, int); // 数字压栈
int PopNum(dStack_t *); // 数字出栈
int GetTopNum(dStack_t *); // 取数据侧栈顶数字
void PushOpr(dStack_t *, char); // 运算符压栈
char PopOpr(dStack_t *); // 运算符出栈
char GetTopOpr(dStack_t *); // 取运算符侧栈顶运算符
void main(void)
{
char *equation = NULL;
char ch = 0;
int i = 0;
equation = (char *)malloc(DSTACK_SIZE * sizeof(char));
if (NULL == equation)
{
printf("main:Insufficient Memory!\n");
exit(0);
}
memset(equation, 0, DSTACK_SIZE * sizeof(char));
printf("Input Formula: Exp. 3+2*(3-4)+2=\n");
ch = getchar();
for (i = 0; ch != '\n'; i++)
{
if (' ' == ch) // 过滤掉等式中的空格,其他非法字符在后面检查
{
continue;
}
*(equation + i) = ch;
ch = getchar();
}
*(equation + i) = '\0';
printf("%d\n", expr(equation));
free(equation);
}
/* 利用双向栈算法的计算函数 */
int expr(const char *equation)
{
char ch = 0;
int digit = 0;
int flag = 0; // 用于标识负号
int finalKey = 0; // 存放最后运算结果
dStack_t *pdStack = NULL;
if (NULL == equation)
{
printf("expr:Insufficient Memory!\n");
exit(0);
}
stackInit(&pdStack);
PushOpr(pdStack, '=');
ch = *(equation++);
if ('-' == ch) // 特殊情况1:首字符为'-',视为负号
{
ch = *(equation++);
flag = 1;
}
while (ch != '=' || GetTopOpr(pdStack) != '=') // 读入字符与运算符栈顶字符均为'='时结束运算
{
if (0 == IsOpr(ch)) // 若输入为数字,可输入多位数
{
digit = ch - '0';
ch = *(equation++);
while (0 == IsOpr(ch))
{
digit = 10 * digit + ch - '0';
ch = *(equation++);
}
if (1 == flag)
{
digit = -digit;
flag = 0;
}
PushNum(pdStack, digit);
}
else if (1 == IsOpr(ch))
{
if (('-' == ch) && ('(' == *(equation - 2))) // 特殊情况2:若字符'-'紧接'('之后,视前者为负号
{
ch = *(equation++);
flag = 1;
}
else
{
switch (Precede(GetTopOpr(pdStack), ch)) // 比较栈顶运算符和输入运算符的优先级
{
case '<':
{
PushOpr(pdStack, ch);
ch = *(equation++);
break;
}
case '=':
{
PopOpr(pdStack);
ch = *(equation++);
break;
}
case '>':
{
operate(pdStack);
break;
}
default:
{
printf("Anomaly Result!\n");
exit(0);
}
}
}
}
else
{
printf("Illegal input!\n");
exit(0);
}
}
finalKey = GetTopNum(pdStack);
free(pdStack);
return finalKey;
}
/* 四则运算函数 */
void operate(dStack_t *stack)
{
int key = 0;
int topDigit = 0;
int hypDigit = 0;
if (NULL == stack)
{
printf("operate:Insufficient Memory!\n");
exit(0);
}
topDigit = PopNum(stack);
hypDigit = PopNum(stack);
switch (PopOpr(stack))
{
case '+':
{
key = hypDigit + topDigit;
break;
}
case '-':
{
key = hypDigit - topDigit;
break;
}
case '*':
{
key = hypDigit * topDigit;
break;
}
case '/':
{
if (0 == topDigit)
{
printf("Divisor cannot be zero!\n");
exit(0);
}
key = hypDigit / topDigit;
break;
}
default:
{
printf("Illegal Operator!\n");
exit(0);
}
}
PushNum(stack, key);
}
/* 双向栈初始化函数 */
void stackInit(dStack_t **stack)
{
*stack = (dStack_t *)malloc(sizeof(dStack_t));
if ((NULL == *stack) || (NULL == stack))
{
printf("stackInit:Insufficient Memory!\n");
exit(0);
}
memset((*stack)->data, 0, DSTACK_SIZE * sizeof(int));
(*stack)->top = -1;
(*stack)->base = DSTACK_SIZE;
}
/* 数字压栈 */
void PushNum(dStack_t *stack, int digit)
{
if (NULL == stack)
{
printf("PushNum:Insufficient Memory!\n");
exit(0);
}
if (stack->top + 1 == stack->base) // 判断是否栈满
{
printf("PushNum:Stack is full!\n");
exit(0);
}
(stack->top)++;
(stack->data)[stack->top] = digit;
}
/* 运算符压栈 */
void PushOpr(dStack_t *stack, char ch)
{
int opr = (int)ch;
if (NULL == stack)
{
printf("PushOpr:Insufficient Memory!\n");
exit(0);
}
if (stack->top + 1 == stack->base) // 判断是否栈满
{
printf("PushOpr:Stack is full!\n");
exit(0);
}
(stack->base)--;
(stack->data)[stack->base] = opr;
}
/* 数字出栈 */
int PopNum(dStack_t *stack)
{
int digit = 0;
if (NULL == stack)
{
printf("PopNum:Insufficient Memory!\n");
exit(0);
}
if (-1 == stack->top) // 判断栈数据侧是否空
{
printf("PopNum:Stack is empty!\n");
exit(0);
}
digit = (stack->data)[stack->top];
(stack->data)[stack->top] = 0; // 栈内存清零,可删除此行代码
(stack->top)--;
return digit;
}
/* 运算符出栈 */
char PopOpr(dStack_t *stack)
{
char opr = 0;
if (NULL == stack)
{
printf("PopOpr:Insufficient Memory!\n");
exit(0);
}
if (DSTACK_SIZE == stack->base) // 判断栈运算符侧是否空
{
printf("PopOpr:Stack is empty!\n");
exit(0);
}
opr = (char)(stack->data)[stack->base];
(stack->data)[stack->base] = 0; // 栈内存清零,可删除
(stack->base)++;
return opr;
}
/* 取数据侧栈顶数字 */
int GetTopNum(dStack_t *stack)
{
if (NULL == stack)
{
printf("GetTopNum:Insufficient Memory!\n");
exit(0);
}
if (-1 == stack->top) // 判断栈运算符侧是否空
{
printf("PopOpr:Stack is empty!\n");
return 0;
}
return (stack->data)[stack->top];
}
/* 取运算符侧栈顶运算符 */
char GetTopOpr(dStack_t *stack)
{
if (NULL == stack)
{
printf("GetTopOpr:Insufficient Memory!\n");
exit(0);
}
if (DSTACK_SIZE == stack->base) // 判断栈运算符侧是否空
{
printf("GetTopOpr:Stack is empty!\n");
return 0;
}
return ((char)(stack->data)[stack->base]);
}
/* 判断输入字符是否运算符:运算符返回1,数字返回0,其他字符返回-1 */
int IsOpr(char ch)
{
if ('+' == ch || '-' == ch || '*' == ch || '/' == ch
|| '(' == ch || ')' == ch || '=' == ch)
{
return 1;
}
else if (ch >= '0' && ch <='9')
{
return 0;
}
else
{
return -1;
}
}
/* 判断运算符的优先级 */
char Precede(char aOpr, char bOpr)
{
switch(aOpr)
{
case '+':
case '-':
{
if ('*' == bOpr || '/' == bOpr || '(' == bOpr)
{
return '<';
}
else
{
return '>';
}
} // 使用return返回,故不加break语句
case '*':
case '/':
{
if ('(' == bOpr)
{
return '<';
}
else
{
return '>';
}
}
case '(':
{
if(')' == bOpr)
{
return '=';
}
else
{
return '<';
}
}
case ')': // 不会出现这种情况
{
return '>';
}
case '=':
{
if ('=' == bOpr)
{
return '=';
}
else
{
return '<';
}
}
default:
{
exit(0);
}
}
}