diff --git a/semester_1/homework7/binarySearchTree/String/String.c b/semester_1/homework7/binarySearchTree/String/String.c new file mode 100644 index 0000000..a652465 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/String/String.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#include "String.h" + +char *getString(size_t * const len, FILE * filename, char const endOfLine) +{ + *len = 0; + size_t capacity = 1; + char *s = (char *)malloc(sizeof(char)); + if (s == NULL) + { + return NULL; + } + + for (char c = fgetc(filename); c != endOfLine && c != EOF; c = fgetc(filename)) + { + s[(*len)++] = c; + + if (*len >= capacity) + { + capacity *= 2; + s = (char *)realloc(s, capacity * sizeof(char)); + if (s == NULL) + { + return NULL; + } + } + } + + s[*len] = '\0'; + + return s; +} + +char *copyString(char * const string) +{ + const size_t len = strlen(string); + char *copy = (char *)malloc(len * sizeof(char)); + if (copy != NULL) + { + strcpy(copy, string); + } + return copy; +} diff --git a/semester_1/homework7/binarySearchTree/String/String.h b/semester_1/homework7/binarySearchTree/String/String.h new file mode 100644 index 0000000..6acea75 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/String/String.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include +#include + +char *getString(size_t * const len, FILE * filename, char const endOfLine); +char *copyString(char * const string); diff --git a/semester_1/homework7/binarySearchTree/binarySearchTree/binarySearchTree.c b/semester_1/homework7/binarySearchTree/binarySearchTree/binarySearchTree.c new file mode 100644 index 0000000..6365288 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/binarySearchTree/binarySearchTree.c @@ -0,0 +1,153 @@ +#include +#include +#include + +#include "binarySearchTree.h" +#include "../String/String.h" + +typedef struct Node +{ + char *value; + int key; + struct Node *leftChild; + struct Node *rightChild; +} Node; + +typedef struct Dictionary +{ + Node *root; +} Dictionary; + +Dictionary *createDictionary(void) +{ + return (Dictionary *)calloc(1, sizeof(Dictionary)); +} + +static Node **searchNode(Node **const root, const int key) +{ + if (*root == NULL) + { + return root; + } + + if (key == ((*root)->key)) + { + return root; + } + + if (key < (*root)->key) + { + return searchNode(&((*root)->leftChild), key); + } + return searchNode((&(*root)->rightChild), key); +} + +DictionaryErrorCode append(Dictionary * const dictionary, int const key, char * const value, bool const copyRequired) +{ + char *valueCopy = value; + if (copyRequired) + { + valueCopy = copyString(value); + if (valueCopy == NULL) + { + return memoryError; + } + } + + Node **nodeToWriteTo = searchNode(&(dictionary->root), key); + if (*nodeToWriteTo == NULL) + { + Node *newNode = (Node *)calloc(1, sizeof(Node)); + if (newNode == NULL) + { + free(valueCopy); + return memoryError; + } + newNode->key = key; + *nodeToWriteTo = newNode; + } + (*nodeToWriteTo)->value = valueCopy; + return ok; +} + +static void deleteNode(Node *const nodeToDelete) +{ + if (nodeToDelete != NULL) + { + free(nodeToDelete->value); + free(nodeToDelete); + } +} + +static Node *getMinNode(Node *const root) + { + Node *currentNode = root; + for (; currentNode->leftChild != NULL; currentNode = currentNode->leftChild) + ; + return currentNode; + } + +void deleteElement(Dictionary *const dictionary, int const key) +{ + Node **nodeToDelete = searchNode(&(dictionary->root), key); + if (*nodeToDelete == NULL) + { + return; + } + + Node *left = (*nodeToDelete)->leftChild; + Node *right = (*nodeToDelete)->rightChild; + + deleteNode(*nodeToDelete); + + if (left != NULL) + { + if (right != NULL) + { + *nodeToDelete = right; + Node *minNode = getMinNode(right); + minNode->leftChild = left; + return; + } + *nodeToDelete = left; + return; + } + else if (right != NULL) + { + *nodeToDelete = right; + return; + } + *nodeToDelete = NULL; +} + +static void deleteRecursion(Node *root) +{ + if (root == NULL) + { + return; + } + deleteRecursion(root->leftChild); + deleteRecursion(root->rightChild); + deleteNode(root); +} + +void deleteDictionary(Dictionary *dictionary) +{ + deleteRecursion(dictionary->root); + free(dictionary); +} + +char *getValue(Dictionary *const dictionary, const int key) +{ + Node **foundNode = searchNode(&(dictionary->root), key); + if (*foundNode == NULL) + { + return NULL; + } + return (*foundNode)->value; +} + +bool keyCheck(Dictionary *const dictionary, const int key) +{ + return *(searchNode(&(dictionary->root), key)) != NULL; +} diff --git a/semester_1/homework7/binarySearchTree/binarySearchTree/binarySearchTree.h b/semester_1/homework7/binarySearchTree/binarySearchTree/binarySearchTree.h new file mode 100644 index 0000000..9fec9b8 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/binarySearchTree/binarySearchTree.h @@ -0,0 +1,17 @@ +#pragma once +#include + +typedef struct Dictionary Dictionary; + +typedef enum DictionaryErrorCode +{ + ok, + memoryError +} DictionaryErrorCode; + +Dictionary *createDictionary(void); +char *getValue(Dictionary *const dictionary, const int key); +bool keyCheck(Dictionary *const dictionary, const int key); +DictionaryErrorCode append(Dictionary * const dictionary, int const key, char * value, bool const copyRequired); +void deleteElement(Dictionary * const dictionary, int const key); +void deleteDictionary(Dictionary * const dictionary); diff --git a/semester_1/homework7/binarySearchTree/main.c b/semester_1/homework7/binarySearchTree/main.c new file mode 100644 index 0000000..d982965 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/main.c @@ -0,0 +1,140 @@ +#include +#include +#include + +#include "binarySearchTree/binarySearchTree.h" +#include "String/String.h" +#include "tests/test.h" +#include "userInput.h" + +#define PROGRAM_FINISHED_CORRECTLY 0 +#define MEMORY_ERROR 1 +#define INPUT_ERROR 2 +#define TESTS_ARE_NOT_PASSED 3 + +#define SOMETHING_WENT_WRONG_MESSAGE "Похоже, что то пошло не так\n" + +const size_t commandsCount = 5; + +static void scanfCheck(int scanned, Dictionary * const dictionary) +{ + if (scanned != 1) + { + printf("%s", SOMETHING_WENT_WRONG_MESSAGE); + deleteDictionary(dictionary); + exit(INPUT_ERROR); + } +} + +static UserInput userInput(Dictionary * const dictionary) +{ + UserInput input = exitCommand; + scanfCheck(scanf("%d", &input), dictionary); + + while (input >= commandsCount) + { + printf("Проверьте правильность ввода\n"); + scanfCheck(scanf("%d", &input), dictionary); + } + + return input; +} + +static const UserInput getCommand(Dictionary * const dictionary) +{ + printf("\nДоступные команды:\n0 – выйти\n1 – добавить в словарь значение по ключу \n2 – получить из словаря значение по ключу\n3 – проверить наличие заданного ключа в словаре\n4 - удалить заданный ключ и значение по нему"); + printf("\nВведите номер, соответствующий команде, которую вы хотите выполнить\n"); + + UserInput input = userInput(dictionary); + + return input; +} + +int main(void) +{ + setlocale(LC_ALL, "Rus"); + if (!test()) + { + printf("Простите, но программа сейчас не работает\n"); + return TESTS_ARE_NOT_PASSED; + } + + Dictionary *dictionary = createDictionary(); + if (dictionary == NULL) + { + return MEMORY_ERROR; + } + + DictionaryErrorCode dictionaryErrorCode = ok; + size_t len = 0; + UserInput input = checkKeyCommand; + while (input != exitCommand) + { + input = getCommand(dictionary); + switch (input) + { + case appendCommand: + { + printf("Введите ключ: "); + int key = 0; + scanfCheck(scanf("%d", &key), dictionary); + fgetc(stdin); + printf("Введите значение: "); + char *value = getString(&len, stdin, '\n'); + if (value == NULL) + { + printf("Недостаточно памяти\n"); + deleteDictionary(dictionary); + return MEMORY_ERROR; + } + dictionaryErrorCode = append(dictionary, key, value, false); + break; + } + + case getValueCommand: + { + printf("Введите ключ: "); + int key = 0; + scanfCheck(scanf("%d", &key), dictionary); + char * value = getValue(dictionary, key); + if (value == NULL) + { + printf("Такого ключа нет в словаре\n"); + break; + } + printf("Значение по ключу %d: %s\n", key, value); + break; + } + + case checkKeyCommand: + { + printf("Введите ключ: "); + int key = 0; + scanfCheck(scanf("%d", &key), dictionary); + printf("%s", (keyCheck(dictionary, key) ? "Такой ключ есть в словаре\n" : "В словаре нет такого ключа\n")); + break; + } + + case deleteElementCommand: + { + printf("Введите ключ: "); + int key = 0; + scanfCheck(scanf("%d", &key), dictionary); + deleteElement(dictionary, key); + printf("Элемент удален\n"); + break; + } + + case exitCommand: + { + printf("Завершение работы\n"); + deleteDictionary(dictionary); + } + + default: + break; + } + } + + return PROGRAM_FINISHED_CORRECTLY; +} diff --git a/semester_1/homework7/binarySearchTree/tests/test.c b/semester_1/homework7/binarySearchTree/tests/test.c new file mode 100644 index 0000000..88fbb9d --- /dev/null +++ b/semester_1/homework7/binarySearchTree/tests/test.c @@ -0,0 +1,111 @@ +#include +#include + +#include "test.h" +#include "../binarySearchTree/binarySearchTree.h" +#include "../userInput.h" + +#include + +static bool testCase(size_t testLen, UserInput const *const testCommands, int const *const keys + , char **values, char const **charAnswers, bool const *const boolAnswers) +{ + Dictionary *dictionary = createDictionary(); + if (dictionary == NULL) + { + return false; + } + size_t currentKey = 0; + size_t currentValue = 0; + size_t currentAnswer = 0; + size_t currentBool = 0; + + DictionaryErrorCode dictionaryErrorCode = ok; + for (size_t currentTest = 0; currentTest < testLen; ++currentTest) + { + switch (testCommands[currentTest]) + { + case appendCommand: + { + + dictionaryErrorCode = append(dictionary, keys[currentKey], values[currentValue], true); + if (dictionaryErrorCode != ok) + { + deleteDictionary(dictionary); + return false; + } + ++currentKey; + ++currentValue; + break; + } + + case getValueCommand: + { + if (strcmp(getValue(dictionary, keys[currentKey]), charAnswers[currentAnswer]) != 0) + { + deleteDictionary(dictionary); + return false; + } + ++currentKey; + ++currentAnswer; + break; + } + + case checkKeyCommand: + { + + if (keyCheck(dictionary, keys[currentKey]) != boolAnswers[currentBool]) + { + deleteDictionary(dictionary); + return false; + } + ++currentKey; + ++currentBool; + break; + } + + case deleteElementCommand: + { + deleteElement(dictionary, keys[currentKey]); + if (keyCheck(dictionary, keys[currentKey])) + { + deleteDictionary(dictionary); + return false; + } + ++currentKey; + break; + } + + default: + break; + } + } + deleteDictionary(dictionary); + return true; +} + +const bool test(void) +{ + UserInput testCommands1[5] = {appendCommand, appendCommand, deleteElementCommand, checkKeyCommand, getValueCommand}; + int const testKeys1[5] = {5, 6, 6, 6, 5}; + char *testValues1[2] = {"five", "six"}; + char const *charAnswers1[1] = {"five"}; + bool const boolAnswers1[] = {false}; + bool testCase1 = testCase(5, testCommands1, testKeys1, testValues1, charAnswers1, boolAnswers1); + + UserInput testCommands2[5] = {checkKeyCommand, appendCommand, checkKeyCommand, deleteElementCommand, checkKeyCommand}; + int const testKeys2[5] = {1, 1, 1, 1, 1}; + char *testValues2[1] = {"one"}; + char const *charAnswers2[0] = {}; + bool const boolAnswers2[3] = {false, true, false}; + bool testCase2 = testCase(5, testCommands2, testKeys2, testValues2, charAnswers2, boolAnswers2); + + UserInput testCommands3[7] = {appendCommand, getValueCommand, appendCommand, getValueCommand, deleteElementCommand, appendCommand, getValueCommand}; + int const testKeys3[7] = {1, 1, 1, 1, 1, 1, 1}; + char *testValues3[3] = {"one", "two", "one"}; + char const *charAnswers3[3] = {"one", "two", "one"}; + bool const boolAnswers3[0] = {}; + bool testCase3 = testCase(4, testCommands3, testKeys3, testValues3, charAnswers3, boolAnswers3); + + return testCase1 && testCase2 && testCase3; +} diff --git a/semester_1/homework7/binarySearchTree/tests/test.h b/semester_1/homework7/binarySearchTree/tests/test.h new file mode 100644 index 0000000..6f31a79 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/tests/test.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#include "../binarySearchTree/binarySearchTree.h" + +const bool test(void); diff --git a/semester_1/homework7/binarySearchTree/userInput.h b/semester_1/homework7/binarySearchTree/userInput.h new file mode 100644 index 0000000..b873643 --- /dev/null +++ b/semester_1/homework7/binarySearchTree/userInput.h @@ -0,0 +1,10 @@ +#pragma once + +typedef enum UserInput +{ + exitCommand, + appendCommand, + getValueCommand, + checkKeyCommand, + deleteElementCommand +} UserInput;