diff --git a/src/hw5_stack/CMakeLists.txt b/src/hw5_stack/CMakeLists.txt new file mode 100644 index 0000000..6cb2efb --- /dev/null +++ b/src/hw5_stack/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 4.0) +project(hw5_stack C) + +set(CMAKE_C_STANDARD 17) + +add_executable(sortingStation + sortingStation.c + stack.c +) + +if(CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(hw5_stack PRIVATE -Wall -Wextra -Wpedantic) +endif() diff --git a/src/hw5_stack/sortingStation.c b/src/hw5_stack/sortingStation.c new file mode 100644 index 0000000..60e6870 --- /dev/null +++ b/src/hw5_stack/sortingStation.c @@ -0,0 +1,109 @@ +#include "sortingStation.h" + +#include +#include +#include +#include "stack.h" + +// Проверяем является ли данный нам символ знаком операции (умножения/деления/сложения/вычитания) +int isOperator(char currElem) { + return currElem == '+' || currElem == '-' || currElem == '*' || currElem == '/'; +} + +// Проверяем приоритет данного нам знака (по мат законам у деления/умножения он выше чем у сложения/вычитания) +int priority(char currElem) { + if (currElem == '+' || currElem == '-') { + return 1; + } + if (currElem == '*' || currElem == '/') { + return 2; + } + return 0; +} + + +// Само преобразованиие Дейкстры +void toPostfix(char infix[], char postfix[]) { + Stack stack; + init_stack(&stack); + int postfix_index = 0; + + for (int i = 0; infix[i] != '\0'; i++) { + char currElem = infix[i]; + + // Пропускаем пробелы + if (currElem == ' ') { + continue; + } + + // Если цифра - добавляем в массив postfix, так как числа идут первыми, а потом операции + if (isdigit(currElem)) { + postfix[postfix_index++] = currElem; // Добавляем число в следующий индекс массива + postfix[postfix_index++] = ' '; // Делаем пробелы между символами, чтоб не слипалось + } + + // Если открывающая скобка, то в стек + else if (currElem == '(') { + push(&stack, currElem); + } + + // Закрывающая скобка завершает выражение в скобках. + // Вынимаем из стека все операции пока не найдем открывающую скобку + else if (currElem == ')') { + while (!StackEmptiness(&stack)) { + char operator = pop(&stack); + if (operator == '(') { + break; + } + postfix[postfix_index++] = operator; + postfix[postfix_index++] = ' '; + } + } + // Если операция + else if (isOperator(currElem)) { + // Вынимаем операторы с более высоким или равным приоритетом, так как надо чтобы в выражениях, где важен порядок, они выполнялись быстрее + while (!StackEmptiness(&stack)) { + char lastOperator = stack.elements[stack.topIndex]; + if (lastOperator == '(') { // Останавливаем, если встречаем открывающую скобку + break; + } + if (priority(lastOperator) >= priority(currElem)) { // Сравниваем приоритетность операторов + // Оператор из стека имеет высший или равный приоритет - вынимаем его + pop(&stack); + postfix[postfix_index++] = lastOperator; + postfix[postfix_index++] = ' '; + } else { + // Оператор из стека имеет низший - останаваливаем вынимание + break; + } + } + // Кладем текущий оператор в стек + push(&stack, currElem); + } + } + + // Вынимаем все оставшиеся символы операций из стека + while (!StackEmptiness(&stack)) { + char lastOperator = pop(&stack); + postfix[postfix_index++] = lastOperator; + postfix[postfix_index++] = ' '; + } +} + +int main() { + char infix[500]; + char postfix[500]; + + printf("Введите выражение со скобками, цифрами и операторами "); + fgets(infix, sizeof(infix), stdin); + + + infix[strlen(infix) - 1] = '\0'; + + toPostfix(infix, postfix); + + printf("Инфиксная форма: %s\n", infix); + printf("Постфиксная форма: %s\n", postfix); + + return 0; +} diff --git a/src/hw5_stack/sortingStation.h b/src/hw5_stack/sortingStation.h new file mode 100644 index 0000000..6f45866 --- /dev/null +++ b/src/hw5_stack/sortingStation.h @@ -0,0 +1,36 @@ +// Description: Этот модуль предоставляет функции для преобразования +// математических выражений из инфиксной формы в постфиксную (обратную польскую запись) +// с использованием алгоритма "сортировочной станции" Э. Дейкстры. +// Поддерживает операции: +, -, *, /, скобки () и цифры. +// + +#pragma once + +// +// Проверяет является ли символ оператором +// Параметр: currElem - символ для проверки +// Возвращает: 1 если оператор, 0 если нет +// +int isOperator(char currElem); + +// +// Определяет приоритет оператора +// Параметр: currElem - оператор +// Возвращает: 2 для * /, 1 для + -, 0 для других символов +// +int priority(char currElem); + +// +// Преобразует инфиксное выражение в постфиксное +// Параметры: +// infix - входное инфиксное выражение +// postfix - выходной буфер для постфиксного выражения +// +// Алгоритм: +// 1. Числа сразу добавляются в выходной массив +// 2. Открывающие скобки помещаются в стек +// 3. Закрывающие скобки выталкивают операторы из стека до открывающей скобки +// 4. Операторы выталкивают из стека операторы с высшим или равным приоритетом +// 5. В конце все оставшиеся операторы выталкиваются из стека +// +void toPostfix(char infix[], char postfix[]); diff --git a/src/hw5_stack/stack.c b/src/hw5_stack/stack.c new file mode 100644 index 0000000..826ee07 --- /dev/null +++ b/src/hw5_stack/stack.c @@ -0,0 +1,31 @@ +#include "stack.h" + +// Создаем стэк, делая значение top равным -1 ("нет элементов") +void init_stack(Stack *stack) { + stack->topIndex = -1; +} + +// Добавляем элемент +void push(Stack *stack, char value) { + stack->topIndex++; // Увеличиваем индекс на 1 + stack->elements[stack->topIndex] = value; // Добавляем сам элемент в массив +} + +// Берем верхний элемент и удаляем его +char pop(Stack *stack) { + if (StackEmptiness(stack)) { // Проверяем не пуст ли стек + return '\0'; // Возвращаем '\0' если пуст (в таком виде, потому что нужно вернуть char) + } + char value = stack->elements[stack->topIndex]; // Сохраняем верхний элемент + stack->topIndex--; // Уменьшаем индекс + return value; // Возвращаем сохраненный элемент +} + +// Проверяем пуст ли стек (Чтоб не убрать "пустоту") +int StackEmptiness(Stack *stack) { + if (stack->topIndex == -1) { + return 1; // 1 - стек пуст + } else { + return 0; // 0 - стек не пуст + } +} diff --git a/src/hw5_stack/stack.h b/src/hw5_stack/stack.h new file mode 100644 index 0000000..9d61041 --- /dev/null +++ b/src/hw5_stack/stack.h @@ -0,0 +1,41 @@ +// Description: Этот модуль предоставляет функции для работы со стеком: +// создание стэка (init_stack), добавление (push), извлечение элементов (pop) и проверка на пустоту (is_empty). +// Нужен для двух задач: Продвинутый баланс скобок и Сортировочная станция +// +#pragma once +#define STACK_SIZE 512 + +// +// Структура для стека +// В ней создаем char массив для хранения элементов длины STACK_SIZE и переменную для хранения индекса верхнего элемента +// +typedef struct { + char elements[STACK_SIZE]; // массив для хранения + int topIndex; // индекс верхнего элемента +} Stack; + +// +// Создание стека +// В качестве параметра берем указатель на стек (для изменения самого стека, а не только копии) +// +void init_stack(Stack *stack); + +// +// Добавление элемента в стек +// Параметр - Указатель на стек и значение элемента для добавления +// +void push(Stack *stack, char value); + +// +// Удаление элемента из стека с проверкой на пустоту +// Параметр - Указатель на стек +// Вернет значение элемента, если есть что удалять, и 0 если нет +// +char pop(Stack *stack); + +// +// Проверка стэка на пустоту +// Параметр - Указатель на стек +// Вернет 1 если стек пуст, 0 если нет +// +int is_empty(Stack *stack);