2024/11/19日 日志 数据结构实验(2)---栈实现表达式求值、队列应用(蓝桥杯)

栈实现表达式求值
问题:https://pintia.cn/problem-sets/1858366427985383424/exam/problems/type/7?problemSetProblemId=1858366732315615232
解答:

点击查看代码
#include<bits/stdc++.h>

using namespace std;
//运算符优先级
int precedence(char op) {
    switch (op) {
    case '+':
    case '-':
        return 1;
    case '*':
    case '/':
        return 2;
    default:
        return 0;
    }
}
//转换为后缀表达式
int infixToPostfix(const string& infix, string& postfix) {
    stack<char>s;
    bool prevWasOp = true; //前一个字符是否是运算符
    int openPar = 0; //开括号数量

    for (char c : infix) {
        if (isspace(c)) {
            continue;//跳过空格
        }
        if (isdigit(c)) {
            if (!prevWasOp) {
                return -2;//表达式缺操作数
            }
            postfix += c;//直接将数字加入后缀表达式
            prevWasOp = false;//当前为操作数
        }
        else if (c == '(') {
            s.push(c);
            openPar++;
            prevWasOp = true;
        }
        else if (c == ')') {
            while (!s.empty() && s.top() != '(') {
                postfix += s.top();
                s.pop();
            }
            if (s.empty()) {
                return -1;//缺少右括号
            }
            s.pop();//弹出'('
            openPar--;
            prevWasOp = false; //')'后面可以是运算符
        }else {
            if (precedence(c) == 0) {
                //无效字符
            }
            if (prevWasOp) {
                return -2;//表达式缺少操作数
            }
            while (!s.empty() && precedence(s.top()) >= precedence(c)) {
                postfix += s.top();
                s.pop();
            }
            s.push(c);
            prevWasOp = true;//当前是运算符
        }
    }
    while (!s.empty()) {
        char top = s.top();
        if (top == '(') {
            return -1;//缺少右括号
        }
        postfix += top;
        s.pop();
    }
    return openPar > 0 ? -1: 0;
}
//计算后缀表达式的值
int evaluatePost(const string& postfix) {
    stack<int>s;
    for (char c : postfix) {
        if (isdigit(c)) {
            s.push(c - '0');//将字符数字转换为整数
        }
        else {
            int b = s.top();
            s.pop();
            int a = s.top();
            s.pop();
            switch (c) {
            case '+':s.push(a + b); break;
            case '-':s.push(a - b); break;
            case '*':s.push(a * b); break;
            case '/':s.push(a / b); break;
            }
        }
    }
    return s.top();
}

int main() {
    string in;
    string post;
    getline(cin,in);
    
    int result = infixToPostfix(in, post);
    if (result == -1) {
        cout << "ERROR:缺少括号"<<endl;
    }
    else if (result == -2) {
        cout << "ERROR:表达式缺操作数" << endl;
    }
    else {
        cout << post << endl;
        int value = evaluatePost(post);
        cout << value ;
    }

    return 0;
}
思路:对于式子转换,先确定符号的优先级,再使用一个栈stacks来存储运算符和处理括号。遍历中缀表达式的每个字符,根据字符类型进行不同的处理:如果是空格,跳过。如果是数字,直接添加到后缀表达式。如果是左括号(,压入栈中并增加开括号计数。如果是右括号),弹出栈顶元素直到遇到左括号,然后弹出左括号。如果是运算符,比较优先级并根据需要弹出栈顶元素,然后将当前运算符压入栈中。函数返回值用于指示转换过程中是否出现错误,如缺少括号或表达式缺操作数。 计算后缀表达式的值,使用一个栈stacks来存储操作数。遍历后缀表达式的每个字符,如果是数字则压入栈中,如果是运算符则从栈中弹出两个操作数进行计算,并将结果压回栈中。最终,栈顶的元素即为后缀表达式的计算结果。 补充:C语言示例代码,较C++写法上会复杂
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MAXSIZE 100

typedef struct {
    char data[MAXSIZE];
    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 == MAXSIZE - 1;
}

void push(Stack *s, char c) {
    if (!isFull(s)) {
        s->data[++(s->top)] = c;
    }
}

char pop(Stack *s) {
    if (!isEmpty(s)) {
        return s->data[(s->top)--];
    }
    return '\0'; // 空栈时返回空字符
}

char peek(Stack *s) {
    if (!isEmpty(s)) {
        return s->data[s->top];
    }
    return '\0'; // 空栈时返回空字符
}

// 运算符优先级
int precedence(char op) {
    switch (op) {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        default:
            return 0;
    }
}

// 转换为后缀表达式
int infixToPostfix(const char *infix, char *postfix) {
    Stack s;
    initStack(&s);
    int j = 0;
    int prevWasOperator = 1; // 表示前一个字符是否是运算符
    int openParentheses = 0; // 记录开括号数量

    for (int i = 0; infix[i] != '\0'; i++) {
        char c = infix[i];

        if (isspace(c)) {
            continue; // 跳过空格
        }

        if (isdigit(c)) {
            if (!prevWasOperator) {
                return -2; // 表达式缺操作数
            }
            postfix[j++] = c; // 直接将数字加入后缀表达式
            prevWasOperator = 0; // 当前是操作数
        } else if (c == '(') {
            push(&s, c);
            openParentheses++;
            prevWasOperator = 1; // '('后面可以是操作数
        } else if (c == ')') {
            while (!isEmpty(&s) && peek(&s) != '(') {
                postfix[j++] = pop(&s);
            }
            if (isEmpty(&s)) {
                return -1; // 缺少右括号
            }
            pop(&s); // 弹出 '('
            openParentheses--;
            prevWasOperator = 0; // ')'后面可以是运算符
        } else {
            if (precedence(c) == 0) {
                return -3; // 无效字符
            }
            if (prevWasOperator) {
                return -2; // 表达式缺操作数
            }
            while (!isEmpty(&s) && precedence(peek(&s)) >= precedence(c)) {
                postfix[j++] = pop(&s);
            }
            push(&s, c);
            prevWasOperator = 1; // 当前是运算符
        }
    }

    while (!isEmpty(&s)) {
        char top = pop(&s);
        if (top == '(') {
            return -1; // 缺少右括号
        }
        postfix[j++] = top;
    }

    postfix[j] = '\0'; // 结束后缀表达式
    return openParentheses > 0 ? -1 : 0; // 确保所有括号匹配
}

// 计算后缀表达式的值
int evaluatePostfix(const char *postfix) {
    Stack s;
    initStack(&s);
    for (int i = 0; postfix[i] != '\0'; i++) {
        char c = postfix[i];
        if (isdigit(c)) {
            push(&s, c - '0'); // 将字符数字转换为整数
        } else {
            int b = pop(&s);
            int a = pop(&s);
            switch (c) {
                case '+': push(&s, a + b); break;
                case '-': push(&s, a - b); break;
                case '*': push(&s, a * b); break;
                case '/': push(&s, a / b); break;
            }
        }
    }
    return pop(&s); // 返回最终结果
}

int main() {
    char infix[MAXSIZE];
    char postfix[MAXSIZE];

    printf("请输入数学表达式: ");
    fgets(infix, MAXSIZE, stdin);
    
    int result = infixToPostfix(infix, postfix);
    if (result == -1) {
        printf("ERROR:缺少括号\n");
    } else if (result == -2) {
        printf("ERROR:表达式缺操作数\n");
    } else if (result == -3) {
        printf("ERROR:无效字符\n");
    } else {
        printf("后缀表达式: %s\n", postfix);
        int value = evaluatePostfix(postfix);
        printf("结果: %d\n", value);
    }

    return 0;
}

队列应用(蓝桥杯)
题目:https://pintia.cn/problem-sets/1858366427985383424/exam/problems/type/7?problemSetProblemId=1858366732315615233
解答:

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int MAXM = 1005;
int M;
string inflx[MAXM];
vector<string>post;
queue<string> vip;
queue<string> nor;

void queueup(const string *inflx) {
    for (int i = 1; i <= M; i++) {
        string in = inflx[i];
        if (in.substr(0, 3) == "IN ") {
            string name = in.substr(3);
            char type = name.back();
            name.pop_back(); //删除末尾类型
            name.pop_back();//删除空格
            if (type == 'V') {
                vip.push(name);
            }
            else if (type == 'N') {
                nor.push(name);
            }
        }else if (in.substr(0, 4) == "OUT ") {
            char type = in[4];
            if (type == 'V' && !vip.empty()) {
                vip.pop();
            }
            else if (type == 'N' &&!nor.empty()) {
                nor.pop();
            }
        }
    }
}


int main() {
    cin >> M;
    cin.ignore();
    for (int i = 1; i <= M; i++) {
        getline(cin, inflx[i]);
    }
    queueup(inflx);
    while (!vip.empty()) {
        post.emplace_back(vip.front());
        vip.pop();
    }
    while (!nor.empty()) {
        post.emplace_back(nor.front());
        nor.pop();
    }
    for (int i = 0; i < post.size(); i++) {
        cout << post[i];
        if (i != post.size() - 1) {
            cout << endl;
        }
    }
    return 0;
}
思路:遍历所有的指令。对于每个指令,检查是否是“IN”指令(对象进入)或“OUT”指令(对象退出)。如果是“IN”指令,解析出对象的名称和类型,根据类型将对象名称加入到对应的队列中。如果是“OUT”指令,检查对应的队列是否非空,如果是非空且满足对应类型,则弹出队列中的相应对象。利用容器储存结果,按要求输出。

补充:https://blog.csdn.net/qq_47332831/article/details/123400882

补:
关于栈定义:

typedef int STDataType;   // 定义数据类型
typedef struct Stack
{
	STDataType* a;   // 定义一个动态数组
	STDataType top;  // 用来确定栈顶位置(指向栈顶元素的下一个位置)
	STDataType capacity;  // 栈的容量
}ST;               // ST 为结构体的缩写名

关于队列定义:

typedef int QDataType;

typedef struct QueueNode
{
	QDataType _data;		//用来存储数据
	struct QueueNode* _next;//用来指向下一个结构体
}QueueNode;

typedef struct Queue
{
	QueueNode* _head; //存放整个队列的队头
	QueueNode* _tail; //存放整个队列的队尾
}Queue;
posted @ 2024-11-19 20:53  Moonbeamsc  阅读(13)  评论(0编辑  收藏  举报
返回顶端