此题的求解过程基本和后缀表达式一致(可以看一下我的“xdoj后缀表达式”),难点之一就是处理输入的字符串,我选择将整个字符串全部读入,然后根据空格的分隔来处理字符串。
我采用了
scanf("%[^\n]", str);
的语句,便可以将空格读入字符串,一般的scanf("%s", str)在遇到空格,也就是 '0' 和回车 也就是
'\n'时会停止读入。
将整个语句读入之后去根据空格的分隔去处理,其中有两个问题,一是对于多位整数
我采用了
do
{
a = a * 10 + (str[i] - '0');
i++;
} while (str[i] != ' ' && str[i] != '\0');
使用do while循环可以省去个位数的情况的判断,无论是几位数都先将第一位数字赋给a,而当是多位数时,原本的a需要进一位,十进制就是乘十了。
第二个问题在于后续计算时,如何判断运算符是运算符,对于上一道题,后缀表达式,题目中说明了是个位数的计算,而加减乘除的符号对应的Ascll码值分别为43,45,42,47,故而可以直接使用 S->data == '+' 来判断,但是对于此题,其中运算的整数并没有特殊说明,甚至在oj中的例子里的42就是 * 的Ascll码值,42 == '/' , 返回的是1。
对此,我采用了在链栈的数据中新加一标志符flag, 当压栈时,数字字符仍是0-9,此时就可以用==来判断运算符,如果确是运算符,就使其为1,后面运算的时候就可以是双重判断,即
S->data == '+' && S->flag == 1,来确定是运算符。
以下是代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct STNode
{
int data;
int flag;
struct STNode* next;
}STNode, * LinkStack;
void Push(LinkStack* S, int e);
int Pop(LinkStack* S);
int main()
{
char str[100];
int i, j;
LinkStack S = NULL;
LinkStack Q = NULL;
int a = 0;
scanf("%[^\n]", str);
for (i = 0; i < strlen(str);)
{
if (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')
{
Push(&S, str[i]);
S->flag = 1;
i++;
}
else if (str[i] >= '0' && str[i] <= '9')
{
do
{
a = a * 10 + (str[i] - '0');
i++;
} while (str[i] != ' ' && str[i] != '\0');
Push(&S, a);
S->flag = 0;
a = 0;
}
else
{
i++;
}
}
while (S != NULL)
{
if (S->data == '+' && S->flag == 1)
{
Push(&Q, Pop(&Q) + Pop(&Q));
Pop(&S);
}
else if (S->data == '-' && S->flag == 1)
{
Push(&Q, Pop(&Q) - Pop(&Q));
Pop(&S);
}
else if (S->data == '*' && S->flag == 1)
{
Push(&Q, Pop(&Q) * Pop(&Q));
Pop(&S);
}
else if (S->data == '/' && S->flag == 1)
{
Push(&Q, Pop(&Q) / Pop(&Q));
Pop(&S);
}
else
{
Push(&Q, Pop(&S));
}
}
printf("%d", Q->data);
return 0;
}
void Push(LinkStack* S, int e)
{
LinkStack q = (LinkStack)malloc(sizeof(STNode));
q->next = (*S);
q->data = e;
(*S) = q;
}
int Pop(LinkStack* S)
{
LinkStack q = (*S);
int e = q->data;
(*S) = (*S)->next;
free(q);
return e;
}