c语言如何写中缀表达式

c语言如何写中缀表达式

C语言如何写中缀表达式:使用栈来实现、递归下降解析法、利用运算符优先级进行转换。C语言中实现中缀表达式解析和计算通常需要用到数据结构如栈来帮助处理运算符的优先级和括号等情况。其中,使用栈来实现中缀表达式解析是最常用的方法。下面将详细描述如何在C语言中实现这一过程。

一、使用栈来实现中缀表达式

1.1、栈的基本概念

栈是一种后进先出(LIFO, Last In First Out)数据结构,具有两个主要操作:入栈(push)和出栈(pop)。在处理中缀表达式时,栈主要用于存储运算符和括号,以便根据优先级进行计算。

1.2、运算符优先级

运算符优先级是实现中缀表达式解析的关键。通常,运算符的优先级如下(从高到低):

  • 括号:()
  • 乘法和除法:* /
  • 加法和减法:+ -

在处理中缀表达式时,需要根据运算符的优先级决定是否将运算符入栈或出栈。

1.3、算法步骤

在处理中缀表达式时,可以按照以下步骤进行:

  1. 创建两个栈:一个用于存储运算符(operands),一个用于存储操作数(operators)。
  2. 从左到右扫描中缀表达式的每个字符:
    • 如果是数字,则直接加入操作数栈。
    • 如果是左括号,则将其入运算符栈。
    • 如果是右括号,则将运算符栈中的运算符依次出栈并进行计算,直到遇到左括号为止。
    • 如果是运算符,则根据其优先级进行处理:
      • 如果运算符栈为空或当前运算符优先级高于栈顶运算符,则将当前运算符入栈。
      • 否则,将运算符栈中的运算符依次出栈并进行计算,直到当前运算符优先级高于栈顶运算符为止。

1.4、代码示例

下面是一个简单的C语言代码示例,展示如何使用栈来实现中缀表达式的解析和计算:

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#define MAX 100

typedef struct {

char data[MAX];

int top;

} Stack;

// 初始化栈

void initStack(Stack *s) {

s->top = -1;

}

// 判断栈是否为空

int isEmpty(Stack *s) {

return s->top == -1;

}

// 判断栈是否满

int isFull(Stack *s) {

return s->top == MAX - 1;

}

// 入栈操作

void push(Stack *s, char value) {

if (isFull(s)) {

printf("Stack overflown");

return;

}

s->data[++s->top] = value;

}

// 出栈操作

char pop(Stack *s) {

if (isEmpty(s)) {

printf("Stack underflown");

return '';

}

return s->data[s->top--];

}

// 获取栈顶元素

char peek(Stack *s) {

if (isEmpty(s)) {

printf("Stack is emptyn");

return '';

}

return s->data[s->top];

}

// 判断运算符优先级

int precedence(char op) {

if (op == '+' || op == '-') {

return 1;

}

if (op == '*' || op == '/') {

return 2;

}

return 0;

}

// 进行基本的算术运算

int applyOp(int a, int b, char op) {

switch (op) {

case '+': return a + b;

case '-': return a - b;

case '*': return a * b;

case '/': return a / b;

}

return 0;

}

// 计算中缀表达式

int evaluate(char *expression) {

int i;

Stack operands, operators;

initStack(&operands);

initStack(&operators);

for (i = 0; expression[i] != ''; i++) {

// 忽略空格

if (expression[i] == ' ') {

continue;

}

// 如果是数字,加入操作数栈

if (isdigit(expression[i])) {

int val = 0;

while (i < strlen(expression) && isdigit(expression[i])) {

val = (val * 10) + (expression[i] - '0');

i++;

}

i--;

push(&operands, val);

}

// 如果是左括号,加入运算符栈

else if (expression[i] == '(') {

push(&operators, expression[i]);

}

// 如果是右括号,进行计算

else if (expression[i] == ')') {

while (!isEmpty(&operators) && peek(&operators) != '(') {

int val2 = pop(&operands);

int val1 = pop(&operands);

char op = pop(&operators);

push(&operands, applyOp(val1, val2, op));

}

pop(&operators);

}

// 如果是运算符,进行优先级处理

else {

while (!isEmpty(&operators) && precedence(peek(&operators)) >= precedence(expression[i])) {

int val2 = pop(&operands);

int val1 = pop(&operands);

char op = pop(&operators);

push(&operands, applyOp(val1, val2, op));

}

push(&operators, expression[i]);

}

}

// 计算剩余的操作数和运算符

while (!isEmpty(&operators)) {

int val2 = pop(&operands);

int val1 = pop(&operands);

char op = pop(&operators);

push(&operands, applyOp(val1, val2, op));

}

return pop(&operands);

}

int main() {

char expression[] = "3 + 5 * 2 - ( 12 / 4 )";

printf("Result: %dn", evaluate(expression));

return 0;

}

二、递归下降解析法

递归下降解析法是一种自顶向下的解析技术,适用于语法结构清晰的表达式。以下将详细介绍如何使用递归下降解析法实现中缀表达式的解析和计算。

2.1、递归下降解析的基本概念

递归下降解析法通过递归函数调用来解析表达式的各个部分。每个递归函数对应一个语法规则,函数调用的嵌套层次反映了表达式的语法结构。

2.2、解析表达式的规则

我们可以将中缀表达式分解为以下几个部分:

  • 表达式(expression):由一个或多个项(term)组成,每个项之间通过加法或减法运算符连接。
  • 项(term):由一个或多个因子(factor)组成,每个因子之间通过乘法或除法运算符连接。
  • 因子(factor):可以是一个数字或一个用括号括起来的表达式。

根据上述规则,可以定义以下递归函数:

  • expression():解析由加法或减法连接的项。
  • term():解析由乘法或除法连接的因子。
  • factor():解析单个数字或括号括起来的表达式。

2.3、代码示例

下面是一个简单的C语言代码示例,展示如何使用递归下降解析法实现中缀表达式的解析和计算:

#include <stdio.h>

#include <ctype.h>

#include <stdlib.h>

const char *expr;

int pos;

int expression();

int term();

int factor();

// 获取下一个字符

char next() {

return expr[pos];

}

// 跳过当前字符并获取下一个字符

char consume() {

return expr[pos++];

}

// 解析因子

int factor() {

int result = 0;

if (next() == '(') {

consume();

result = expression();

consume(); // 跳过右括号

} else {

while (isdigit(next())) {

result = result * 10 + (consume() - '0');

}

}

return result;

}

// 解析项

int term() {

int result = factor();

while (next() == '*' || next() == '/') {

if (consume() == '*') {

result *= factor();

} else {

result /= factor();

}

}

return result;

}

// 解析表达式

int expression() {

int result = term();

while (next() == '+' || next() == '-') {

if (consume() == '+') {

result += term();

} else {

result -= term();

}

}

return result;

}

int evaluate(const char *input) {

expr = input;

pos = 0;

return expression();

}

int main() {

const char *input = "3 + 5 * 2 - ( 12 / 4 )";

printf("Result: %dn", evaluate(input));

return 0;

}

三、利用运算符优先级进行转换

中缀表达式的解析和计算可以通过将其转换为后缀表达式(逆波兰表达式)来简化。后缀表达式的计算不需要考虑运算符优先级和括号问题。

3.1、中缀表达式转换为后缀表达式

将中缀表达式转换为后缀表达式的步骤如下:

  1. 创建一个栈用于存储运算符。
  2. 从左到右扫描中缀表达式的每个字符:
    • 如果是数字,则直接输出。
    • 如果是左括号,则将其入栈。
    • 如果是右括号,则将栈中的运算符依次出栈并输出,直到遇到左括号为止。
    • 如果是运算符,则根据其优先级进行处理:
      • 如果运算符栈为空或当前运算符优先级高于栈顶运算符,则将当前运算符入栈。
      • 否则,将栈中的运算符依次出栈并输出,直到当前运算符优先级高于栈顶运算符为止。

3.2、计算后缀表达式

计算后缀表达式的步骤如下:

  1. 创建一个栈用于存储操作数。
  2. 从左到右扫描后缀表达式的每个字符:
    • 如果是数字,则将其入栈。
    • 如果是运算符,则将栈顶的两个操作数出栈,进行相应的运算,并将结果入栈。
  3. 最后栈中的唯一元素即为表达式的计算结果。

3.3、代码示例

下面是一个简单的C语言代码示例,展示如何将中缀表达式转换为后缀表达式,并计算后缀表达式的结果:

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include <string.h>

#define MAX 100

typedef struct {

char data[MAX];

int top;

} Stack;

// 初始化栈

void initStack(Stack *s) {

s->top = -1;

}

// 判断栈是否为空

int isEmpty(Stack *s) {

return s->top == -1;

}

// 判断栈是否满

int isFull(Stack *s) {

return s->top == MAX - 1;

}

// 入栈操作

void push(Stack *s, char value) {

if (isFull(s)) {

printf("Stack overflown");

return;

}

s->data[++s->top] = value;

}

// 出栈操作

char pop(Stack *s) {

if (isEmpty(s)) {

printf("Stack underflown");

return '';

}

return s->data[s->top--];

}

// 获取栈顶元素

char peek(Stack *s) {

if (isEmpty(s)) {

printf("Stack is emptyn");

return '';

}

return s->data[s->top];

}

// 判断运算符优先级

int precedence(char op) {

if (op == '+' || op == '-') {

return 1;

}

if (op == '*' || op == '/') {

return 2;

}

return 0;

}

// 将中缀表达式转换为后缀表达式

void infixToPostfix(char *infix, char *postfix) {

Stack s;

initStack(&s);

int i, j = 0;

for (i = 0; infix[i] != ''; i++) {

if (isdigit(infix[i])) {

postfix[j++] = infix[i];

} else if (infix[i] == '(') {

push(&s, infix[i]);

} else if (infix[i] == ')') {

while (!isEmpty(&s) && peek(&s) != '(') {

postfix[j++] = pop(&s);

}

pop(&s); // 弹出左括号

} else {

while (!isEmpty(&s) && precedence(peek(&s)) >= precedence(infix[i])) {

postfix[j++] = pop(&s);

}

push(&s, infix[i]);

}

}

while (!isEmpty(&s)) {

postfix[j++] = pop(&s);

}

postfix[j] = '';

}

// 计算后缀表达式

int evaluatePostfix(char *postfix) {

Stack s;

initStack(&s);

int i;

for (i = 0; postfix[i] != ''; i++) {

if (isdigit(postfix[i])) {

push(&s, postfix[i] - '0');

} else {

int val2 = pop(&s);

int val1 = pop(&s);

switch (postfix[i]) {

case '+': push(&s, val1 + val2); break;

case '-': push(&s, val1 - val2); break;

case '*': push(&s, val1 * val2); break;

case '/': push(&s, val1 / val2); break;

}

}

}

return pop(&s);

}

int main() {

char infix[] = "3+5*2-(12/4)";

char postfix[MAX];

infixToPostfix(infix, postfix);

printf("Postfix Expression: %sn", postfix);

printf("Result: %dn", evaluatePostfix(postfix));

return 0;

}

四、总结

在C语言中实现中缀表达式的解析和计算,常用的方法有:使用栈来实现递归下降解析法利用运算符优先级进行转换。其中,使用栈来实现是最常用的方法,通过栈来处理运算符的优先级和括号等问题。而递归下降解析法适用于语法结构清晰的表达式,通过递归函数调用来解析表达式的各个部分。利用运算符优先级进行转换则是通过将中缀表达式转换为后缀表达式来简化计算过程。这些方法各有优劣,开发者可以根据具体需求选择合适的方法来实现中缀表达式的解析和计算。

在实际开发中,使用研发项目管理系统PingCode通用项目管理软件Worktile可以帮助团队更好地进行项目管理和协作,提高开发效率。

相关问答FAQs:

1. 什么是中缀表达式?
中缀表达式是指将运算符放在两个操作数之间的表达式形式,例如:3 + 4。

2. 如何将中缀表达式转换为后缀表达式?
将中缀表达式转换为后缀表达式可以通过使用栈来实现。具体步骤包括:从左到右遍历中缀表达式,如果遇到操作数,则直接输出;如果遇到运算符,将其与栈顶运算符进行比较,如果栈顶运算符优先级较低,则将该运算符入栈;如果栈顶运算符优先级较高或相等,则将栈顶运算符出栈并输出,直到栈为空或遇到优先级较低的运算符为止。

3. 如何计算后缀表达式的值?
计算后缀表达式的值可以通过使用栈来实现。具体步骤包括:从左到右遍历后缀表达式,如果遇到操作数,则将其入栈;如果遇到运算符,则从栈中弹出两个操作数,进行运算,并将结果入栈。重复以上步骤直到遍历完后缀表达式,最后栈中的唯一元素就是表达式的值。

原创文章,作者:Edit2,如若转载,请注明出处:https://docs.pingcode.com/baike/1208321

(0)
Edit2Edit2
上一篇 2024年8月31日 上午12:10
下一篇 2024年8月31日 上午12:10
免费注册
电话联系

4008001024

微信咨询
微信咨询
返回顶部