From 79bbc7e8ba7e1954d51912bb79b536131ecfc805 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 02:54:37 +0300 Subject: [PATCH 01/19] Homework 7 - task 2 (WIP) --- homework_7/CMakeLists.txt | 2 + homework_7/task_2/CMakeLists.txt | 9 ++ homework_7/task_2/intStringDictionary.c | 143 ++++++++++++++++++++++++ homework_7/task_2/intStringDictionary.h | 13 +++ homework_7/task_2/main.c | 3 + homework_7/task_2/test.c | 11 ++ 6 files changed, 181 insertions(+) create mode 100644 homework_7/task_2/CMakeLists.txt create mode 100644 homework_7/task_2/intStringDictionary.c create mode 100644 homework_7/task_2/intStringDictionary.h create mode 100644 homework_7/task_2/main.c create mode 100644 homework_7/task_2/test.c diff --git a/homework_7/CMakeLists.txt b/homework_7/CMakeLists.txt index d33f737..0fdfa24 100644 --- a/homework_7/CMakeLists.txt +++ b/homework_7/CMakeLists.txt @@ -1,3 +1,5 @@ project(homework_7) set(homeworkName "${PROJECT_NAME}") + +add_subdirectory(task_2) diff --git a/homework_7/task_2/CMakeLists.txt b/homework_7/task_2/CMakeLists.txt new file mode 100644 index 0000000..7e6d313 --- /dev/null +++ b/homework_7/task_2/CMakeLists.txt @@ -0,0 +1,9 @@ +project("${homeworkName}_task_2") + +add_library(intStringDictionary intStringDictionary.c) + +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} intStringDictionary) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test intStringDictionary) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c new file mode 100644 index 0000000..839f200 --- /dev/null +++ b/homework_7/task_2/intStringDictionary.c @@ -0,0 +1,143 @@ +#include "intStringDictionary.h" + +#include + +typedef struct Node { + int key; + const char *value; + struct Node *left; + struct Node *right; +} Node; + +typedef struct IntStringDictionary { + Node *root; +} IntStringDictionary; + +bool createDictionary(IntStringDictionary **dictionary) { + *dictionary = malloc(sizeof(IntStringDictionary)); + if (*dictionary == NULL) { + return false; + } + + (*dictionary)->root = NULL; + + return true; +} + +static bool createNode(Node **node, int key, const char *value) { + *node = malloc(sizeof(Node)); + if (*node == NULL) { + return false; + } + + (*node)->key = key; + (*node)->value = value; + (*node)->left = NULL; + (*node)->right = NULL; + + return true; +} + +static bool addAfterNode(Node *node, int key, const char *value) { + Node *parent = NULL; + Node *child = node; + while (child != NULL) { + parent = child; + if (key > parent->key) { + child = parent->right; + } else if (key < parent->key) { + child = parent->left; + } else { + parent->value = value; + return true; + } + } + + if (parent == NULL) { + return false; + } + + Node **childPointer = key > parent->key ? &parent->right: &node->left; + + return createNode(childPointer, key, value); +} + +bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value) { + if (dictionary->root == NULL) { + return createNode(&dictionary->root, key, value); + } + + return addAfterNode(dictionary->root, key, value); +} + +Node *getNode(Node *node, int key) { + Node *previous = NULL; + while (true) { + if (node == NULL) { + return NULL; + } + + if (key < node->key) { + previous = node; + node = node->left; + } else if (key > node->key) { + previous = node; + node = node->right; + } else { + break; + } + } + + return node; +} + +const char *getValue(IntStringDictionary *dictionary, int key) { + Node *node = getNode(dictionary->root, key); + + return node == NULL ? NULL : node->value; +} + +bool containsKey(IntStringDictionary *dictionary, int key) { + Node *node = getNode(dictionary->root, key); + + return node != NULL; +} + +bool removeFromDictionary(IntStringDictionary *dictionary, int key) { + Node *node = getNode(dictionary->root, key); + if (node == NULL) { + return false; + } + + if (node == dictionary->root) { + if (node->left == NULL) { + dictionary->root = node->right; + return true; + } + + if (node->right == NULL) { + dictionary->root = node->left; + return true; + } + + Node *rightmostInLeft = NULL; // TODO: add rightmost search + rightmostInLeft->right = node->right; + dictionary->root = node->left; + + return true; + } + + if (node->left == NULL) { + // TODO: set parents left/right as node->right + return true; + } + + if (node->right == NULL) { + // TODO: set parents left/right as node->left + return true; + } + + Node *rightmostInLeft = NULL; // TODO: add rightmost search + rightmostInLeft->right = node->right; + // TODO: set parents left/right as node->right +} diff --git a/homework_7/task_2/intStringDictionary.h b/homework_7/task_2/intStringDictionary.h new file mode 100644 index 0000000..84a415f --- /dev/null +++ b/homework_7/task_2/intStringDictionary.h @@ -0,0 +1,13 @@ +#pragma once + +typedef struct IntStringDictionary IntStringDictionary; + +bool createDictionary(IntStringDictionary **dictionary); + +bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value); + +const char *getValue(IntStringDictionary *dictionary, int key); + +bool containsKey(IntStringDictionary *dictionary, int key); + +bool removeFromDictionary(IntStringDictionary *dictionary, int key); diff --git a/homework_7/task_2/main.c b/homework_7/task_2/main.c new file mode 100644 index 0000000..0eb6e89 --- /dev/null +++ b/homework_7/task_2/main.c @@ -0,0 +1,3 @@ +int main(void) { + +} diff --git a/homework_7/task_2/test.c b/homework_7/task_2/test.c new file mode 100644 index 0000000..9dc7980 --- /dev/null +++ b/homework_7/task_2/test.c @@ -0,0 +1,11 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include + +#include "intStringDictionary.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} From 6beb7fd9b230e8c8dd7ef3f606fd9ed85276ed7e Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:09:15 +0300 Subject: [PATCH 02/19] Added dictionary disposing (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 15 +++++++++++++++ homework_7/task_2/intStringDictionary.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index 839f200..a84e3ff 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -141,3 +141,18 @@ bool removeFromDictionary(IntStringDictionary *dictionary, int key) { rightmostInLeft->right = node->right; // TODO: set parents left/right as node->right } + +void disposeNode(Node *node) { + if (node == NULL) { + return; + } + + disposeNode(node->left); + disposeNode(node->right); + free(node); +} + +void disposeDictionary(IntStringDictionary *dictionary) { + disposeNode(dictionary->root); + free(dictionary); +} diff --git a/homework_7/task_2/intStringDictionary.h b/homework_7/task_2/intStringDictionary.h index 84a415f..ebf52e4 100644 --- a/homework_7/task_2/intStringDictionary.h +++ b/homework_7/task_2/intStringDictionary.h @@ -11,3 +11,5 @@ const char *getValue(IntStringDictionary *dictionary, int key); bool containsKey(IntStringDictionary *dictionary, int key); bool removeFromDictionary(IntStringDictionary *dictionary, int key); + +void disposeDictionary(IntStringDictionary *dictionary); From 8764824e509e17a2a391bf67b98593fd65eadca8 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:10:17 +0300 Subject: [PATCH 03/19] Fixed adding key-value (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index a84e3ff..08e4ed6 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -57,7 +57,7 @@ static bool addAfterNode(Node *node, int key, const char *value) { return false; } - Node **childPointer = key > parent->key ? &parent->right: &node->left; + Node **childPointer = key > parent->key ? &parent->right: &parent->left; return createNode(childPointer, key, value); } From 00579ea4dfdad768c447d0bb23b9db34c8bbadc5 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:11:28 +0300 Subject: [PATCH 04/19] Removed unused variable (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index 08e4ed6..a822bed 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -71,17 +71,14 @@ bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value } Node *getNode(Node *node, int key) { - Node *previous = NULL; while (true) { if (node == NULL) { return NULL; } if (key < node->key) { - previous = node; node = node->left; } else if (key > node->key) { - previous = node; node = node->right; } else { break; From 58d2a9f7a98bd456cd1ee7c71f53fb9f96b82a1e Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:12:25 +0300 Subject: [PATCH 05/19] Implemented removing value by key (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 46 ++++++++++++++++++++----- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index a822bed..1613fae 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -100,43 +100,73 @@ bool containsKey(IntStringDictionary *dictionary, int key) { return node != NULL; } +// returns rightmost child of given node, or node itself if right is NULL +Node *getRightmost(Node *node) { + while (node->right != NULL) { + node = node->right; + } + return node; +} + bool removeFromDictionary(IntStringDictionary *dictionary, int key) { - Node *node = getNode(dictionary->root, key); - if (node == NULL) { - return false; + Node *node = dictionary->root; + Node *previous = NULL; + while (true) { + if (node == NULL) { + return false; + } + + if (key < node->key) { + previous = node; + node = node->left; + } else if (key > node->key) { + previous = node; + node = node->right; + } else { + break; + } } if (node == dictionary->root) { if (node->left == NULL) { dictionary->root = node->right; + free(node); return true; } if (node->right == NULL) { dictionary->root = node->left; + free(node); return true; } - Node *rightmostInLeft = NULL; // TODO: add rightmost search + Node *rightmostInLeft = getRightmost(node->left); rightmostInLeft->right = node->right; dictionary->root = node->left; + free(node); + return true; } + Node **setNewNodeTo = key < previous->key ? &previous->left : &previous->right; + if (node->left == NULL) { - // TODO: set parents left/right as node->right + *setNewNodeTo = node->right; + free(node); return true; } if (node->right == NULL) { - // TODO: set parents left/right as node->left + *setNewNodeTo = node->left; + free(node); return true; } - Node *rightmostInLeft = NULL; // TODO: add rightmost search + Node *rightmostInLeft = getRightmost(node->left); rightmostInLeft->right = node->right; - // TODO: set parents left/right as node->right + *setNewNodeTo = node->left; + free(node); } void disposeNode(Node *node) { From bf634baeebec6edaccad6ea684d5233a749a9b5a Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:14:43 +0300 Subject: [PATCH 06/19] Added tests (hw7 task 2) --- homework_7/task_2/test.c | 98 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/homework_7/task_2/test.c b/homework_7/task_2/test.c index 9dc7980..0aba117 100644 --- a/homework_7/task_2/test.c +++ b/homework_7/task_2/test.c @@ -9,3 +9,101 @@ int main(int argc, const char *argv[]) { return ctest_main(argc, argv); } + +IntStringDictionary *createDict(void) { + IntStringDictionary *dictionary = NULL; + ASSERT_TRUE(createDictionary(&dictionary)); + return dictionary; +} + +void addToDict(IntStringDictionary *dict, int key, const char *value) { + ASSERT_TRUE(addToDictionary(dict, key, value)); +} + +CTEST(dictonaryTests, emptyTest) { + IntStringDictionary *dict = createDict(); + disposeDictionary(dict); +} + +CTEST(dictonaryTests, singleEntryTest) { + IntStringDictionary *dict = createDict(); + + const int key = 0; + const char *value = "string_0"; + addToDict(dict, key, value); + ASSERT_TRUE(containsKey(dict, key)); + + ASSERT_STR(getValue(dict, key), value); + + ASSERT_TRUE(removeFromDictionary(dict, key)); + ASSERT_FALSE(removeFromDictionary(dict, key)); + ASSERT_FALSE(containsKey(dict, key)); + ASSERT_NULL(getValue(dict, key)); + + disposeDictionary(dict); +} + +void assertAddingAndRemoving(int keys[], const char *values[], int size) { + IntStringDictionary *dict = createDict(); + + for (int i = 0; i < size; ++i) { + addToDict(dict, keys[i], values[i]); + ASSERT_TRUE(containsKey(dict, keys[i])); + ASSERT_STR(getValue(dict, keys[i]), values[i]); + } + + for (int i = 0; i < size; ++i) { + ASSERT_TRUE(containsKey(dict, keys[i])); + ASSERT_STR(getValue(dict, keys[i]), values[i]); + } + + for (int i = 0; i < size; ++i) { + // offset index so values will be removed a bit randomly + int index = (i + (size * 2 / 3)) % size; + + ASSERT_TRUE(removeFromDictionary(dict, keys[index])); + ASSERT_FALSE(removeFromDictionary(dict, keys[index])); + ASSERT_FALSE(containsKey(dict, keys[index])); + ASSERT_NULL(getValue(dict, keys[index])); + } + + disposeDictionary(dict); +} + +CTEST(dictonaryTests, binaryEntriesTest) { + int keys[15] = { 32, 16, 48, 8, 24, 40, 56, 4, 12, 20, 28, 36, 44, 52, 60 }; + const char *values[15] = { "32", "16", "48", "8", "24", "40", "56", "4", "12", "20", "28", "36", "44", "52", "60" }; + assertAddingAndRemoving(keys, values, 15); +} + +CTEST(dictonaryTests, randomEntriesTest) { +#define size 16384 + int keys[size] = { 0 }; + const char *values[size] = { 0 }; + + srand(453563458); + + const int minValue = -14274; + const int maxValue = 17343; + for (int i = 0; i < size; ++i) { + while (true) { + int value = rand() * (maxValue - minValue) / RAND_MAX + minValue; + bool contains = false; + for (int j = 0; j < i; ++j) { + if (keys[j] == value) { + contains = true; + break; + } + } + if (!contains) { + keys[i] = value; + break; + } + } + + values[i] = NULL; + } + + assertAddingAndRemoving(keys, values, size); +#undef size +} From bea7662c68123cdbe12ed7e5434c2b9074b79cf1 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:19:50 +0300 Subject: [PATCH 07/19] Add non-NULL value in tests (hw7 task 2) --- homework_7/task_2/test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homework_7/task_2/test.c b/homework_7/task_2/test.c index 0aba117..5336606 100644 --- a/homework_7/task_2/test.c +++ b/homework_7/task_2/test.c @@ -83,6 +83,8 @@ CTEST(dictonaryTests, randomEntriesTest) { srand(453563458); + const char *string = "random_string"; + const int minValue = -14274; const int maxValue = 17343; for (int i = 0; i < size; ++i) { @@ -101,7 +103,7 @@ CTEST(dictonaryTests, randomEntriesTest) { } } - values[i] = NULL; + values[i] = string; } assertAddingAndRemoving(keys, values, size); From 5fd6ce0855a386c30605aa7638af728f800c5831 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:24:46 +0300 Subject: [PATCH 08/19] Added missing return statement (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 1 + 1 file changed, 1 insertion(+) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index 1613fae..98426aa 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -167,6 +167,7 @@ bool removeFromDictionary(IntStringDictionary *dictionary, int key) { rightmostInLeft->right = node->right; *setNewNodeTo = node->left; free(node); + return true; } void disposeNode(Node *node) { From 116283140c4780d73cbdf691da1565243eb02385 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:32:02 +0300 Subject: [PATCH 09/19] Added comments (hw7 task 2) --- homework_7/task_2/intStringDictionary.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/homework_7/task_2/intStringDictionary.h b/homework_7/task_2/intStringDictionary.h index ebf52e4..5341de3 100644 --- a/homework_7/task_2/intStringDictionary.h +++ b/homework_7/task_2/intStringDictionary.h @@ -1,15 +1,38 @@ #pragma once +/// @brief Dictionary of `int` keys associated with `const char *` values typedef struct IntStringDictionary IntStringDictionary; +/// @brief Creates new dictionary +/// @param dictionary Pointer to write new dictionary to +/// @return `true` if created successfully, `false` otherwise (allocation failed) bool createDictionary(IntStringDictionary **dictionary); +/// @brief Adds key and associated with it value to dictionary +/// @param dictionary Dictionary to add key and value to +/// @param key Key to add +/// @param value Value to add +/// @return `true` if added successfully, `false` otherwise (allocation failed) bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value); +/// @brief Gets value corresponding to given key +/// @param dictionary Dictionary to get value from +/// @param key Key associated with value +/// @return String associated with key, or `NULL` if value was not found const char *getValue(IntStringDictionary *dictionary, int key); +/// @brief Checks if dictionary contains given key +/// @param dictionary Dictionary to check +/// @param key Key to check +/// @return `true` if key exists in dictionary, `false` otherwise bool containsKey(IntStringDictionary *dictionary, int key); +/// @brief Removes value from dictionary using given key +/// @param dictionary Dictionary to remove value from +/// @param key Key associated with value to be removed +/// @return `true` if removed successfully, `false` otherwise (key does not exist in dictionary) bool removeFromDictionary(IntStringDictionary *dictionary, int key); +/// @brief Disposes dictionary and all of its entries +/// @param dictionary Dictionary to dispose void disposeDictionary(IntStringDictionary *dictionary); From 2526fd1bc71f5dc2b598dd1046c4089938e54707 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:35:07 +0300 Subject: [PATCH 10/19] Replaced const char * -> char * (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 10 +++++----- homework_7/task_2/intStringDictionary.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index 98426aa..8206f82 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -4,7 +4,7 @@ typedef struct Node { int key; - const char *value; + char *value; struct Node *left; struct Node *right; } Node; @@ -24,7 +24,7 @@ bool createDictionary(IntStringDictionary **dictionary) { return true; } -static bool createNode(Node **node, int key, const char *value) { +static bool createNode(Node **node, int key, char *value) { *node = malloc(sizeof(Node)); if (*node == NULL) { return false; @@ -38,7 +38,7 @@ static bool createNode(Node **node, int key, const char *value) { return true; } -static bool addAfterNode(Node *node, int key, const char *value) { +static bool addAfterNode(Node *node, int key, char *value) { Node *parent = NULL; Node *child = node; while (child != NULL) { @@ -62,7 +62,7 @@ static bool addAfterNode(Node *node, int key, const char *value) { return createNode(childPointer, key, value); } -bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value) { +bool addToDictionary(IntStringDictionary *dictionary, int key, char *value) { if (dictionary->root == NULL) { return createNode(&dictionary->root, key, value); } @@ -88,7 +88,7 @@ Node *getNode(Node *node, int key) { return node; } -const char *getValue(IntStringDictionary *dictionary, int key) { +char *getValue(IntStringDictionary *dictionary, int key) { Node *node = getNode(dictionary->root, key); return node == NULL ? NULL : node->value; diff --git a/homework_7/task_2/intStringDictionary.h b/homework_7/task_2/intStringDictionary.h index 5341de3..9be4130 100644 --- a/homework_7/task_2/intStringDictionary.h +++ b/homework_7/task_2/intStringDictionary.h @@ -1,6 +1,6 @@ #pragma once -/// @brief Dictionary of `int` keys associated with `const char *` values +/// @brief Dictionary of `int` keys associated with `char *` values typedef struct IntStringDictionary IntStringDictionary; /// @brief Creates new dictionary @@ -13,13 +13,13 @@ bool createDictionary(IntStringDictionary **dictionary); /// @param key Key to add /// @param value Value to add /// @return `true` if added successfully, `false` otherwise (allocation failed) -bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value); +bool addToDictionary(IntStringDictionary *dictionary, int key, char *value); /// @brief Gets value corresponding to given key /// @param dictionary Dictionary to get value from /// @param key Key associated with value /// @return String associated with key, or `NULL` if value was not found -const char *getValue(IntStringDictionary *dictionary, int key); +char *getValue(IntStringDictionary *dictionary, int key); /// @brief Checks if dictionary contains given key /// @param dictionary Dictionary to check From 248407ae5dd2432b995318f0cdfca947e05da1bc Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 21:10:19 +0300 Subject: [PATCH 11/19] Added interactive mode (hw7 task 2) --- homework_7/task_2/main.c | 139 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/homework_7/task_2/main.c b/homework_7/task_2/main.c index 0eb6e89..c19d148 100644 --- a/homework_7/task_2/main.c +++ b/homework_7/task_2/main.c @@ -1,3 +1,142 @@ +#include +#include + +#include "intStringDictionary.h" + +void addEntryCommand(IntStringDictionary *dictionary) { + printf("Enter key to add: "); + int key = 0; + if (scanf("%d", &key) != 1) { + printf("Error: not a number\n"); + return; + } + + printf("Enter value to add: "); + char buffer[256] = { 0 }; + if (scanf("%255s", buffer) != 1) { + printf("Error: not a string\n"); + return; + } + + char *newString = strdup(buffer); + + if (newString == NULL || !addToDictionary(dictionary, key, newString)) { + printf("Error: cannot add new entry\n"); + } +} + +void getValueCommand(IntStringDictionary *dictionary) { + printf("Enter a key of value to retrieve: "); + int key = 0; + if (scanf("%d", &key) != 1) { + printf("Error: not a number\n"); + return; + } + + char *value = getValue(dictionary, key); + if (value == NULL) { + printf("Value with key '%d' does not exist in dictionary\n", key); + } else { + printf("Found value with key '%d': \"%s\"\n", key, value); + } +} + +void checkIfExistsCommand(IntStringDictionary *dictionary) { + printf("Enter a key of value to check: "); + int key = 0; + if (scanf("%d", &key) != 1) { + printf("Error: not a number\n"); + return; + } + + printf("Key '%d' %s in dictionary\n", key, containsKey(dictionary, key) ? "exists" : "does not exist"); +} + +void removeEntryCommand(IntStringDictionary *dictionary) { + printf("Enter a key of value to remove: "); + int key = 0; + if (scanf("%d", &key) != 1) { + printf("Error: not a number\n"); + return; + } + + if (!removeFromDictionary(dictionary, key)) { + printf("Error: cannot remove value; it is not stored in dictionary\n"); + } +} + +int readCommand(void) { + int command = -1; + if (scanf("%d", &command) != 1) { + command = -1; + } + while (getchar() != '\n') {} + switch (command) { + case 0: + case 1: + case 2: + case 3: + case 4: + return command; + default: + printf("Error: unknown command\n"); + return -1; + } +} + +bool doConversation(IntStringDictionary *dictionary) { + printf("Dictionary\n"); + printf("Available commands: \n"); + printf(" 0 - exit;\n"); + printf(" 1 - add new entry (key and value);\n"); + printf(" 2 - get value by key;\n"); + printf(" 3 - check if key exists in dictionary;\n"); + printf(" 4 - remove entry by key;\n"); + + while (true) { + printf("dictionary> "); + int command = readCommand(); + switch (command) + { + case -1: + break; + + case 0: + return true; + + case 1: + addEntryCommand(dictionary); + break; + + case 2: + getValueCommand(dictionary); + break; + + case 3: + checkIfExistsCommand(dictionary); + break; + + case 4: + removeEntryCommand(dictionary); + break; + + default: + printf("Error: unknown state\n"); + return false; + } + } +} + int main(void) { + IntStringDictionary *dictionary = NULL; + if (!createDictionary(&dictionary)) { + printf("Error: allocation failed\n"); + return 1; + } + if (!doConversation(dictionary)) { + disposeDictionary(dictionary); + return 1; + } + disposeDictionary(dictionary); } From 9bb6ab6161308c51dfb4b331f3f423d1a8dddfb4 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 21:17:18 +0300 Subject: [PATCH 12/19] Copy whole string when adding entry (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index 8206f82..a393cdd 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -1,6 +1,7 @@ #include "intStringDictionary.h" #include +#include typedef struct Node { int key; @@ -31,7 +32,13 @@ static bool createNode(Node **node, int key, char *value) { } (*node)->key = key; - (*node)->value = value; + + char *valueCopy = strdup(value); + if (valueCopy == NULL) { + return false; + } + (*node)->value = valueCopy; + (*node)->left = NULL; (*node)->right = NULL; @@ -48,7 +55,12 @@ static bool addAfterNode(Node *node, int key, char *value) { } else if (key < parent->key) { child = parent->left; } else { - parent->value = value; + free(parent->value); + char *valueCopy = strdup(value); + if (valueCopy == NULL) { + return false; + } + parent->value = valueCopy; return true; } } @@ -177,6 +189,8 @@ void disposeNode(Node *node) { disposeNode(node->left); disposeNode(node->right); + + free(node->value); free(node); } From 793c8a104c398a5d15cd96501f546ea0a2ba3d34 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 21:18:05 +0300 Subject: [PATCH 13/19] Input strings are 'const' again (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 6 +++--- homework_7/task_2/intStringDictionary.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index a393cdd..bdd9e20 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -25,7 +25,7 @@ bool createDictionary(IntStringDictionary **dictionary) { return true; } -static bool createNode(Node **node, int key, char *value) { +static bool createNode(Node **node, int key, const char *value) { *node = malloc(sizeof(Node)); if (*node == NULL) { return false; @@ -45,7 +45,7 @@ static bool createNode(Node **node, int key, char *value) { return true; } -static bool addAfterNode(Node *node, int key, char *value) { +static bool addAfterNode(Node *node, int key, const char *value) { Node *parent = NULL; Node *child = node; while (child != NULL) { @@ -74,7 +74,7 @@ static bool addAfterNode(Node *node, int key, char *value) { return createNode(childPointer, key, value); } -bool addToDictionary(IntStringDictionary *dictionary, int key, char *value) { +bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value) { if (dictionary->root == NULL) { return createNode(&dictionary->root, key, value); } diff --git a/homework_7/task_2/intStringDictionary.h b/homework_7/task_2/intStringDictionary.h index 9be4130..0f39024 100644 --- a/homework_7/task_2/intStringDictionary.h +++ b/homework_7/task_2/intStringDictionary.h @@ -13,7 +13,7 @@ bool createDictionary(IntStringDictionary **dictionary); /// @param key Key to add /// @param value Value to add /// @return `true` if added successfully, `false` otherwise (allocation failed) -bool addToDictionary(IntStringDictionary *dictionary, int key, char *value); +bool addToDictionary(IntStringDictionary *dictionary, int key, const char *value); /// @brief Gets value corresponding to given key /// @param dictionary Dictionary to get value from From 5a69277aaa641bc8d9c80eb4632e026d99382c2f Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 12 Nov 2024 21:19:46 +0300 Subject: [PATCH 14/19] Applied new changes to interactive mode (hw7 task 2) --- homework_7/task_2/main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/homework_7/task_2/main.c b/homework_7/task_2/main.c index c19d148..a69936f 100644 --- a/homework_7/task_2/main.c +++ b/homework_7/task_2/main.c @@ -18,9 +18,7 @@ void addEntryCommand(IntStringDictionary *dictionary) { return; } - char *newString = strdup(buffer); - - if (newString == NULL || !addToDictionary(dictionary, key, newString)) { + if (!addToDictionary(dictionary, key, buffer)) { printf("Error: cannot add new entry\n"); } } From 100ad86714501a85b62fe05353112444d4fd339b Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Thu, 14 Nov 2024 18:38:50 +0300 Subject: [PATCH 15/19] Attempt make tests run in github actions --- homework_7/task_2/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homework_7/task_2/test.c b/homework_7/task_2/test.c index 5336606..fe85092 100644 --- a/homework_7/task_2/test.c +++ b/homework_7/task_2/test.c @@ -76,7 +76,7 @@ CTEST(dictonaryTests, binaryEntriesTest) { assertAddingAndRemoving(keys, values, 15); } -CTEST(dictonaryTests, randomEntriesTest) { +CTEST_SKIP(dictonaryTests, randomEntriesTest) { #define size 16384 int keys[size] = { 0 }; const char *values[size] = { 0 }; From 4bbf1c81f73c8c559f98ddb984e5a6a7fb902516 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:00:43 +0300 Subject: [PATCH 16/19] Fixed random test (hw7 task 2) --- homework_7/task_2/test.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/homework_7/task_2/test.c b/homework_7/task_2/test.c index fe85092..22791e9 100644 --- a/homework_7/task_2/test.c +++ b/homework_7/task_2/test.c @@ -76,34 +76,27 @@ CTEST(dictonaryTests, binaryEntriesTest) { assertAddingAndRemoving(keys, values, 15); } -CTEST_SKIP(dictonaryTests, randomEntriesTest) { +CTEST(dictonaryTests, randomEntriesTest) { #define size 16384 int keys[size] = { 0 }; const char *values[size] = { 0 }; - srand(453563458); - const char *string = "random_string"; + for (int i = 0; i < size; ++i) { + keys[i] = i * 2 - 24517; + values[i] = string; + } + + srand(453563458); - const int minValue = -14274; - const int maxValue = 17343; for (int i = 0; i < size; ++i) { - while (true) { - int value = rand() * (maxValue - minValue) / RAND_MAX + minValue; - bool contains = false; - for (int j = 0; j < i; ++j) { - if (keys[j] == value) { - contains = true; - break; - } - } - if (!contains) { - keys[i] = value; - break; - } - } + int index = (rand() % (size - i)) + i; - values[i] = string; + int key = keys[i]; + keys[i] = keys[index]; + keys[index] = key; + + // dont swap values, they are all the same } assertAddingAndRemoving(keys, values, size); From b095c66256c5fa4dc8a8a16bcc29257f66da4282 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 10 Dec 2024 03:27:33 +0300 Subject: [PATCH 17/19] Added stdbool.h includes (hw7 task 2) --- homework_7/task_2/intStringDictionary.c | 1 + homework_7/task_2/intStringDictionary.h | 2 ++ homework_7/task_2/main.c | 1 + 3 files changed, 4 insertions(+) diff --git a/homework_7/task_2/intStringDictionary.c b/homework_7/task_2/intStringDictionary.c index bdd9e20..9c262cc 100644 --- a/homework_7/task_2/intStringDictionary.c +++ b/homework_7/task_2/intStringDictionary.c @@ -1,5 +1,6 @@ #include "intStringDictionary.h" +#include #include #include diff --git a/homework_7/task_2/intStringDictionary.h b/homework_7/task_2/intStringDictionary.h index 0f39024..a080eb8 100644 --- a/homework_7/task_2/intStringDictionary.h +++ b/homework_7/task_2/intStringDictionary.h @@ -1,5 +1,7 @@ #pragma once +#include + /// @brief Dictionary of `int` keys associated with `char *` values typedef struct IntStringDictionary IntStringDictionary; diff --git a/homework_7/task_2/main.c b/homework_7/task_2/main.c index a69936f..915b075 100644 --- a/homework_7/task_2/main.c +++ b/homework_7/task_2/main.c @@ -1,3 +1,4 @@ +#include #include #include From 0576464c8c789fc13fcb9f4f71027a0785ad4955 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 10 Dec 2024 03:54:44 +0300 Subject: [PATCH 18/19] Removed unused string.h include (hw7 task 2) --- homework_7/task_2/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/homework_7/task_2/main.c b/homework_7/task_2/main.c index 915b075..f122493 100644 --- a/homework_7/task_2/main.c +++ b/homework_7/task_2/main.c @@ -1,6 +1,5 @@ #include #include -#include #include "intStringDictionary.h" From e44c99809cbc5072058c6370440ed482ead5ddb9 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 25 Dec 2024 19:34:32 +0300 Subject: [PATCH 19/19] Added task name to README (hw7 task 2) --- homework_7/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homework_7/README.md b/homework_7/README.md index 20152e5..446a696 100644 --- a/homework_7/README.md +++ b/homework_7/README.md @@ -1 +1,3 @@ # Homework 7 + +[Task 2. Search tree](/homework_7/task_2)