栈应用---中缀表达式转后缀表达式及计算实现

中缀表达式转后缀表达式及计算

概述

该程序实现了将中缀表达式转换为后缀表达式,并计算后缀表达式的值。程序首先读取用户输入的中缀表达式,然后将其转换为后缀表达式,并输出转换后的结果。接着,程序要求用户输入一个后缀表达式(可以是之前转换的结果或其他后缀表达式),并计算其值。

数据结构定义

栈结构

栈用来存储运算符,并辅助完成中缀表达式到后缀表达式的转换以及后缀表达式的计算。

c 复制代码
typedef struct Stack {
    int top; // 栈顶索引
    int stack[MAX_SIZE]; // 存储栈元素的数组
} Stack;

基本操作

创建栈

分配内存并初始化栈顶索引为 -1,表示栈为空。

c 复制代码
Stack *createStack() {
    Stack *stack = (Stack *)malloc(sizeof(Stack));
    stack->top = -1;
    return stack;
}

销毁栈

释放栈所占用的内存。

c 复制代码
void destroyStack(Stack *stack) {
    free(stack);
}

判断栈是否为空

检查栈顶索引是否为 -1

c 复制代码
int isEmpty(Stack *stack) {
    return stack->top == -1;
}

入栈

将元素压入栈顶,如果栈满则输出错误信息并终止程序。

c 复制代码
void push(Stack *stack, int value) {
    if (stack->top >= MAX_SIZE - 1) {
        printf("栈溢出。\n");
        exit(1);
    }
    stack->stack[++stack->top] = value;
}

出栈

弹出栈顶元素,如果栈为空则输出错误信息并终止程序。

c 复制代码
int pop(Stack *stack) {
    if (isEmpty(stack)) {
        printf("栈下溢。\n");
        exit(1);
    }
    return stack->stack[stack->top--];
}

查看栈顶元素

返回栈顶元素,如果栈为空则输出错误信息并终止程序。

c 复制代码
int peek(Stack *stack) {
    if (isEmpty(stack)) {
        printf("栈为空。\n");
        exit(1);
    }
    return stack->stack[stack->top];
}

获取运算符的优先级

根据运算符返回对应的优先级。

c 复制代码
int getPrecedence(char op) {
    if (op == '+' || op == '-') return 1;
    if (op == '*' || op == '/') return 2;
    return 0;
}

中缀表达式转后缀表达式

遍历中缀表达式,根据运算符和括号的不同情况,将中缀表达式转换为后缀表达式。

c 复制代码
void infixToPostfix(char *infix, char *postfix) {
    Stack *stack = createStack();
    int i = 0, j = 0;
    while (infix[i] != '\0') {
        if (isdigit(infix[i])) {
            postfix[j++] = infix[i++];
        } else if (infix[i] == '(') {
            push(stack, infix[i++]);
        } else if (infix[i] == ')') {
            while (!isEmpty(stack) && peek(stack) != '(') {
                postfix[j++] = (char)pop(stack);
            }
            if (!isEmpty(stack) && peek(stack) == '(') {
                pop(stack);
                i++;
            }
        } else {
            while (!isEmpty(stack) && getPrecedence((char)peek(stack)) >= getPrecedence(infix[i])) {
                postfix[j++] = (char)pop(stack);
            }
            push(stack, infix[i++]);
        }
    }
    while (!isEmpty(stack)) {
        postfix[j++] = (char)pop(stack);
    }
    postfix[j] = '\0';
    destroyStack(stack);
}

计算后缀表达式的值

遍历后缀表达式,根据不同的运算符执行相应的操作。

c 复制代码
int evaluatePostfix(char *postfix) {
    Stack *stack = createStack();
    int i = 0;
    while (postfix[i] != '\0') {
        if (isdigit(postfix[i])) {
            push(stack, postfix[i] - '0');
            i++;
        } else {
            int val2 = pop(stack);
            int val1 = pop(stack);
            switch (postfix[i++]) {
                case '+':
                    push(stack, val1 + val2);
                    break;
                case '-':
                    push(stack, val1 - val2);
                    break;
                case '*':
                    push(stack, val1 * val2);
                    break;
                case '/':
                    push(stack, val1 / val2);
                    break;
            }
        }
    }
    int result = pop(stack);
    destroyStack(stack);
    return result;
}

示例代码解析

以下是一个简单的程序示例,演示了如何使用上述定义的栈来转换中缀表达式为后缀表达式,并计算后缀表达式的值:

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAX_SIZE 100

// 定义栈结构
typedef struct Stack {
    int top; // 栈顶索引
    int stack[MAX_SIZE]; // 存储栈元素的数组
} Stack;

// 创建一个新的栈
Stack *createStack() {
    Stack *stack = (Stack *)malloc(sizeof(Stack)); // 分配内存
    stack->top = -1; // 初始化栈顶索引为 -1,表示栈为空
    return stack;
}

// 销毁栈
void destroyStack(Stack *stack) {
    free(stack); // 释放栈所占用的内存
}

// 判断栈是否为空
int isEmpty(Stack *stack) {
    return stack->top == -1; // 如果栈顶索引为 -1,则栈为空
}

// 入栈操作
void push(Stack *stack, int value) {
    if (stack->top >= MAX_SIZE - 1) { // 如果栈满
        printf("栈溢出。\n");
        exit(1); // 终止程序
    }
    stack->stack[++stack->top] = value; // 将值压入栈顶
}

// 出栈操作
int pop(Stack *stack) {
    if (isEmpty(stack)) { // 如果栈为空
        printf("栈下溢。\n");
        exit(1); // 终止程序
    }
    return stack->stack[stack->top--]; // 返回栈顶元素,并将栈顶索引减一
}

// 查看栈顶元素
int peek(Stack *stack) {
    if (isEmpty(stack)) { // 如果栈为空
        printf("栈为空。\n");
        exit(1); // 终止程序
    }
    return stack->stack[stack->top]; // 返回栈顶元素
}

// 获取运算符的优先级
int getPrecedence(char op) {
    if (op == '+' || op == '-') return 1; // 加号和减号的优先级为 1
    if (op == '*' || op == '/') return 2; // 乘号和除号的优先级为 2
    return 0; // 非运算符的优先级为 0
}

// 将中缀表达式转换为后缀表达式
void infixToPostfix(char *infix, char *postfix) {
    Stack *stack = createStack(); // 创建一个新的栈
    int i = 0, j = 0; // 初始化索引
    while (infix[i] != '\0') { // 遍历中缀表达式
        if (isdigit(infix[i])) { // 如果当前字符是数字
            postfix[j++] = infix[i++]; // 将数字添加到后缀表达式
        } else if (infix[i] == '(') { // 如果当前字符是左括号
            push(stack, infix[i++]); // 将左括号压入栈
        } else if (infix[i] == ')') { // 如果当前字符是右括号
            while (!isEmpty(stack) && peek(stack) != '(') { // 弹出栈中的运算符直到左括号
                postfix[j++] = (char)pop(stack); // 将运算符添加到后缀表达式
            }
            if (!isEmpty(stack) && peek(stack) == '(') { // 如果栈顶是左括号
                pop(stack); // 弹出左括号
                i++; // 移动到下一个字符
            }
        } else { // 如果当前字符是运算符
            while (!isEmpty(stack) && getPrecedence((char)peek(stack)) >= getPrecedence(infix[i])) { // 如果栈顶运算符优先级更高或相等
                postfix[j++] = (char)pop(stack); // 将栈顶运算符添加到后缀表达式
            }
            push(stack, infix[i++]); // 将当前运算符压入栈
        }
    }
    while (!isEmpty(stack)) { // 将剩余的运算符从栈中弹出并添加到后缀表达式
        postfix[j++] = (char)pop(stack);
    }
    postfix[j] = '\0'; // 添加字符串结束符
    destroyStack(stack); // 销毁栈
}

// 计算后缀表达式的值
int evaluatePostfix(char *postfix) {
    Stack *stack = createStack(); // 创建一个新的栈
    int i = 0; // 初始化索引
    while (postfix[i] != '\0') { // 遍历后缀表达式
        if (isdigit(postfix[i])) { // 如果当前字符是数字
            push(stack, postfix[i] - '0'); // 将数字转换为整数并压入栈
            i++; // 移动到下一个字符
        } else { // 如果当前字符是运算符
            int val2 = pop(stack); // 弹出第二个操作数
            int val1 = pop(stack); // 弹出第一个操作数
            switch (postfix[i++]) { // 根据运算符执行相应的操作
                case '+':
                    push(stack, val1 + val2); // 加法
                    break;
                case '-':
                    push(stack, val1 - val2); // 减法
                    break;
                case '*':
                    push(stack, val1 * val2); // 乘法
                    break;
                case '/':
                    push(stack, val1 / val2); // 除法
                    break;
            }
        }
    }
    int result = pop(stack); // 最终结果位于栈顶
    destroyStack(stack); // 销毁栈
    return result; // 返回结果
}

int main() {
    char infixExpression[MAX_SIZE]; // 用于存储中缀表达式
    char postfixExpression[MAX_SIZE]; // 用于存储后缀表达式

    printf("请输入一个中缀表达式: "); // 提示输入中缀表达式
    fgets(infixExpression, MAX_SIZE, stdin); // 读取一行输入
    infixExpression[strcspn(infixExpression, "\n")] = 0; // 移除换行符

    infixToPostfix(infixExpression, postfixExpression); // 调用函数将中缀表达式转换为后缀表达式
    printf("中缀表达式: %s\n", infixExpression); // 输出中缀表达式
    printf("后缀表达式: %s\n", postfixExpression); // 输出后缀表达式

    char inputPostfix[MAX_SIZE]; // 用于存储输入的后缀表达式
    printf("请输入后缀表达式进行计算: "); // 提示输入后缀表达式
    fgets(inputPostfix, MAX_SIZE, stdin); // 读取一行输入
    inputPostfix[strcspn(inputPostfix, "\n")] = 0; // 移除换行符

    int result = evaluatePostfix(inputPostfix); // 调用函数计算后缀表达式的值
    printf("结果: %d\n", result); // 输出结果

    return 0;
}

注意事项

  1. 内存管理:确保正确释放分配给栈的内存,避免内存泄漏。
  2. 边界条件处理:检查栈是否为空或满的情况,避免越界访问。
  3. 输入验证:对于用户输入进行适当的验证,确保程序的健壮性。
相关推荐
好奇龙猫14 分钟前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
sp_fyf_20241 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘
ChoSeitaku1 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程1 小时前
双向链表专题
数据结构
香菜大丸1 小时前
链表的归并排序
数据结构·算法·链表
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
oliveira-time1 小时前
golang学习2
算法
@小博的博客2 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
南宫生2 小时前
贪心算法习题其四【力扣】【算法学习day.21】
学习·算法·leetcode·链表·贪心算法
懒惰才能让科技进步3 小时前
从零学习大模型(十二)-----基于梯度的重要性剪枝(Gradient-based Pruning)
人工智能·深度学习·学习·算法·chatgpt·transformer·剪枝