用C语言实现字符串转表达式并计算结果

本文介绍了如何使用C语言将中缀表达式转换为后缀表达式并进行计算。通过栈操作处理运算符的优先级,详细步骤包括中缀转后缀以及后缀表达式的计算过程。程序支持整数、小数和科学计数法,涵盖基本算术运算符。读者可在评论区讨论或留言获取更多细节。

用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

运行结果:测试成功

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值