用C语言实现字符串转表达式并计算结果
原理:用栈操作将中缀表达式转换为后缀表达式,再将后缀表达式计算。(需要特别注意运算符的优先级)。
中缀转后缀:读到操作数时,将其放到输出中,操作符用栈保存,特别注意运算符的优先级。(详细原理可查阅资料)
后缀计算:将读到的操作数保存到栈,读到操作符时将栈中两个操作数出栈,并与该操作符进行运算,再将计算结果压栈,特别要注意需要做好错误处理。
注意:栈可分别建立一个数据栈和一个操作符栈。该程序支持小数 整数 科学计数法 ,运算符支持+ - * / 幂(^)需要其他操作可在此基础上添加。
需要详细说明可留言或评论区讨论。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define STACK_SIZE 512
typedef enum ElemDataType
{
OPERATOR = 1,
INT,
DOUBLE,
POINTER
} ElemDataType;
typedef struct StackElem
{
ElemDataType type;
union {
char op;
int i;
double d;
void *p;
};
} ElemType;
ElemType elemFromOperator(char c)
{
ElemType ret = {.type = OPERATOR, .op = c};
return ret;
}
ElemType elemFromInt(int i)
{
ElemType ret = {.type = INT, .i = i};
return ret;
}
ElemType elemFromDouble(double d)
{
ElemType ret = {.type = DOUBLE, .d = d};
return ret;
}
ElemType elemFromPointer(void* p)
{
ElemType ret = {.type = POINTER, .p = p};
return ret;
}
// ADT: Expression
//==================================================================
typedef struct Expression
{
int size;
int capacity; // 容量
ElemType *tokens;
} Expression;
void initExpression(Expression *pExpr)
{
if (pExpr == NULL)
{
return;
}
pExpr->size = 0;
pExpr->capacity = 10;
pExpr->tokens = malloc(sizeof(ElemType) * pExpr->capacity);
}
// 扩容
void expandExpression(Expression *pExpr, int newCapcity)
{
if (pExpr == NULL)
{
return;
}
if (newCapcity <= pExpr->capacity * 2)
{
newCapcity = pExpr->capacity * 2;
}
ElemType* newTokens = malloc(sizeof(ElemType) * newCapcity);
memcpy(newTokens, pExpr->tokens, sizeof(ElemType) * pExpr->capacity);
free(pExpr->tokens);
pExpr->tokens = newTokens;
}
void appendToken(Expression *pExpr, ElemType elem)
{
if (pExpr == NULL)
{
return;
}
if (pExpr->size == pExpr->capacity)
{
expandExpression(pExpr, 0);
}
pExpr->tokens[pExpr->size] = elem;
pExpr->size ++;
}
void clearExpression(Expression *pExpr, ElemType type)
{
if (pExpr == NULL)
{
return;
}
pExpr->size = 0;
}
void freeExpression(Expression *pExpr)
{
if (pExpr == NULL || pExpr->tokens == NULL)
{
return;
}
free(pExpr->tokens);
pExpr->tokens = NULL;
pExpr->size = 0;
}
// ADT: Stack
//==================================================================
struct Stack
{
ElemType datas[STACK_SIZE];
int top;
};
typedef struct Stack Stack;
//检测是否为空
int isEmpty(Stack *stack)
{
return stack->top == -1;
}
int getStackSize(Stack *stack)
{
return stack->top < 0 ? 0 : stack->top + 1;
}
//初始化
void clear(Stack *stack)
{
stack->top = -1;
}
//判断是否栈满
int isFull(Stack *stack)
{
return stack->top == STACK_SIZE - 1;
}
//进栈、压栈
int push(Stack *stack, ElemType val)
{
if (isFull(stack))
{
printf("push element to a full stack\n");
return 0;
}
stack->datas[++stack->top] = val;
return 1;
}
// 获取栈顶元素
int getStackTop(Stack *stack, ElemType *topElem)
{
if (isEmpty(stack))
{
printf("get top of a empty stack\n");
return 0;
}
*topElem = stack->datas[stack->top];
return 1;
}
//出栈
int pop(Stack *stack)
{
if (isEmpty(stack))
{
printf("pop a empty stack\n");
return 0;
}
stack->top--;
return 1;
}
//==================================================================
int isDigit(char c)
{
return c >= '0' && c <= '9';
}
int isOperator(char c)
{
return c == '+' || c == '-' || c == '*' || c == '/' || c == '^';
}
int getPriority(char c)
{
switch (c)
{
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
case '^':
return 3;
}
return 0;
}
double calculateOp(char op, double val1, double val2)
{
if (op == '+')
{
return val1 + val2;
}
if (op == '-')
{
return val1 - val2;
}
if (op == '*')
{
return val1 * val2;
}
if (op == '/')
{
return val1 / val2;
}
if (op == '^')
{
return pow(val1, val2);
}
printf("unkown operator %c\n", op);
return -1;
}
// return value : 0 invalid 1 valid
int infixToPostfix(Stack *pStack, Expression *pExpr, char* str)
{
if (pStack == NULL || pExpr == NULL || str == NULL)
{
return 0;
}
int i = 0;
while (str[i] != '\0')
{
while (str[i] == ' ' || str[i] == '\t')
{
i++;
}
if (isDigit(str[i]))
{
double value = 0;
while (isDigit(str[i]))
{
value = value * 10 + str[i] - '0';
printf("%c", str[i]);
i++;
}
if (str[i] == '.')
{
i++;
double fraction = 0.0;
double magnitude = 0.1;
if (!isDigit(str[i]))
{
printf("invalid floating point number, no digits after .\n");
return 0;
}
while (isDigit(str[i]))
{
fraction += magnitude * (str[i] - '0');
magnitude *= 0.1;
i ++;
}
value += fraction;
}
if (str[i] == 'e' || str[i] == 'E')
{
i++;
int negative = 0;
if (str[i] == '-')
{
negative = 1;
i++;
}
if (!isDigit(str[i]))
{
printf("missing exponent after e/E\n");
return 0;
}
int exponent = 0;
while(isDigit(str[i]))
{
exponent = exponent * 10 + str[i] - '0';
i++;
}
if(negative == 1)
{
exponent = -exponent;
}
value = value *pow(10, exponent);
}
printf(" ");
appendToken(pExpr, elemFromDouble(value));
continue;
}
else if (str[i] == '(')
{
push(pStack, elemFromOperator(str[i]));
}
else if (str[i] == ')')
{
if (isEmpty(pStack))
{
printf("missing (\n");
return 0;
}
ElemType elem = {};
getStackTop(pStack, &elem);
while (elem.op != '(' && !isEmpty(pStack))
{
printf("%c ", elem.op);
appendToken(pExpr, elemFromOperator(elem.op));
pop(pStack);
if (isEmpty(pStack))
{
printf("missing (\n");
return 0;
}
getStackTop(pStack, &elem);
}
if (isEmpty(pStack))
{
printf("missing (\n");
return 0;
}
pop(pStack);
}
else if (isOperator(str[i]))
{
if (isEmpty(pStack))
{
push(pStack, elemFromOperator(str[i]));
}
else
{
ElemType elem = {};
getStackTop(pStack, &elem);
while (elem.op != '(' && !isEmpty(pStack) && getPriority(str[i]) <= getPriority(elem.op))
{
printf("%c ", elem.op);
appendToken(pExpr, elemFromOperator(elem.op));
pop(pStack);
if (isEmpty(pStack))
{
break;
}
getStackTop(pStack, &elem);
}
push(pStack, elemFromOperator(str[i]));
}
}
else
{
printf("invalid character %c\n", str[i]);
return 0;
}
i++;
}
while (!isEmpty(pStack))
{
ElemType elem = {};
getStackTop(pStack, &elem);
pop(pStack);
if (elem.op == '(')
{
printf("missing )\n");
return 0;
}
else
{
printf("%c ", elem.op);
appendToken(pExpr, elemFromOperator(elem.op));
}
}
printf("\n");
return 1;
}
int calculatePostfix(Expression *pExpr, double *pRes)
{
if (pExpr == NULL || pRes == NULL)
{
return 0;
}
Stack stack;
clear(&stack);
int i = 0;
for (i = 0; i < pExpr->size; i ++)
{
ElemType elem = pExpr->tokens[i];
if (elem.type == DOUBLE)
{
push(&stack, elem);
}
else if(elem.type == OPERATOR)
{
if (!isOperator(elem.op))
{
printf("invalid operator %c\n", elem.op);
return 0;
}
if (isEmpty(&stack))
{
printf("missing value\n");
return 0;
}
ElemType valElem1 = {}, valElem2 = {};
getStackTop(&stack, &valElem1);
pop(&stack);
if (isEmpty(&stack))
{
printf("missing value\n");
return 0;
}
getStackTop(&stack, &valElem2);
pop(&stack);
push(&stack, elemFromDouble(calculateOp(elem.op, valElem2.d, valElem1.d)));
}
}
if (isEmpty(&stack))
{
printf("empty expression\n");
return 0;
}
if (getStackSize(&stack) > 1)
{
printf("missing operator\n");
return 0;
}
ElemType elem = {};
getStackTop(&stack, &elem);
*pRes = elem.d;
return 1;
}
//测试函数
// a simplest test framework
//=====================================================================================
static int count = 0;
static int passedCount = 0;
void test(char* str, int expectedValid, double exptectedRes)
{
Stack stack;
clear(&stack);
Expression expr;
initExpression(&expr);
int valid1 = infixToPostfix(&stack, &expr, str);
double actualResult = 0;
int actualValid = valid1 ? calculatePostfix(&expr, &actualResult) : 0;
int pass = expectedValid == actualValid && (expectedValid == 0 || (exptectedRes - actualResult) <= 1e-10 * exptectedRes
||exptectedRes * actualResult>0 && isinf(exptectedRes) == isinf(actualResult));
count ++;
passedCount += pass ? 1 : 0;
printf("case %d %s, input : %s, valid: %d, expected result: %lf, actual result: %lf\n",
count, pass ? "passed" : "failed", str, expectedValid, exptectedRes, actualResult);
}
//计算结果测试
int main()
{
// integer
test(" 1 / 2 * 3", 1, 1 / 2 * 3);
test("(", 0, 0);
test("1+", 0, 0);
test("100+(10 * 2 / 5 * (3 - 2 + 5)) * (100-10)", 1, 100+(10 * 2 / 5 * (3 - 2 + 5)) * (100-10));
test("100+(10 * 2 / 5 * (3 - 2 + 5) * (100-10)", 0, 0);
test("+1", 0, 0);
test("&", 0, 0);
test("10^2", 1, pow(10, 2));
test("1.123421890 * 1234801.1234123 / 12342.2134123", 1, 1.123421890 * 1234801.1234123 / 12342.2134123);
test("1.1234235^2.213412 * 100.809774551 ^ 41.87012342", 1, pow(1.1234235, 2.213412) * pow(100.809774551, 41.87012342));
test("32425+324e-3+32423.34324", 1, 32425+324e-3+32423.34324);
test("324223e-23+7298437+234.1^20", 1, 324223e-23+7298437+pow(234.1, 20));
printf("total : %d, passed: %d, failed: %d\n", count, passedCount, count - passedCount);
return 0;
}
//T.M
运行结果:
本文介绍了如何使用C语言将中缀表达式转换为后缀表达式并进行计算。通过栈操作处理运算符的优先级,详细步骤包括中缀转后缀以及后缀表达式的计算过程。程序支持整数、小数和科学计数法,涵盖基本算术运算符。读者可在评论区讨论或留言获取更多细节。
6627

被折叠的 条评论
为什么被折叠?



