diff --git a/.gitignore b/.gitignore index b48d248..b1e499b 100644 --- a/.gitignore +++ b/.gitignore @@ -55,4 +55,7 @@ Module.symvers Mkfile.old dkms.conf +# CMake +build + # End of https://www.toptal.com/developers/gitignore/api/c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6ea464c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.25) +project(sorting_station C) + +add_library(stack src/stack_and_queue/stack/stack.c) + +add_executable(sorting_station src/stack_and_queue/stack/sorting_station.c) +target_link_libraries(sorting_station PRIVATE stack) +target_compile_options(sorting_station PRIVATE -Wall -Wextra -pedantic) diff --git a/README.md b/README.md index 8d586e5..ab05d77 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,9 @@ Основная почта: nicholas.shestakov@gmail.com Телеграм: @Kolya_shesterka + +## Инструкции по сборке: +```console +$ cmake . -B build +$ cmake --build build +``` diff --git a/src/stack_and_queue/stack/sorting_station.c b/src/stack_and_queue/stack/sorting_station.c new file mode 100644 index 0000000..594698b --- /dev/null +++ b/src/stack_and_queue/stack/sorting_station.c @@ -0,0 +1,156 @@ +#include "stack.h" +#include +#include +#include +#include +#include +#include + +bool isOperatorFirstPriority(char c) +{ + return c == '*' || c == '/'; +} + +bool isOperatorSecondPriority(char c) +{ + return c == '+' || c == '-'; +} + +// Takes infix form of expression as string and returns pointer to postfix form string. Please, dont forget free memory. +// Can track unbalanced brackets and correctness of order of numbers and operators. Cant track extraneous symbols. +// If the error is tracked, returns pointer to the string with the error description. +char* sortingStation(char* infixForm) +{ + char* output = calloc(2 * strlen(infixForm), sizeof(output)); + Stack* operators = newStack(); + + bool isNumberTurn = true; // For check correctness of order. + char* errorMessage = calloc(64, sizeof(*errorMessage)); // For error returns. + int indexOfOutput = 0; + for (int indexOfInfix = 0; infixForm[indexOfInfix] != '\0'; ++indexOfInfix) { + if (isdigit(infixForm[indexOfInfix])) { + if (!isNumberTurn) { + strcat(errorMessage, "Error! Order of numbers and operators is incorrect."); + } + isNumberTurn = !isNumberTurn; + + output[indexOfOutput] = infixForm[indexOfInfix]; + output[indexOfOutput + 1] = ' '; + indexOfOutput += 2; + } + if (isOperatorFirstPriority(infixForm[indexOfInfix])) { + if (isNumberTurn) { + strcat(errorMessage, "Error! Order of numbers and operators is incorrect."); + } + isNumberTurn = !isNumberTurn; + + push(operators, infixForm[indexOfInfix]); + } + if (isOperatorSecondPriority(infixForm[indexOfInfix])) { + if (isNumberTurn) { + strcat(errorMessage, "Error! Order of numbers and operators is incorrect."); + } + isNumberTurn = !isNumberTurn; + + while (!isEmpty(operators) && peek(operators) != '(') { + output[indexOfOutput++] = pop(operators); + output[indexOfOutput++] = ' '; + } + push(operators, infixForm[indexOfInfix]); + } + if (infixForm[indexOfInfix] == '(') { + if (!isNumberTurn) { + strcat(errorMessage, "Error! Number before opening bracket."); + } + + push(operators, infixForm[indexOfInfix]); + } + // Многоступенчатость в целях предотвращения одновременного добавления сразу нескольких сообщений об ошибке. + if (infixForm[indexOfInfix] == ')') { + if (isEmpty(operators)) { + strcat(errorMessage, "Error! Brackets not opened."); + } else { + if (isNumberTurn) { + strcat(errorMessage, "Error! Operator before closing bracket."); + } else { + while (peek(operators) != '(') { + output[indexOfOutput++] = pop(operators); + output[indexOfOutput++] = ' '; + + if (isEmpty(operators)) { + strcat(errorMessage, "Error! Brackets not opened."); + break; + } + } + if (!isEmpty(operators)) { + pop(operators); + } + } + } + } + + // Данное условие истинно, когда строки не равны. + if (strcmp(errorMessage, "")) { + free(output); + deleteStack(operators); + return errorMessage; + } + } + + while (!isEmpty(operators)) { + output[indexOfOutput++] = pop(operators); + output[indexOfOutput++] = ' '; + + if (output[indexOfOutput - 2] == '(') { + free(output); + deleteStack(operators); + strcat(errorMessage, "Error! Brackets not closed."); + return errorMessage; + } + } + + deleteStack(operators); + return output; +} + +int main() +{ + char* testSimple = sortingStation("(1 + (4 + 5 / 2) - 3) + (6 + 8)"); + char* testNoSpaces = sortingStation("4/2+6"); + char* testManyBrackets = sortingStation("((((1))))"); + char* testOnlyNumber = sortingStation("1"); + char* testEmpty = sortingStation(""); + char* testIncorrectOrder = sortingStation("1 + + 1"); + char* testIncorrectOrder2 = sortingStation("+ 1"); + char* testNumberBeforeBracket = sortingStation("1 (+ 3)"); + char* testOperatorBeforeBracket = sortingStation("1 + (2 + ) 3"); + char* testBracketsNotOpened = sortingStation("1 + 2)"); + char* testBracketsNotClosed = sortingStation("1 + (2 + 3"); + + assert(!strcmp(testSimple, "1 4 5 2 / + + 3 - 6 8 + + ") && "testSimple incorrect."); + assert(!strcmp(testNoSpaces, "4 2 / 6 + ") && "testNoSpaces incorrect."); + assert(!strcmp(testManyBrackets, "1 ") && "testManyBrackets incorrect."); + assert(!strcmp(testOnlyNumber, "1 ") && "testOnlyNumber incorrect."); + assert(!strcmp(testEmpty, "") && "testEmpty incorrect."); + assert(!strcmp(testIncorrectOrder, "Error! Order of numbers and operators is incorrect.") && "testIncorrectOrder incorrect."); + assert(!strcmp(testIncorrectOrder2, "Error! Order of numbers and operators is incorrect.") && "testIncorrectOrder2 incorrect."); + assert(!strcmp(testNumberBeforeBracket, "Error! Number before opening bracket.") && "testNumberBeforeBracket incorrect."); + assert(!strcmp(testOperatorBeforeBracket, "Error! Operator before closing bracket.") && "testOperatorBeforeBracket incorrect."); + assert(!strcmp(testBracketsNotOpened, "Error! Brackets not opened.") && "testBracketsNotOpened incorrect."); + assert(!strcmp(testBracketsNotClosed, "Error! Brackets not closed.") && "testBracketsNotClosed incorrect."); + + printf("All tests passed successfully.\n"); + + free(testSimple); + free(testNoSpaces); + free(testManyBrackets); + free(testOnlyNumber); + free(testEmpty); + free(testIncorrectOrder); + free(testIncorrectOrder2); + free(testNumberBeforeBracket); + free(testOperatorBeforeBracket); + free(testBracketsNotOpened); + free(testBracketsNotClosed); + return 0; +} diff --git a/src/stack_and_queue/stack/stack.c b/src/stack_and_queue/stack/stack.c new file mode 100644 index 0000000..2878e96 --- /dev/null +++ b/src/stack_and_queue/stack/stack.c @@ -0,0 +1,60 @@ +#include "stack.h" + +#include +#include +#include +#include + +typedef struct StackNode { + int value; + struct StackNode* next; +} StackNode; + +struct Stack { + StackNode* head; +}; + +Stack* newStack() +{ + Stack* stack = calloc(1, sizeof(*stack)); + assert(stack != NULL && "Error! Memory allocated incorrect."); + return stack; +} + +void deleteStack(Stack* stack) +{ + while (!isEmpty(stack)) { + pop(stack); + } + free(stack); +} + +void push(Stack* stack, int value) +{ + StackNode* newNode = malloc(sizeof(*newNode)); + assert(newNode != NULL && "Error! Memory allocated incorrect."); + newNode->value = value; + newNode->next = stack->head; + stack->head = newNode; +} + +int pop(Stack* stack) +{ + assert(!isEmpty(stack) && "Error! Stack is empty. Can`t pop value."); + StackNode* poppedNode = stack->head; + int value = poppedNode->value; + stack->head = poppedNode->next; + free(poppedNode); + return value; +} + +int peek(Stack* stack) +{ + assert(!isEmpty(stack) && "Error! Stack is empty. Can`t peek value."); + return stack->head->value; +} + +bool isEmpty(Stack* stack) +{ + return stack->head == NULL; +} diff --git a/src/stack_and_queue/stack/stack.h b/src/stack_and_queue/stack/stack.h new file mode 100644 index 0000000..984d7e7 --- /dev/null +++ b/src/stack_and_queue/stack/stack.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +typedef struct Stack Stack; + +// Creates new stack. +// Returns pointer to the created stack. +Stack* newStack(); + +// Deletes stack. Frees all memory used in it. +// Takes pointer to the stack. +void deleteStack(Stack* stack); + +// Pushes new value on the top of the stack. +// Takes pointer to the stack and value for push. +void push(Stack* stack, int value); + +// Deletes the top value of the stack and returns it. Frees memory used for top node. +// Takes pointer to the stack. +// Don`t use if the stack is empty. It causes the error. +// Check this with isEmpty before use this function. +int pop(Stack* stack); + +// Returns the top value of the stack. +// Takes pointer to the stack. +// Don`t use if the stack is empty. It causes the error. +// Check this with isEmpty before use this function. +int peek(Stack* stack); + +// Returns true if the stack is empty and false if not. +// Takes pointer to the stack. +bool isEmpty(Stack* stack);