首页
社区
课程
招聘
[旧帖] [原创]菜鸟努力转正之:四则运算器 0.00雪花
发表于: 2011-2-12 22:30 1411

[旧帖] [原创]菜鸟努力转正之:四则运算器 0.00雪花

2011-2-12 22:30
1411
声明:
我是小菜鸟,不会上传图片。下面的代码也仅仅可以计算出结果,运行效率可能一点也不高效。
为了能够早日转正,还是厚着脸皮发出来吧。

程序简介:
四则运算计算器,支持+、-、*、/运算,支持()、[]、{}。
无表达式合法性验证,所以请输入合法的表达式(例如,()中不能嵌套[]、{}。)
另外,不支持浮点数,但是很容易修改。

算法简介:
本程序的前身是一个仅支持+、-、*、/运算的计算器,之后可轻易添加括号支持。
首先介绍一下前身,以表达式 1+ 2*3*4为例:
这个表达式中有1、2、3、4这几个操作数;有+、*、*这几个运算符。并且可以断定
操作数的个数肯定是运算符个数加1。
算法中用到如下两个对应的数据结构:
typedef struct _VAL_ITEM {
    int     nValue;
    BOOL    bAval;      // 是否有效
} VAL_ITEM, *PVAL_ITEM;

typedef struct _OPT_ITEM {
    char    cOpt;
    BOOL    bHasCal;    // 是否计算
} OPT_ITEM, *POPT_ITEM;

1、扫描整个表达式,得到运算符个数,假设为N
2、分配N个OPT_ITEM,N+1个VAL_ITEM
3、重新扫描表达式,若是运算符,则依次放到OPT_ITEM结构中;
若是操作数,则依次放到VAL_ITEM结构中。bHasCal初始为FALSE,
bAval初始为TRUE。

下面开始就是真正地计算部分了,真正的计算次数也就是运算符个数,
如果该运算符已经计算过了,则将bHasCal设为TRUE。计算过程中还要
从VAL_ITEM取出两个操作数,计算结果保存到第一个操作数(这个保证
了数组中第一个VAL_ITEM结构中就是最终的计算结果),第二个操作数
的bAval设为FALSE。具体的怎么取操作数,其实就是向前遍历、向后遍
历,找到bAval为TRUE的结构即可。

4、计算*、/

5、计算+、-

扩展:添加()、[]、{}支持
在上面的基础上可以很轻松的添加对括号的支持。
例如: ((1+2)*2) + 1,
扫描‘(’,这里我们忽略空格,第1个字符即为‘(’,然后查找‘)’,
定位到第6个字符。然后在第1个和第6个之间再次查找‘(’,如果找到了
说明它们之间不匹配,否则匹配成功。

1、匹配成功时:
把之间的表达式拷贝出来,交给上面的函数计算。计算结果还要把刚刚的
整个表达式连同()给替换掉,也就是生成新的中间表达式,然后重新扫描。

2、匹配不成功:
向后继续扫描

如果找不到‘(’则直接计算即可。

对于[]、{}这里不再赘述,与上面相同。

完整代码:
// by lazy_cat   
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <Windows.h>

#define IsOpt(c) (c == '+' || c == '-' || c == '*' || c == '/')

typedef struct _VAL_ITEM {
    int     nValue;
    BOOL    bAval;      // 是否有效
} VAL_ITEM, *PVAL_ITEM;

typedef struct _OPT_ITEM {
    char    cOpt;
    BOOL    bHasCal;    // 是否计算
} OPT_ITEM, *POPT_ITEM;

int GetValueIndex(PVAL_ITEM pValItem, int nOptIndex, int nMaxIndex, BOOL bIsLeft)
{
    int nLeftIndex = nOptIndex, nRightIndex = nOptIndex + 1;
    switch (bIsLeft)
    {
    case TRUE:
        while (nLeftIndex >= 0) {
            if (pValItem[nLeftIndex].bAval)
                return nLeftIndex;
            nLeftIndex--;
        }
        break;

    case FALSE:
        while (nRightIndex <= nMaxIndex) {
            if (pValItem[nRightIndex].bAval) {
                pValItem[nRightIndex].bAval = FALSE;
                return nRightIndex;
            }
            nRightIndex++;
        }
        break;
    }
    return -1;
}

int CalWithOutBracket(char *szExp)
{
    int nResult = 0;
    int nOptCount = 0;  // 运算符个数
    for (int i = 0; TRUE; i++)
    {
        if (IsOpt(szExp[i]))
            nOptCount++;
        if (!szExp[i])
            break;
    }
    POPT_ITEM pOptItem = (POPT_ITEM)malloc(sizeof(OPT_ITEM) * nOptCount);
    PVAL_ITEM pValItem = (PVAL_ITEM)malloc(sizeof(VAL_ITEM) * (nOptCount + 1));
    int nOptPos = 0, nValPos = 0;

    char szNum[16] = { 0 };
    int  nDest = 0;
    for (int i = 0; TRUE; i++)
    {
        if (szExp[i] >= '0' && szExp[i] <= '9')
            szNum[nDest++] = szExp[i];
        else
        {
            if (nDest)
            {
                pValItem[nValPos].nValue = atoi(szNum);
                pValItem[nValPos].bAval = TRUE;
                nValPos++;
                nDest = 0;
                RtlZeroMemory(szNum, sizeof(szNum));
            }            
            if (IsOpt(szExp[i])) {
                pOptItem[nOptPos].cOpt = szExp[i];
                pOptItem[nOptPos].bHasCal = FALSE;
                nOptPos++;
            }
        }
        if (!szExp[i])
            break;
    }
    for (int i = 0; i < nOptCount; i++)
    {
        if (pOptItem[i].cOpt == '*' || pOptItem[i].cOpt == '/')
        {
            int nLeftIndex = GetValueIndex(pValItem, i, nOptCount, TRUE);
            int nRightIndex = GetValueIndex(pValItem, i, nOptCount, FALSE);
            switch (pOptItem[i].cOpt)
            {
            case '*':
                pValItem[nLeftIndex].nValue *= pValItem[nRightIndex].nValue;
                break;
            case '/':
                pValItem[nLeftIndex].nValue /= pValItem[nRightIndex].nValue;
                break;
            }
            pOptItem[i].bHasCal = TRUE;
        }
    }
    for (int i = 0; i < nOptCount; i++)
    {
        if (!pOptItem[i].bHasCal)
        {
            int nLeftIndex = GetValueIndex(pValItem, i, nOptCount, TRUE);
            int nRightIndex = GetValueIndex(pValItem, i, nOptCount, FALSE);
            switch (pOptItem[i].cOpt)
            {
            case '+':
                pValItem[nLeftIndex].nValue += pValItem[nRightIndex].nValue;
                break;
            case '-':
                pValItem[nLeftIndex].nValue -= pValItem[nRightIndex].nValue;
                break;
            }
            pOptItem[i].bHasCal = TRUE;
        }
    }
    nResult = pValItem[0].nValue;
    free(pOptItem);
    free(pValItem);
    return nResult;
}

void CalBracket(char *szExp, char cLeftBrc, char cRightBrc)
{
    char *pStart = strchr(szExp, cLeftBrc);
    while (pStart)
    {
        char *pEnd = strchr(pStart, cRightBrc);
        char szPart[64];
        RtlZeroMemory(szPart, sizeof(szPart));
        strncpy(szPart, pStart + 1, pEnd - pStart - 1);
        if (!strchr(szPart, cLeftBrc))
        {
            char szTmpExp[256] = { 0 }, szNum[16] = { 0 };
            strncpy(szTmpExp, pStart + 1, pEnd - pStart - 1);
            sprintf(szNum, "%d", CalWithOutBracket(szTmpExp));
            RtlZeroMemory(szTmpExp, sizeof(szTmpExp));
            strncpy(szTmpExp, szExp, pStart - szExp);
            strcat(szTmpExp, szNum);
            strcat(szTmpExp, pEnd + 1);
            strcpy(szExp, szTmpExp);
            pStart = strchr(szExp, cLeftBrc);
            continue;
        }
        pStart = strchr(pStart + 1, cLeftBrc);
    }   
}

void main()
{
    SetConsoleTitle(TEXT("lazy_cat"));
    char szExp[256] = { 0 };
    printf("输入要计算的表达式:");
    scanf("%[^\n]s", szExp);
    CalBracket(szExp, '(', ')');
    CalBracket(szExp, '[', ']');
    CalBracket(szExp, '{', '}');
    printf("计算结果:%d\n", CalWithOutBracket(szExp));
}

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (2)
雪    币: 386
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
好啊,,,,,,,,,
2011-2-12 22:32
0
雪    币: 53
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
网速太卡,不小心发表重复了,请管理删除此贴吧,谢谢!
2011-2-12 22:49
0
游客
登录 | 注册 方可回帖
返回
//