基於《數據結構》(嚴蔚敏版) 運算符優先算法,純 C 實現,無 STL 依賴。
#include
#include
#include
#include
#include
#define TRUE 1
#define FALSE 0
#define OPSETSIZE 7
typedef int Status;
char OPSET[OPSETSIZE] = {'+', '-', '*', '/', '(', ')', '#'};
char PRIOR[OPSETSIZE][OPSETSIZE] = {
{'>','>','<','<','<','>','>'}, // +
{'>','>','<','<','<','>','>'}, // -
{'>','>','>','>','<','>','>'}, // *
{'>','>','>','>','<','>','>'}, // /
{'<','<','<','<','<','=',' '}, // (
{'>','>','>','>',' ','>','>'}, // )
{'<','<','<','<','<',' ','='}, // #
};
typedef struct SC { char c; struct SC *next; } *StackChar;
typedef struct SF { double f; struct SF *next; } *StackFloat;
StackChar pushSC(StackChar s, char c) {
StackChar p = malloc(sizeof(*p)); p->c = c; p->next = s; return p;
}
StackChar popSC(StackChar s) { StackChar q = s; s = s->next; free(q); return s; }
StackFloat pushSF(StackFloat s, double f) {
StackFloat p = malloc(sizeof(*p)); p->f = f; p->next = s; return p;
}
StackFloat popSF(StackFloat s) { StackFloat q = s; s = s->next; free(q); return s; }
int inOpSet(char ch) {
for (int i = 0; i < OPSETSIZE; i++) if (OPSET[i] == ch) return TRUE;
return FALSE;
}
int opIndex(char op) {
for (int i = 0; i < OPSETSIZE; i++) if (OPSET[i] == op) return i;
return -1;
}
char precede(char a, char b) {
return PRIOR[opIndex(a)][opIndex(b)];
}
double operate(double a, char op, double b) {
switch(op) {
case '+': return a+b;
case '-': return a-b;
case '*': return a*b;
case '/': return b==0 ? NAN : a/b;
}
return NAN;
}
double evaluateExpression(char *expr) {
StackChar optr = NULL;
StackFloat opnd = NULL;
optr = pushSC(optr, '#');
char *p = expr;
char numBuf[32];
int bufLen = 0;
while (*p != '#' || ((StackChar)optr)->c != '#') {
if (isdigit(*p) || *p == '.') {
numBuf[bufLen++] = *p++;
} else {
if (bufLen > 0) {
numBuf[bufLen] = '\0';
opnd = pushSF(opnd, atof(numBuf));
bufLen = 0;
}
if (*p == '\0') break;
if (!inOpSet(*p)) { p++; continue; }
switch (precede(((StackChar)optr)->c, *p)) {
case '<': optr = pushSC(optr, *p); p++; break;
case '=': optr = popSC(optr); p++; break;
case '>': {
char op = ((StackChar)optr)->c;
optr = popSC(optr);
double b = ((StackFloat)opnd)->f; opnd = popSF(opnd);
double a = ((StackFloat)opnd)->f; opnd = popSF(opnd);
opnd = pushSF(opnd, operate(a, op, b));
break;
}
}
}
}
double result = ((StackFloat)opnd)->f;
// 釋放剩餘棧內存 (略)
return result;
}
int main() {
char expr[256];
printf("輸入表達式 (以 # 結束): ");
fgets(expr, sizeof(expr), stdin);
expr[strcspn(expr, "\n")] = '#';
printf("結果: %g\n", evaluateExpression(expr));
return 0;
}
| 項目 | ID 28850 | 本版本 (嚴蔚敏風格) |
|---|---|---|
| 棧節點定義 | 分離結構體指針類型 | typedef 直接定義指針類型 StackChar |
| 數字解析 | 緩衝區 + atof | 同 |
| 優先級表 | 7x7 (含 #) | 同 |
| 主循環終止條件 | *p != '#' || optr->c != '#' | 同 |
| 內存釋放 | 略 | 略 (生產代碼需補全) |
$ gcc -std=c99 -o calc calc.c -lm
$ ./calc
輸入表達式 (以 # 結束): 3+4*2/(1-5)#
結果: 1
operate 中返回 NAN 或設置錯誤碼。inOpSet 過濾。optr->c == '#' 但 *p != '#'。這是經典教科書級實現,適合**數據結構課程作業**、**嵌入式無 STL 環境**、**面試手寫算法**。生產環境請用成熟庫 (tinyexpr, muParser)。