简单逻辑实现一个计算器,没有用到树的知识

来源:互联网 发布:淘宝发货快递公司填错 编辑:程序博客网 时间:2024/05/18 01:35

/*

这几天想整理一下自己所学,就想写一些简单的东西,就想到实现一个简单的计算器


1. 输入的每个计算数必须是整数,且长度不超过10
2. 整个表达式的长度不超过256
3. 不考虑异常输入,保证每个输入都是合法的
4. 操作符只包含()*/+-
5. 优先级,()最高,*/次之,+-最低


最开始的思路:
1. 区分操作数operand与操作符operator;
2. 每个操作符都会有一个左操作数与右操作数
3. 相邻的操作符之间会有一个优先级,通过比较可以取出其中一个操作符先计算,然后将计算出的结果作为一个新的操作数
4. 替换(),遍历的时候先去掉(),即如果遇到(,则遍历字符串直到),然后将这些内容取出,作为一个整体计算出结果,作为一个新的操作数


按照开始的思路的话,可以声明2个数组,一个用来存放操作数,一个用来存放操作符,这里数组大小也是个问题;
A)开始遍历
-->>a.如果是数字,存储到一个临时数组,继续遍历,直到遇到一个非数字为止,然后将给临时数组转换为整数,存放进操作数数组
-->>b.如果是操作符
-->>c.不是(,第一次肯定先存储到操作符数组,如果操作符数组非空的话,则在存储前先与上一个操作符比较,
如果优先级比上一个高(*/ >  +-),则继续读取,如果低(+- < */),则先取出上一个操作符,同时从操作数数组中取出
2个操作数,生成一个新操作数存入操作数数组,并将这个操作符存入操作符数组;
-->>d.且是(,则继续遍历,直到),将读取到的字符串放到一个临时数组,然后计算该字符串的结果作为一个新操作数
存入到操作数数组
B)一直遍历,最后可以发现剩下的操作符数组中,都是前面的操作符优先级小于后面的操作符,此时我们就可以倒序计算结果


好吧,这时发现如果有嵌套()的话,上面的思路d就不适用了。

考虑到()是成对就近匹配的,即最近的一个()是一对,再想一下,即)跟离它最近的一个(是一对,好吧,精确匹配的话,遇到(的时候,我们可以先存储起来,直到遇到),然后依次取出直到遇到第一个(,然后计算替换成一个新操作数存储起来;


下面贴出的是具体实现代码,可以发现使用stack替换成array,数组的存储、取出的操作对应stack的push、pop;

这里不是说stack比数组好用,而是为了回忆一下stack的用法与实现;

这里的stack也非常简单,类型都是固定了,int,char,如果通用的话,可能就会用到void *;

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define MAX_NUM 256
#define OPD_MAX_LEN 10


#ifdef __DEBUG
#define DBG_PRINT printf
#else
#define DBG_PRINT(fmt, ...)
#endif


typedef struct _optStack
{
    char opt[MAX_NUM];
    int top;
} optStack;


typedef struct _opdStack
{
    int opd[MAX_NUM];
    int top;
} opdStack;


optStack optSt;
opdStack opdSt;


void initOptSt()
{
    optSt.top = -1;
}


void initOpdSt()
{
    opdSt.top = -1;
}


int isOptEmpty()
{
    if (-1 == optSt.top)
    {
        return 1;
    }
    
    return 0;
}


char getLastOpt()
{
DBG_PRINT("--->>%d optSt.top:%d\n", __LINE__, optSt.top);
    return optSt.opt[optSt.top];
}


int getLastOpd()
{
return opdSt.opd[opdSt.top];
}


int isOpdEmpty()
{
    if (-1 == opdSt.top)
    {
        return 1;
    }
    return 0;
}


void pushOpt(char c)
{
    optSt.top++;
    optSt.opt[optSt.top] = c;
}


char popOpt()
{
    char op = optSt.opt[optSt.top];
    optSt.top--;
    return op;
}


void pushOpd(int opd)
{
    opdSt.top++;
    opdSt.opd[opdSt.top] = opd;
}


int popOpd()
{
    int opd = opdSt.opd[opdSt.top];
    opdSt.top--;
    return opd;
}


int getOptLen()
{
DBG_PRINT("--->>>%d optSt.top:%d\n", __LINE__, optSt.top);
    return (optSt.top + 1);
}


int isDigit(char c)
{
    if ((c >= '0') && (c <= '9'))
    {
        return 1;
    }


    return 0;
}


int isOpt(char c)
{
    if ((c == '+') || (c == '-') || (c == '*') || (c == '/') || 
        (c == '(') || (c == ')'))
    {
        return 1;
    }


    return 0;
}


int calc(int leftOpd, int rightOpd, char opt)
{
    int ret = 0;
    switch (opt)
    {
    case '+':
        ret = leftOpd + rightOpd;
        break;


    case '-':
        ret = leftOpd - rightOpd;
        break;


    case '*':
        ret = leftOpd * rightOpd;
        break;


    case '/':
        ret = leftOpd / rightOpd;
        break;


    default:
        break;
    }
    
    return ret;
}


char comparePriority(char pre, char next)
{
    switch (pre)
    {
        case '+':
        case '-':
            if ((next == '+') || (next == '-'))
            {
                return '>';
            }
            else if ((next == '*') || (next == '/'))
            {
                return '<';
            }
            else if (next == '(')
            {
                return '<';
            }
            else if (next == ')')
            {
                return '>';
            }
            else
            {
                return '>';
            }
        break;
        
        case '*':
        case '/':
            if ((next == '+') || (next == '-'))
            {
                return '>';
            }
            else if ((next == '*') || (next == '/'))
            {
                return '>';
            }
            else if (next == '(')
            {
                return '<';
            }
            else if (next == ')')
            {
                return '>';
            }
            else
            {
                return '>';
            }
            break;


        case '(':
            if ((next == '+') || (next == '-'))
            {
                return '<';
            }
            else if ((next == '*') || (next == '/'))
            {
                return '<';
            }
            else if (next == '(')
            {
                return '<';
            }
            else if (next == ')')
            {
                return '=';
            }
            else
            {
                return '>';
            }
            break;


        case ')':
            if ((next == '+') || (next == '-'))
            {
                return '<';
            }
            else if ((next == '*') || (next == '/'))
            {
                return '<';
            }
            else if (next == ')')
            {
                return '=';
            }
            else
            {
                return '>';
            }
            break;
        default:
            return '>';
            break;
    }
}


int transCharArrToInt(char arr[], int len)
{
    int i = 0;
    int num = 0;
    for (; i < len; i++)
    {
        int j = 0;
        int digit = arr[i] - '0';
        for (j = 1; j < len - i; j++)
        {
            digit = digit * 10;
        }
        num += digit;
    }


    return num;
}


void trimParenthese()
{
while (getLastOpt() != '(')
{
char nextOpt = popOpt();
DBG_PRINT("---->>>%d nextOpd:%c\n", __LINE__, nextOpt);
if (getLastOpt() == '(')
{
int rightOpd = popOpd();
int leftOpd = popOpd();
int newOpd = calc(leftOpd, rightOpd, nextOpt);
DBG_PRINT("--->>>>%d newOpd:%d\n", __LINE__, newOpd);
pushOpd(newOpd);
}
else
{
char preOpt = getLastOpt();
if (comparePriority(preOpt, nextOpt) == '<')
{
int rightOpd = popOpd();
int leftOpd = popOpd();
int newOpd = calc(leftOpd, rightOpd, nextOpt);
DBG_PRINT("--->>>%d newOpd:%d\n", __LINE__, newOpd);
pushOpd(newOpd);
}
else if (comparePriority(preOpt, nextOpt) == '>')
{

}
}
}
popOpt();
}


int calculator(const char * inputStr)
{
    char *tmpPtr;
    char curChar;
    char opdArr[OPD_MAX_LEN + 1];
    int index = 0;
    tmpPtr = inputStr;


    memset(opdArr, 0, OPD_MAX_LEN + 1);
    curChar = *tmpPtr;

    while (curChar != '\0')
    {
DBG_PRINT("-->>> %d curChar:%c\n", __LINE__, curChar);
        if (isDigit(curChar))
        {
            opdArr[index] = curChar;           
            index++;
            if (*(tmpPtr + 1) == '\0')
            {
                int opd = transCharArrToInt(opdArr, index);
                pushOpd(opd);
                DBG_PRINT("-->>%d last opd:%d\n", __LINE__, opd);
            }
        }
        else
        {
            if (index != 0)
            {
                int opd = transCharArrToInt(opdArr, index);
                pushOpd(opd);
                DBG_PRINT("--->%d opd:%d\n", __LINE__, opd);
                memset(opdArr, 0, index);
                index = 0;
            }
            
            if (isOpt(curChar))
            {
DBG_PRINT("--->>>%d curChar:%c isOptEmpty:%d\n", __LINE__, curChar, isOptEmpty());
                if (isOptEmpty())
                {
DBG_PRINT("-->%d pushOpt curChar:%c\n", __LINE__, curChar);
                    pushOpt(curChar);
                }
                else
                {
                    char preOpt = getLastOpt();
DBG_PRINT("--->>%d preOpt:%c\n", __LINE__, preOpt);
if (curChar == ')')
{
trimParenthese();
}
else
{
if (!isOptEmpty())
{
if (comparePriority(preOpt, curChar) == '>')
{

int rightOpd = popOpd();
int leftOpd = popOpd();
char opt = popOpt();
int newOpd = calc(leftOpd, rightOpd, opt);
DBG_PRINT("--->>>%d newOpd:%d\n", __LINE__, newOpd);
pushOpd(newOpd);
pushOpt(curChar);
}
else
{
pushOpt(curChar);
DBG_PRINT("---> %d pushOpt curChar:%c\n", __LINE__, curChar);
}
}
}
                }
            }
        }
        tmpPtr++;
        curChar = *tmpPtr;
    }


    while (!isOptEmpty() && getOptLen() > 1)
    {
        char topOpt = popOpt();
if (topOpt == ')')
{
trimParenthese();
}
        char preOpt = getLastOpt();
        if (comparePriority(preOpt, topOpt) == '<')
        {
DBG_PRINT("--->>%d preOpt:%c topOpt:%c\n", __LINE__, preOpt, topOpt);
            int rightOpd = popOpd();
            int leftOpd = popOpd();
            int newOpd = calc(leftOpd, rightOpd, topOpt);
DBG_PRINT("--->>>%d newOpd:%d\n", __LINE__, newOpd);
            pushOpd(newOpd);
        }
else if (comparePriority(preOpt, topOpt) == '>')
{
int opd = popOpd();
int rightOpd = popOpd();
int leftOpd = popOpd();
int newOpd = calc(leftOpd, rightOpd, topOpt);
newOpd = calc(newOpd, opd, preOpt);
popOpt();
pushOpd(newOpd);
DBG_PRINT("--->>%d preOpt:%c, topOpt:%c\n", __LINE__, preOpt, topOpt);
}
else if (comparePriority(preOpt, topOpt) == '=')
{
DBG_PRINT("--->>%d preOpt:%c, topOpt:%c\n", __LINE__, preOpt, topOpt);
popOpt();
}
    }


    if (getOptLen() == 1)
    {
        int rightOpd = popOpd();
        int leftOpd = popOpd();
        char topOpt = popOpt();
        int newOpd = calc(leftOpd, rightOpd, topOpt);
        pushOpd(newOpd);
        return newOpd;
    }
else
{
return getLastOpd();
}
}


int main()
{
initOptSt();
initOpdSt();

    char str[]="3+4*5";
char str2[] = "3*(5-4)";
char str3[] = "(12+3)*6";
char str4[] = "12-3*3-2";
char str5[] = "12+3-9";
char str6[] = "12/3-5";
char str7[] = "12-6/3";
char str8[] = "12-6/3*2";
char str9[] = "(12-9*3)+2";
char str10[] = "(12+3)*6+(12/2-2)/2";
    int a = 0;

a = calculator(str10);
printf("-->>>a=%d\n", a);
    return 0;
}
0 0
原创粉丝点击