Загрузка данных
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// ======================== СТЕК ДЛЯ ОПЕРАТОРОВ (char) ========================
typedef struct Node {
char data;
struct Node* next;
} Node;
typedef struct {
Node* top;
} Stack;
void initStack(Stack* s) {
s->top = NULL;
}
int isEmptyStack(Stack* s) {
return s->top == NULL;
}
void pushStack(Stack* s, char value) {
Node* newNode = (Node*)malloc(sizeof(Node));
if (!newNode) {
printf("Ошибка: не удалось выделить память!\n");
exit(1);
}
newNode->data = value;
newNode->next = s->top;
s->top = newNode;
}
char popStack(Stack* s) {
if (isEmptyStack(s)) {
return '\0'; // ошибка
}
Node* temp = s->top;
char value = temp->data;
s->top = s->top->next;
free(temp);
return value;
}
char peekStack(Stack* s) {
if (isEmptyStack(s)) return '\0';
return s->top->data;
}
void freeStack(Stack* s) {
while (!isEmptyStack(s)) {
popStack(s);
}
}
// ======================== СТЕК ДЛЯ ЧИСЕЛ (double) ========================
typedef struct DNode {
double data;
struct DNode* next;
} DNode;
typedef struct {
DNode* top;
} DStack;
void initDStack(DStack* s) {
s->top = NULL;
}
int isEmptyDStack(DStack* s) {
return s->top == NULL;
}
void pushDStack(DStack* s, double value) {
DNode* newNode = (DNode*)malloc(sizeof(DNode));
if (!newNode) {
printf("Ошибка памяти!\n");
exit(1);
}
newNode->data = value;
newNode->next = s->top;
s->top = newNode;
}
double popDStack(DStack* s) {
if (isEmptyDStack(s)) {
printf("Ошибка: стек пуст при pop!\n");
return 0.0;
}
DNode* temp = s->top;
double value = temp->data;
s->top = s->top->next;
free(temp);
return value;
}
// Пошаговый вывод состояния стека (для наглядности)
void printDStack(DStack* s) {
DNode* current = s->top;
printf("[ ");
while (current != NULL) {
printf("%.2f ", current->data);
current = current->next;
}
printf("] (верхушка слева)\n");
}
// Приоритет операций
int precedence(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0;
}
// ======================== ПРЕОБРАЗОВАНИЕ ИНФИКС → ОПЗ (алгоритм сортировочной станции) ========================
char* infixToPostfix(const char* infix) {
int len = strlen(infix);
char* postfix = (char*)malloc(len * 2 + 10); // запас для пробелов
if (!postfix) return NULL;
postfix[0] = '\0';
Stack s;
initStack(&s);
int i = 0;
int j = 0; // индекс для postfix
while (infix[i] != '\0') {
// Пропускаем пробелы
if (isspace(infix[i])) {
i++;
continue;
}
// Если число (целое)
if (isdigit(infix[i])) {
while (isdigit(infix[i])) {
postfix[j++] = infix[i++];
}
postfix[j++] = ' ';
continue;
}
// Левая скобка
if (infix[i] == '(') {
pushStack(&s, '(');
}
// Правая скобка
else if (infix[i] == ')') {
while (!isEmptyStack(&s) && peekStack(&s) != '(') {
postfix[j++] = popStack(&s);
postfix[j++] = ' ';
}
if (!isEmptyStack(&s) && peekStack(&s) == '(') {
popStack(&s); // удаляем '('
} else {
printf("Ошибка: несбалансированные скобки!\n");
}
}
// Оператор
else if (strchr("+-*/", infix[i])) {
char op = infix[i];
while (!isEmptyStack(&s) && peekStack(&s) != '(' &&
precedence(peekStack(&s)) >= precedence(op)) {
postfix[j++] = popStack(&s);
postfix[j++] = ' ';
}
pushStack(&s, op);
} else {
printf("Некорректный символ: %c\n", infix[i]);
}
i++;
}
// Вытаскиваем оставшиеся операторы
while (!isEmptyStack(&s)) {
if (peekStack(&s) == '(') {
printf("Ошибка: несбалансированные скобки!\n");
}
postfix[j++] = popStack(&s);
postfix[j++] = ' ';
}
postfix[j] = '\0';
freeStack(&s);
return postfix;
}
// ======================== ВЫЧИСЛЕНИЕ ОПЗ (стековый калькулятор) ========================
double evaluatePostfix(const char* postfix) {
DStack s;
initDStack(&s);
char temp[1024];
strncpy(temp, postfix, sizeof(temp) - 1);
temp[sizeof(temp) - 1] = '\0';
char* token = strtok(temp, " ");
printf("Пошаговое вычисление ОПЗ:\n");
while (token != NULL) {
// Если число (поддержка отрицательных)
if (isdigit(token[0]) || (token[0] == '-' && isdigit(token[1]))) {
double num = atof(token);
pushDStack(&s, num);
printf("После push %.2f: ", num);
printDStack(&s);
}
// Если оператор
else if (strlen(token) == 1 && strchr("+-*/", token[0])) {
if (isEmptyDStack(&s)) {
printf("Ошибка: недостаточно операндов!\n");
return 0.0;
}
double right = popDStack(&s);
if (isEmptyDStack(&s)) {
printf("Ошибка: недостаточно операндов!\n");
return 0.0;
}
double left = popDStack(&s);
double result = 0.0;
char op = token[0];
switch (op) {
case '+': result = left + right; break;
case '-': result = left - right; break;
case '*': result = left * right; break;
case '/':
if (right == 0.0) {
printf("Ошибка: деление на ноль!\n");
return 0.0;
}
result = left / right;
break;
default:
printf("Неизвестный оператор!\n");
return 0.0;
}
pushDStack(&s, result);
printf("После %c (%.2f %c %.2f = %.2f): ", op, left, op, right, result);
printDStack(&s);
}
token = strtok(NULL, " ");
}
if (isEmptyDStack(&s)) {
printf("Ошибка: пустой результат!\n");
return 0.0;
}
double result = popDStack(&s);
if (!isEmptyDStack(&s)) {
printf("Предупреждение: в стеке остались элементы!\n");
}
return result;
}
int main() {
char infix[512];
printf("Введите арифметическое выражение (например: 3 + 4 * 2 / (1 - 5)):\n");
fgets(infix, sizeof(infix), stdin);
infix[strcspn(infix, "\n")] = 0; // удаляем перевод строки
printf("\nИсходное выражение: %s\n", infix);
char* postfix = infixToPostfix(infix);
if (postfix == NULL) {
printf("Ошибка преобразования!\n");
return 1;
}
printf("Обратная польская запись (ОПЗ): %s\n\n", postfix);
double result = evaluatePostfix(postfix);
printf("\nРезультат: %.2f\n", result);
free(postfix);
return 0;
}