From 0348f5f2cbbd24e19035777dd83df34682ef583f Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:24:27 +0300 Subject: [PATCH 01/33] Homework 10 - task 1 (WIP) --- CMakeLists.txt | 1 + homework_10/CMakeLists.txt | 5 + homework_10/task_1/CMakeLists.txt | 9 + homework_10/task_1/graph.c | 562 ++++++++++++++++++++++++++++++ homework_10/task_1/graph.h | 15 + homework_10/task_1/main.c | 5 + homework_10/task_1/test.c | 9 + 7 files changed, 606 insertions(+) create mode 100644 homework_10/CMakeLists.txt create mode 100644 homework_10/task_1/CMakeLists.txt create mode 100644 homework_10/task_1/graph.c create mode 100644 homework_10/task_1/graph.h create mode 100644 homework_10/task_1/main.c create mode 100644 homework_10/task_1/test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index b49a297..e1579e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,3 +7,4 @@ set(CMAKE_C_STANDARD_REQUIRED TRUE) add_compile_options(-Wall -Wextra) add_subdirectory(homework_2) +add_subdirectory(homework_10) diff --git a/homework_10/CMakeLists.txt b/homework_10/CMakeLists.txt new file mode 100644 index 0000000..d059869 --- /dev/null +++ b/homework_10/CMakeLists.txt @@ -0,0 +1,5 @@ +project(homework_10) + +set(homeworkName "${PROJECT_NAME}") + +add_subdirectory(task_1) diff --git a/homework_10/task_1/CMakeLists.txt b/homework_10/task_1/CMakeLists.txt new file mode 100644 index 0000000..8a35aa9 --- /dev/null +++ b/homework_10/task_1/CMakeLists.txt @@ -0,0 +1,9 @@ +project("${homeworkName}_task_1") + +add_library(graph graph.c) + +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} graph) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test graph) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c new file mode 100644 index 0000000..bb377d7 --- /dev/null +++ b/homework_10/task_1/graph.c @@ -0,0 +1,562 @@ +#include "graph.h" + +#include +#include + +static bool tryExtendArrayByOne(void **elements, int count, int *capacity) { + if (count + 1 >= *capacity) { + *capacity *= 4; + void *newData = realloc(*elements, *capacity); + if (newData == NULL) { + return false; + } + *elements = newData; + } + + return true; +} + +#pragma region NodeHashtable + +typedef struct { + GraphNode *node; + int distance; +} NodeHashtableData; + +typedef struct { + NodeHashtableData *data; + int count; + int capacity; +} Bucket; + +typedef struct { + Bucket *buckets; + int count; + int capacity; +} NodeHashtable; + +typedef struct { + NodeHashtable *hashtable; + int bucketIndex; + int listIndex; +} HashtableIterator; + +static void disposeBuckets(NodeHashtable *hashtable) { + for (int i = 0; i < hashtable->capacity; ++i) { + free(hashtable->buckets[i].data); + } +} + +static bool createHashtable(NodeHashtable **hashtable, int capacity) { + NodeHashtable *newHashtable = malloc(sizeof(NodeHashtable)); + + if (newHashtable == NULL) { + return false; + } + + newHashtable->count = 0; + newHashtable->capacity = capacity; + newHashtable->buckets = calloc(newHashtable->capacity, sizeof(Bucket)); + + if (newHashtable->buckets == NULL) { + free(newHashtable); + return false; + } + + bool failed = false; + for (int i = 0; i < newHashtable->capacity; ++i) { + Bucket bucket = newHashtable->buckets[i]; + bucket.count = 0; + bucket.capacity = 8; + bucket.data = calloc(bucket.capacity, sizeof(NodeHashtableData)); + if (bucket.data == NULL) { + failed = false; + break; + } + } + + if (failed) { + disposeBuckets(newHashtable); + free(newHashtable); + return false; + } + + *hashtable = newHashtable; + return true; +} + +bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance, bool *replacedValue); + +static bool expandHashtable(NodeHashtable *hashtable) { + int newCapacity = hashtable->capacity * 4; + + NodeHashtable *newHashtable = NULL; + if (!createHashtable(&newHashtable, newCapacity)) { + return false; + } + + for (int i = 0; i < hashtable->count; ++i) { + Bucket bucket = hashtable->buckets[i]; + for (int j = 0; j < bucket.count; ++j) { + addDistanceToHashtable(newHashtable, bucket.data[j].node, bucket.data[j].distance, NULL); + } + } + + disposeBuckets(hashtable); + + *hashtable = *newHashtable; + + free(newHashtable); + + return true; +} + +bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance, bool *replacedValue) { + if ((float)hashtable->count / hashtable->capacity > 4.0) { + expandHashtable(hashtable); + } + + int bucketIndex = (size_t)node % hashtable->capacity; + Bucket bucket = hashtable->buckets[bucketIndex]; + + for (int i = 0; i < bucket.count; ++i) { + if (bucket.data[i].node == node) { + if (replacedValue != NULL) { + *replacedValue = true; + } + + bucket.data[i].distance = distance; + return true; + } + } + + if (!tryExtendArrayByOne((void**)&bucket.data, bucket.count, &bucket.capacity)) { + return false; + } + + bucket.data[bucket.count].node = node; + bucket.data[bucket.count].distance = distance; + + ++bucket.count; + + if (replacedValue != NULL) { + *replacedValue = false; + } + + return true; +} + +bool getDistanceFromHashtable(NodeHashtable *hashtable, GraphNode *node, int *distance) { + int bucketIndex = (size_t)node % hashtable->capacity; + Bucket bucket = hashtable->buckets[bucketIndex]; + + for (int i = 0; i < bucket.count; ++i) { + if (bucket.data[i].node == node) { + if (distance != NULL) { + *distance = bucket.data[i].distance; + } + return true; + } + } + + return false; +} + +HashtableIterator getIterator(NodeHashtable *hashtable) { + return (HashtableIterator) { .hashtable = hashtable, .bucketIndex = 0, .listIndex = 0 }; +} + +bool moveNext(HashtableIterator *iterator) { + for (; iterator->bucketIndex < iterator->hashtable->capacity; ++iterator->bucketIndex) { + Bucket bucket = iterator->hashtable->buckets[iterator->bucketIndex]; + for (; iterator->listIndex < bucket.count; ++iterator->listIndex) { + return true; + } + } + return false; +} + +NodeHashtableData getCurrent(HashtableIterator iterator) { + return iterator.hashtable->buckets[iterator.bucketIndex].data[iterator.listIndex]; +} + +void disposeHashtable(NodeHashtable *hashtable) { + if (hashtable == NULL) { + return; + } + disposeBuckets(hashtable); + free(hashtable); +} + +#pragma endregion + +typedef struct GraphNode { + NodeHashtable *neighbors; +} GraphNode; + +bool createNode(GraphNode **node) { + GraphNode *newNode = malloc(sizeof(GraphNode)); + if (newNode == NULL) { + return false; + } + + if (!createHashtable(&newNode->neighbors, 64)) { + free(newNode); + return false; + } + + *node = newNode; + + return true; +} + +static bool addNeighbor(GraphNode *node, GraphNode *neighbor, int distance) { + bool wasReplaced = false; + if (!addDistanceToHashtable(node->neighbors, neighbor, distance, &wasReplaced)) { + return false; + } + + if (wasReplaced) { + // TODO: do something + } + + return true; +} + +bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { + return addNeighbor(nodeA, nodeB, distance) && addNeighbor(nodeB, nodeA, distance); +} + +bool getAllNeighbors(GraphNode *node, GraphNode **neighbors, int *length) { + *neighbors = calloc(node->neighbors->count, sizeof(GraphNode *)); + if (*neighbors == NULL) { + return false; + } + + int count = 0; + HashtableIterator iterator = getIterator(node->neighbors); + while (moveNext(&iterator)) { + neighbors[count] = getCurrent(iterator).node; + ++count; + } + + *length = count; + return true; +} + +typedef struct Country { + GraphNode **nodes; + int count; +} Country; + +#pragma region Queue + +typedef struct QNode { + NodeHashtableData data; + struct QNode *next; +} QNode; + +typedef struct { + QNode *first; +} Queue; + +bool createQueue(Queue **queue) { + *queue = calloc(1, sizeof(Queue)); + if (*queue == NULL) { + return false; + } + return true; +} + +bool enqueue(Queue *queue, NodeHashtableData data) { + QNode *node = malloc(sizeof(QNode)); + if (node == NULL) { + return false; + } + + node->data = data; + node->next = NULL; + + if (queue->first == NULL) { + queue->first = node; + return true; + } + + if (data.distance < queue->first->data.distance) { + node->next = queue->first; + queue->first = node; + return true; + } + + QNode *last = queue->first; + while (last->next != NULL) { + if (last->next->data.distance > data.distance) { + break; + } + + last = last->next; + } + + node->next = last->next; + last->next = node; + + return true; +} + +bool isEmpty(Queue *queue) { + if (queue->first == NULL) { + return false; + } + return true; +} + +bool dequeueWithMinDistance(Queue *queue, NodeHashtableData *data) { + if (!isEmpty(queue)) { + return false; + } + + QNode *first = queue->first; + + *data = first->data; + + queue->first = first->next; + + free(first); + + return true; +} + +void disposeQueue(Queue *queue) { + if (queue == NULL) { + return; + } + QNode *node = queue->first; + while (node != NULL) { + QNode *next = node->next; + free(node); + node = next; + } + free(queue); +} + +#pragma endregion + +bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount) { + NodeHashtable *capturedCities = NULL; + if (!createHashtable(&capturedCities, 64)) { + return false; + } + + Queue **queues = calloc(capitalsCount, sizeof(Queue *)); + if (queues == NULL) { + disposeHashtable(capturedCities); + return false; + } + + NodeHashtable **countriesWithDistances = calloc(capitalsCount, sizeof(NodeHashtable *)); + if (countries == NULL) { + disposeHashtable(capturedCities); + free(queues); + return false; + } + + int *nodesPerCountry = calloc(capitalsCount, sizeof(int)); + if (nodesPerCountry == NULL) { + disposeHashtable(capturedCities); + free(queues); + free(countriesWithDistances); + return false; + } + + bool failed = false; + for (int i = 0; i < capitalsCount; ++i) { + NodeHashtableData data = { .node = capitals[i], .distance = 0 }; + + if (!createQueue(&queues[i])) { + failed = true; + break; + } + + if (!createHashtable(&countriesWithDistances[i], 64)) { + failed = true; + break; + } + + if (!enqueue(queues[i], data)) { + failed = true; + break; + } + + if (addDistanceToHashtable(countriesWithDistances[i], data.node, data.distance, NULL)) { + failed = true; + break; + } + } + + if (failed) { + for (int i = 0; i < capitalsCount; ++i) { + disposeQueue(queues[i]); + disposeHashtable(countriesWithDistances[i]); + } + disposeHashtable(capturedCities); + return false; + } + + int step = -1; + while (true) { + int emptyCount = 0; + for (int i = 0; i < capitalsCount; ++i) { + if (isEmpty(queues[i])) { + ++emptyCount; + } + } + + if (emptyCount == capitalsCount) { + break; + } + + ++step; + step %= capitalsCount; + Queue *countryQueue = queues[step]; + + NodeHashtableData closestData = { 0 }; + bool queueIsEmpty = false; + while (true) { + if (!dequeueWithMinDistance(countryQueue, &closestData)) { + queueIsEmpty = true; + break; + } + + if (!getDistanceFromHashtable(capturedCities, closestData.node, NULL)) { + queueIsEmpty = false; + break; + } + } + + if (queueIsEmpty) { + continue; + } + + GraphNode *closestNode = closestData.node; + + int distanceToCapital = 0; + if (!getDistanceFromHashtable(countriesWithDistances[step], closestNode, &distanceToCapital)) { + failed = true; + break; + } + + HashtableIterator iterator = getIterator(closestNode->neighbors); + while (moveNext(&iterator)) { + NodeHashtableData neighborData = getCurrent(iterator); + GraphNode *neighbor = neighborData.node; + + if (getDistanceFromHashtable(capturedCities, neighbor, NULL)) { + continue; + } + + int neighborDistanceToCapital = distanceToCapital + neighborData.distance; + if (!enqueue(countryQueue, (NodeHashtableData) { .node = neighbor, .distance = neighborDistanceToCapital })) { + failed = true; + break; + } + + int newDistance = neighborDistanceToCapital; + int storedDistance = 0; + if (getDistanceFromHashtable(countriesWithDistances[step], neighbor, &storedDistance)) { + newDistance = newDistance < storedDistance ? newDistance : storedDistance; + } + + if (!addDistanceToHashtable(countriesWithDistances[step], neighbor, newDistance, NULL)) { + failed = true; + break; + } + } + + if (failed) { + break; + } + + ++nodesPerCountry[step]; + } + + for (int i = 0; i < capitalsCount; ++i) { + disposeQueue(queues[i]); + } + free(queues); + disposeHashtable(capturedCities); + + if (failed) { + for (int i = 0; i < capitalsCount; ++i) { + disposeHashtable(countriesWithDistances[i]); + } + free(countriesWithDistances); + free(nodesPerCountry); + return false; + } + + *countries = calloc(capitalsCount, sizeof(Country *)); + if (*countries == NULL) { + for (int i = 0; i < capitalsCount; ++i) { + disposeHashtable(countriesWithDistances[i]); + } + free(countriesWithDistances); + free(nodesPerCountry); + return false; + } + + for (int i = 0; i < capitalsCount; ++i) { + Country *country = calloc(1, sizeof(Country)); + if (country == NULL) { + failed = true; + break; + } + + country->count = nodesPerCountry[i]; + country->nodes = calloc(country->count, sizeof(GraphNode *)); + if (country->nodes == NULL) { + failed = true; + break; + } + HashtableIterator iterator = getIterator(countriesWithDistances[i]); + int index = 0; + while (moveNext(&iterator)) { + country->nodes[index] = getCurrent(iterator).node; + ++index; + } + (*countries)[i] = country; + } + + for (int i = 0; i < capitalsCount; ++i) { + disposeHashtable(countriesWithDistances[i]); + free(countriesWithDistances); + } + free(nodesPerCountry); + + if (failed) { + for (int i = 0; i < capitalsCount; ++i) { + Country *country = (*countries)[i]; + if (country == NULL) { + continue; + } + free(country->nodes); + free(country); + } + free(*countries); + return false; + } + + return true; +} + +bool getAllCities(Country *country, GraphNode **nodes, int *length) { + *nodes = calloc(country->count, sizeof(GraphNode *)); + if (*nodes == NULL) { + return false; + } + + memcpy(*nodes, country->nodes, country->count * sizeof(GraphNode *)); + + *length = country->count; + + return true; +} diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h new file mode 100644 index 0000000..ffc0cd2 --- /dev/null +++ b/homework_10/task_1/graph.h @@ -0,0 +1,15 @@ +#pragma once + +typedef struct GraphNode GraphNode; + +bool createNode(GraphNode **node); + +bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance); + +bool getAllNeighbors(GraphNode *node, GraphNode **neighbors, int *length); + +typedef struct Country Country; + +bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount); + +bool getAllCities(Country *country, GraphNode **nodes, int *length); diff --git a/homework_10/task_1/main.c b/homework_10/task_1/main.c new file mode 100644 index 0000000..3da3074 --- /dev/null +++ b/homework_10/task_1/main.c @@ -0,0 +1,5 @@ +#include "graph.h" + +int main() { + +} diff --git a/homework_10/task_1/test.c b/homework_10/task_1/test.c new file mode 100644 index 0000000..059e20b --- /dev/null +++ b/homework_10/task_1/test.c @@ -0,0 +1,9 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include "graph.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} From c0844f0f9c883fc1dba25d7c31e92fbaee0f93f0 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:37:52 +0300 Subject: [PATCH 02/33] Fixed function arguments (hw10 task 1) --- homework_10/task_1/graph.c | 2 +- homework_10/task_1/graph.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index bb377d7..2f274e5 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -227,7 +227,7 @@ bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { return addNeighbor(nodeA, nodeB, distance) && addNeighbor(nodeB, nodeA, distance); } -bool getAllNeighbors(GraphNode *node, GraphNode **neighbors, int *length) { +bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length) { *neighbors = calloc(node->neighbors->count, sizeof(GraphNode *)); if (*neighbors == NULL) { return false; diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index ffc0cd2..1c87e0d 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -6,7 +6,7 @@ bool createNode(GraphNode **node); bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance); -bool getAllNeighbors(GraphNode *node, GraphNode **neighbors, int *length); +bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length); typedef struct Country Country; From f4afe025a7df0ed71feda9fa3e8876c834ffdf15 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:44:29 +0300 Subject: [PATCH 03/33] Moved queue to hashtable (hw10 task 1) --- homework_10/task_1/graph.c | 118 ++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 2f274e5..0c9840f 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -190,65 +190,6 @@ void disposeHashtable(NodeHashtable *hashtable) { #pragma endregion -typedef struct GraphNode { - NodeHashtable *neighbors; -} GraphNode; - -bool createNode(GraphNode **node) { - GraphNode *newNode = malloc(sizeof(GraphNode)); - if (newNode == NULL) { - return false; - } - - if (!createHashtable(&newNode->neighbors, 64)) { - free(newNode); - return false; - } - - *node = newNode; - - return true; -} - -static bool addNeighbor(GraphNode *node, GraphNode *neighbor, int distance) { - bool wasReplaced = false; - if (!addDistanceToHashtable(node->neighbors, neighbor, distance, &wasReplaced)) { - return false; - } - - if (wasReplaced) { - // TODO: do something - } - - return true; -} - -bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { - return addNeighbor(nodeA, nodeB, distance) && addNeighbor(nodeB, nodeA, distance); -} - -bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length) { - *neighbors = calloc(node->neighbors->count, sizeof(GraphNode *)); - if (*neighbors == NULL) { - return false; - } - - int count = 0; - HashtableIterator iterator = getIterator(node->neighbors); - while (moveNext(&iterator)) { - neighbors[count] = getCurrent(iterator).node; - ++count; - } - - *length = count; - return true; -} - -typedef struct Country { - GraphNode **nodes; - int count; -} Country; - #pragma region Queue typedef struct QNode { @@ -341,6 +282,65 @@ void disposeQueue(Queue *queue) { #pragma endregion +typedef struct GraphNode { + NodeHashtable *neighbors; +} GraphNode; + +bool createNode(GraphNode **node) { + GraphNode *newNode = malloc(sizeof(GraphNode)); + if (newNode == NULL) { + return false; + } + + if (!createHashtable(&newNode->neighbors, 64)) { + free(newNode); + return false; + } + + *node = newNode; + + return true; +} + +static bool addNeighbor(GraphNode *node, GraphNode *neighbor, int distance) { + bool wasReplaced = false; + if (!addDistanceToHashtable(node->neighbors, neighbor, distance, &wasReplaced)) { + return false; + } + + if (wasReplaced) { + // TODO: do something + } + + return true; +} + +bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { + return addNeighbor(nodeA, nodeB, distance) && addNeighbor(nodeB, nodeA, distance); +} + +bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length) { + *neighbors = calloc(node->neighbors->count, sizeof(GraphNode *)); + if (*neighbors == NULL) { + return false; + } + + int count = 0; + HashtableIterator iterator = getIterator(node->neighbors); + while (moveNext(&iterator)) { + neighbors[count] = getCurrent(iterator).node; + ++count; + } + + *length = count; + return true; +} + +typedef struct Country { + GraphNode **nodes; + int count; +} Country; + bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount) { NodeHashtable *capturedCities = NULL; if (!createHashtable(&capturedCities, 64)) { From 7f7c0214bb2bbcaf635fa625f2445058114bba73 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:47:26 +0300 Subject: [PATCH 04/33] Renamed NodeHashtableData -> NodeData (hw10 task 1) --- homework_10/task_1/graph.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 0c9840f..c852fd6 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -16,15 +16,15 @@ static bool tryExtendArrayByOne(void **elements, int count, int *capacity) { return true; } -#pragma region NodeHashtable - typedef struct { GraphNode *node; int distance; -} NodeHashtableData; +} NodeData; + +#pragma region NodeHashtable typedef struct { - NodeHashtableData *data; + NodeData *data; int count; int capacity; } Bucket; @@ -68,7 +68,7 @@ static bool createHashtable(NodeHashtable **hashtable, int capacity) { Bucket bucket = newHashtable->buckets[i]; bucket.count = 0; bucket.capacity = 8; - bucket.data = calloc(bucket.capacity, sizeof(NodeHashtableData)); + bucket.data = calloc(bucket.capacity, sizeof(NodeData)); if (bucket.data == NULL) { failed = false; break; @@ -176,7 +176,7 @@ bool moveNext(HashtableIterator *iterator) { return false; } -NodeHashtableData getCurrent(HashtableIterator iterator) { +NodeData getCurrent(HashtableIterator iterator) { return iterator.hashtable->buckets[iterator.bucketIndex].data[iterator.listIndex]; } @@ -193,7 +193,7 @@ void disposeHashtable(NodeHashtable *hashtable) { #pragma region Queue typedef struct QNode { - NodeHashtableData data; + NodeData data; struct QNode *next; } QNode; @@ -209,7 +209,7 @@ bool createQueue(Queue **queue) { return true; } -bool enqueue(Queue *queue, NodeHashtableData data) { +bool enqueue(Queue *queue, NodeData data) { QNode *node = malloc(sizeof(QNode)); if (node == NULL) { return false; @@ -251,7 +251,7 @@ bool isEmpty(Queue *queue) { return true; } -bool dequeueWithMinDistance(Queue *queue, NodeHashtableData *data) { +bool dequeueWithMinDistance(Queue *queue, NodeData *data) { if (!isEmpty(queue)) { return false; } @@ -370,7 +370,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou bool failed = false; for (int i = 0; i < capitalsCount; ++i) { - NodeHashtableData data = { .node = capitals[i], .distance = 0 }; + NodeData data = { .node = capitals[i], .distance = 0 }; if (!createQueue(&queues[i])) { failed = true; @@ -419,7 +419,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou step %= capitalsCount; Queue *countryQueue = queues[step]; - NodeHashtableData closestData = { 0 }; + NodeData closestData = { 0 }; bool queueIsEmpty = false; while (true) { if (!dequeueWithMinDistance(countryQueue, &closestData)) { @@ -447,7 +447,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou HashtableIterator iterator = getIterator(closestNode->neighbors); while (moveNext(&iterator)) { - NodeHashtableData neighborData = getCurrent(iterator); + NodeData neighborData = getCurrent(iterator); GraphNode *neighbor = neighborData.node; if (getDistanceFromHashtable(capturedCities, neighbor, NULL)) { @@ -455,7 +455,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou } int neighborDistanceToCapital = distanceToCapital + neighborData.distance; - if (!enqueue(countryQueue, (NodeHashtableData) { .node = neighbor, .distance = neighborDistanceToCapital })) { + if (!enqueue(countryQueue, (NodeData) { .node = neighbor, .distance = neighborDistanceToCapital })) { failed = true; break; } From 440e23bf05b179a73db46ae415e6a591d4a51943 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Sun, 1 Dec 2024 09:53:19 +0300 Subject: [PATCH 05/33] Made queue parameters more explicit (hw10 task 1) --- homework_10/task_1/graph.c | 50 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index c852fd6..d3b03dc 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -209,37 +209,37 @@ bool createQueue(Queue **queue) { return true; } -bool enqueue(Queue *queue, NodeData data) { - QNode *node = malloc(sizeof(QNode)); - if (node == NULL) { +bool enqueue(Queue *queue, GraphNode *node, int distance) { + QNode *qnode = malloc(sizeof(QNode)); + if (qnode == NULL) { return false; } - node->data = data; - node->next = NULL; + qnode->data = (NodeData){ .node = node, .distance = distance }; + qnode->next = NULL; if (queue->first == NULL) { - queue->first = node; + queue->first = qnode; return true; } - if (data.distance < queue->first->data.distance) { - node->next = queue->first; - queue->first = node; + if (distance < queue->first->data.distance) { + qnode->next = queue->first; + queue->first = qnode; return true; } QNode *last = queue->first; while (last->next != NULL) { - if (last->next->data.distance > data.distance) { + if (last->next->data.distance > distance) { break; } last = last->next; } - node->next = last->next; - last->next = node; + qnode->next = last->next; + last->next = qnode; return true; } @@ -251,14 +251,20 @@ bool isEmpty(Queue *queue) { return true; } -bool dequeueWithMinDistance(Queue *queue, NodeData *data) { +bool dequeueWithMinDistance(Queue *queue, GraphNode **node, int *distance) { if (!isEmpty(queue)) { return false; } QNode *first = queue->first; - *data = first->data; + if (node != NULL) { + *node = first->data.node; + } + + if (distance != NULL) { + *distance = first->data.distance; + } queue->first = first->next; @@ -370,8 +376,6 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou bool failed = false; for (int i = 0; i < capitalsCount; ++i) { - NodeData data = { .node = capitals[i], .distance = 0 }; - if (!createQueue(&queues[i])) { failed = true; break; @@ -382,12 +386,12 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou break; } - if (!enqueue(queues[i], data)) { + if (!enqueue(queues[i], capitals[i], 0)) { failed = true; break; } - if (addDistanceToHashtable(countriesWithDistances[i], data.node, data.distance, NULL)) { + if (addDistanceToHashtable(countriesWithDistances[i], capitals[i], 0, NULL)) { failed = true; break; } @@ -419,15 +423,15 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou step %= capitalsCount; Queue *countryQueue = queues[step]; - NodeData closestData = { 0 }; + GraphNode *closestNode = NULL; bool queueIsEmpty = false; while (true) { - if (!dequeueWithMinDistance(countryQueue, &closestData)) { + if (!dequeueWithMinDistance(countryQueue, &closestNode, NULL)) { queueIsEmpty = true; break; } - if (!getDistanceFromHashtable(capturedCities, closestData.node, NULL)) { + if (!getDistanceFromHashtable(capturedCities, closestNode, NULL)) { queueIsEmpty = false; break; } @@ -437,8 +441,6 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou continue; } - GraphNode *closestNode = closestData.node; - int distanceToCapital = 0; if (!getDistanceFromHashtable(countriesWithDistances[step], closestNode, &distanceToCapital)) { failed = true; @@ -455,7 +457,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou } int neighborDistanceToCapital = distanceToCapital + neighborData.distance; - if (!enqueue(countryQueue, (NodeData) { .node = neighbor, .distance = neighborDistanceToCapital })) { + if (!enqueue(countryQueue, neighbor, neighborDistanceToCapital)) { failed = true; break; } From 636c8dbde14713743d673d60ad9b2a3bd38c6c72 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:37:49 +0300 Subject: [PATCH 06/33] Moved iterator to the top of the implementation (hw10 task 1) --- homework_10/task_1/graph.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index d3b03dc..399e75c 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -41,6 +41,24 @@ typedef struct { int listIndex; } HashtableIterator; +HashtableIterator getIterator(NodeHashtable *hashtable) { + return (HashtableIterator) { .hashtable = hashtable, .bucketIndex = 0, .listIndex = 0 }; +} + +bool moveNext(HashtableIterator *iterator) { + for (; iterator->bucketIndex < iterator->hashtable->capacity; ++iterator->bucketIndex) { + NodeList bucket = iterator->hashtable->buckets[iterator->bucketIndex]; + for (; iterator->listIndex < bucket.count; ++iterator->listIndex) { + return true; + } + } + return false; +} + +NodeData getCurrent(HashtableIterator iterator) { + return iterator.hashtable->buckets[iterator.bucketIndex].data[iterator.listIndex]; +} + static void disposeBuckets(NodeHashtable *hashtable) { for (int i = 0; i < hashtable->capacity; ++i) { free(hashtable->buckets[i].data); @@ -162,24 +180,6 @@ bool getDistanceFromHashtable(NodeHashtable *hashtable, GraphNode *node, int *di return false; } -HashtableIterator getIterator(NodeHashtable *hashtable) { - return (HashtableIterator) { .hashtable = hashtable, .bucketIndex = 0, .listIndex = 0 }; -} - -bool moveNext(HashtableIterator *iterator) { - for (; iterator->bucketIndex < iterator->hashtable->capacity; ++iterator->bucketIndex) { - Bucket bucket = iterator->hashtable->buckets[iterator->bucketIndex]; - for (; iterator->listIndex < bucket.count; ++iterator->listIndex) { - return true; - } - } - return false; -} - -NodeData getCurrent(HashtableIterator iterator) { - return iterator.hashtable->buckets[iterator.bucketIndex].data[iterator.listIndex]; -} - void disposeHashtable(NodeHashtable *hashtable) { if (hashtable == NULL) { return; From 4e6128353b5adb7f996dbacf3f7cfcb116d0a363 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:40:24 +0300 Subject: [PATCH 07/33] Use iterator when expanding hashtable (hw10 task 1) --- homework_10/task_1/graph.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 399e75c..23802e2 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -113,11 +113,10 @@ static bool expandHashtable(NodeHashtable *hashtable) { return false; } - for (int i = 0; i < hashtable->count; ++i) { - Bucket bucket = hashtable->buckets[i]; - for (int j = 0; j < bucket.count; ++j) { - addDistanceToHashtable(newHashtable, bucket.data[j].node, bucket.data[j].distance, NULL); - } + HashtableIterator iterator = getIterator(hashtable); + while (moveNext(&iterator)) { + NodeData data = getCurrent(iterator); + addDistanceToHashtable(newHashtable, data.node, data.distance, NULL); } disposeBuckets(hashtable); From dba48cf91fafdc40a86b3e0ffcf223300a2a08dc Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 2 Dec 2024 18:52:43 +0300 Subject: [PATCH 08/33] Use list instead of hashtable for storing neighbors (hw10 task 1) --- homework_10/task_1/graph.c | 90 ++++++++++++++++++++++++-------------- homework_10/task_1/graph.h | 8 +++- 2 files changed, 64 insertions(+), 34 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 23802e2..21b9edb 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -21,16 +21,44 @@ typedef struct { int distance; } NodeData; -#pragma region NodeHashtable - typedef struct { NodeData *data; int count; int capacity; -} Bucket; +} NodeList; + +bool createList(NodeList *list) { + list->count = 0; + list->capacity = 8; + list->data = calloc(list->capacity, sizeof(NodeData)); + return list->data == NULL; +} + +bool addToList(NodeList *list, GraphNode *node, int distance) { + if (!tryExtendArrayByOne((void**)&list->data, list->count, &list->capacity)) { + return false; + } + + list->data[list->count].node = node; + list->data[list->count].distance = distance; + + ++list->count; + return true; +} + +bool contains(NodeList list, GraphNode *node) { + for (int i = 0; i < list.count; ++i) { + if (list.data[i].node == node) { + return true; + } + } + return false; +} + +#pragma region NodeHashtable typedef struct { - Bucket *buckets; + NodeList *buckets; int count; int capacity; } NodeHashtable; @@ -74,7 +102,7 @@ static bool createHashtable(NodeHashtable **hashtable, int capacity) { newHashtable->count = 0; newHashtable->capacity = capacity; - newHashtable->buckets = calloc(newHashtable->capacity, sizeof(Bucket)); + newHashtable->buckets = calloc(newHashtable->capacity, sizeof(NodeList)); if (newHashtable->buckets == NULL) { free(newHashtable); @@ -83,12 +111,8 @@ static bool createHashtable(NodeHashtable **hashtable, int capacity) { bool failed = false; for (int i = 0; i < newHashtable->capacity; ++i) { - Bucket bucket = newHashtable->buckets[i]; - bucket.count = 0; - bucket.capacity = 8; - bucket.data = calloc(bucket.capacity, sizeof(NodeData)); - if (bucket.data == NULL) { - failed = false; + if (!createList(&newHashtable->buckets[i])) { + failed = true; break; } } @@ -134,7 +158,7 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista } int bucketIndex = (size_t)node % hashtable->capacity; - Bucket bucket = hashtable->buckets[bucketIndex]; + NodeList bucket = hashtable->buckets[bucketIndex]; for (int i = 0; i < bucket.count; ++i) { if (bucket.data[i].node == node) { @@ -165,7 +189,7 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista bool getDistanceFromHashtable(NodeHashtable *hashtable, GraphNode *node, int *distance) { int bucketIndex = (size_t)node % hashtable->capacity; - Bucket bucket = hashtable->buckets[bucketIndex]; + NodeList bucket = hashtable->buckets[bucketIndex]; for (int i = 0; i < bucket.count; ++i) { if (bucket.data[i].node == node) { @@ -288,7 +312,7 @@ void disposeQueue(Queue *queue) { #pragma endregion typedef struct GraphNode { - NodeHashtable *neighbors; + NodeList neighbors; } GraphNode; bool createNode(GraphNode **node) { @@ -297,7 +321,7 @@ bool createNode(GraphNode **node) { return false; } - if (!createHashtable(&newNode->neighbors, 64)) { + if (!createList(&newNode->neighbors)) { free(newNode); return false; } @@ -307,34 +331,35 @@ bool createNode(GraphNode **node) { return true; } -static bool addNeighbor(GraphNode *node, GraphNode *neighbor, int distance) { - bool wasReplaced = false; - if (!addDistanceToHashtable(node->neighbors, neighbor, distance, &wasReplaced)) { - return false; +static ConnectionResult addNeighbor(GraphNode *node, GraphNode *neighbor, int distance) { + if (contains(node->neighbors, neighbor)) { + return CONNECTION_ALREADY_EXISTS; } - if (wasReplaced) { - // TODO: do something + if (!addToList(&node->neighbors, neighbor, distance)) { + return CONNECTION_ALLOCATION_ERROR; } - return true; + return CONNECTION_OK; } -bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { - return addNeighbor(nodeA, nodeB, distance) && addNeighbor(nodeB, nodeA, distance); +ConnectionResult connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { + ConnectionResult result = addNeighbor(nodeA, nodeB, distance); + if (result != CONNECTION_OK) { + return result; + } + return addNeighbor(nodeB, nodeA, distance); } bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length) { - *neighbors = calloc(node->neighbors->count, sizeof(GraphNode *)); + int count = node->neighbors.count; + *neighbors = calloc(count, sizeof(GraphNode *)); if (*neighbors == NULL) { return false; } - int count = 0; - HashtableIterator iterator = getIterator(node->neighbors); - while (moveNext(&iterator)) { - neighbors[count] = getCurrent(iterator).node; - ++count; + for (int i = 0; i < count; ++i) { + (*neighbors)[count] = node->neighbors.data[i].node; } *length = count; @@ -446,9 +471,8 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou break; } - HashtableIterator iterator = getIterator(closestNode->neighbors); - while (moveNext(&iterator)) { - NodeData neighborData = getCurrent(iterator); + for (int i = 0; i < closestNode->neighbors.count; ++i) { + NodeData neighborData = closestNode->neighbors.data[i]; GraphNode *neighbor = neighborData.node; if (getDistanceFromHashtable(capturedCities, neighbor, NULL)) { diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index 1c87e0d..5d89795 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -1,10 +1,16 @@ #pragma once +typedef enum { + CONNECTION_OK, + CONNECTION_ALLOCATION_ERROR, + CONNECTION_ALREADY_EXISTS +} ConnectionResult; + typedef struct GraphNode GraphNode; bool createNode(GraphNode **node); -bool connect(GraphNode *nodeA, GraphNode *nodeB, int distance); +ConnectionResult connect(GraphNode *nodeA, GraphNode *nodeB, int distance); bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length); From 7de2ad6923a10d07d9b6e279f0de5e0af70413df Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:49:49 +0300 Subject: [PATCH 09/33] Fixed couple logical issues (hw10 task 1) --- homework_10/task_1/graph.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 21b9edb..0a3fbc2 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -31,7 +31,7 @@ bool createList(NodeList *list) { list->count = 0; list->capacity = 8; list->data = calloc(list->capacity, sizeof(NodeData)); - return list->data == NULL; + return list->data != NULL; } bool addToList(NodeList *list, GraphNode *node, int distance) { @@ -268,14 +268,11 @@ bool enqueue(Queue *queue, GraphNode *node, int distance) { } bool isEmpty(Queue *queue) { - if (queue->first == NULL) { - return false; - } - return true; + return queue->first == NULL; } bool dequeueWithMinDistance(Queue *queue, GraphNode **node, int *distance) { - if (!isEmpty(queue)) { + if (isEmpty(queue)) { return false; } From f44bb55c9c79f2a8ddc0573c87a80fb883eae653 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:51:33 +0300 Subject: [PATCH 10/33] Updated hash functions (hw10 task 1) --- homework_10/task_1/graph.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 0a3fbc2..583ff65 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -152,12 +152,17 @@ static bool expandHashtable(NodeHashtable *hashtable) { return true; } +static unsigned int getHashCode(GraphNode *node) { + // nodes are more likely to be allocated in bulk, so divide address by node size + return (size_t)node / sizeof(GraphNode); +} + bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance, bool *replacedValue) { if ((float)hashtable->count / hashtable->capacity > 4.0) { expandHashtable(hashtable); } - int bucketIndex = (size_t)node % hashtable->capacity; + int bucketIndex = getHashCode(node) % hashtable->capacity; NodeList bucket = hashtable->buckets[bucketIndex]; for (int i = 0; i < bucket.count; ++i) { @@ -188,7 +193,7 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista } bool getDistanceFromHashtable(NodeHashtable *hashtable, GraphNode *node, int *distance) { - int bucketIndex = (size_t)node % hashtable->capacity; + int bucketIndex = getHashCode(node) % hashtable->capacity; NodeList bucket = hashtable->buckets[bucketIndex]; for (int i = 0; i < bucket.count; ++i) { From f5120c675c0a01ae976f2d97b4ea0feb5a6248f0 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:55:43 +0300 Subject: [PATCH 11/33] Added disposeNode and disposeCountry (hw10 task 1) --- homework_10/task_1/graph.c | 18 ++++++++++++++++++ homework_10/task_1/graph.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 583ff65..566cc1b 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -368,6 +368,15 @@ bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length) { return true; } +void disposeNode(GraphNode *node) { + if (node == NULL) { + return; + } + + free(node->neighbors.data); + free(node); +} + typedef struct Country { GraphNode **nodes; int count; @@ -587,3 +596,12 @@ bool getAllCities(Country *country, GraphNode **nodes, int *length) { return true; } + +void disposeCountry(Country *country) { + if (country == NULL) { + return; + } + + free(country->nodes); + free(country); +} diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index 5d89795..336357d 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -14,8 +14,12 @@ ConnectionResult connect(GraphNode *nodeA, GraphNode *nodeB, int distance); bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length); +void disposeNode(GraphNode *node); + typedef struct Country Country; bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount); bool getAllCities(Country *country, GraphNode **nodes, int *length); + +void disposeCountry(Country *country); From 52d4bd1bbb422d5d1b575748ad20b7018c7e434c Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:57:23 +0300 Subject: [PATCH 12/33] Fixed tryExtendArrayByOne() (hw10 task 1) --- homework_10/task_1/graph.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 566cc1b..53dac2a 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -3,10 +3,10 @@ #include #include -static bool tryExtendArrayByOne(void **elements, int count, int *capacity) { +static bool tryExtendArrayByOne(void **elements, int count, int *capacity, int elementSize) { if (count + 1 >= *capacity) { *capacity *= 4; - void *newData = realloc(*elements, *capacity); + void *newData = realloc(*elements, *capacity * elementSize); if (newData == NULL) { return false; } @@ -35,7 +35,7 @@ bool createList(NodeList *list) { } bool addToList(NodeList *list, GraphNode *node, int distance) { - if (!tryExtendArrayByOne((void**)&list->data, list->count, &list->capacity)) { + if (!tryExtendArrayByOne((void**)&list->data, list->count, &list->capacity, sizeof(NodeData))) { return false; } @@ -176,7 +176,7 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista } } - if (!tryExtendArrayByOne((void**)&bucket.data, bucket.count, &bucket.capacity)) { + if (!tryExtendArrayByOne((void**)&bucket.data, bucket.count, &bucket.capacity, sizeof(NodeList))) { return false; } From 7d78d6b231b2e089639e5b8ac7584dc6dfc0a76d Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:58:00 +0300 Subject: [PATCH 13/33] Fixed hashtable iterator (hw10 task 1) --- homework_10/task_1/graph.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 53dac2a..05a0912 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -70,16 +70,25 @@ typedef struct { } HashtableIterator; HashtableIterator getIterator(NodeHashtable *hashtable) { - return (HashtableIterator) { .hashtable = hashtable, .bucketIndex = 0, .listIndex = 0 }; + return (HashtableIterator) { .hashtable = hashtable, .bucketIndex = -1, .listIndex = -1 }; } bool moveNext(HashtableIterator *iterator) { - for (; iterator->bucketIndex < iterator->hashtable->capacity; ++iterator->bucketIndex) { + while (iterator->bucketIndex < iterator->hashtable->capacity) { + ++iterator->bucketIndex; + if (iterator->bucketIndex >= iterator->hashtable->capacity) { + return false; + } NodeList bucket = iterator->hashtable->buckets[iterator->bucketIndex]; - for (; iterator->listIndex < bucket.count; ++iterator->listIndex) { - return true; + while (iterator->listIndex < bucket.count) { + ++iterator->listIndex; + if (iterator->listIndex < bucket.count) { + return true; + } } + iterator->listIndex = -1; } + return false; } From d919bc15ab583dc5b4b82bbd87b2266598762945 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:02:20 +0300 Subject: [PATCH 14/33] Removed replacedValue parameter from addDistanceToHashtable() (hw10 task 1) --- homework_10/task_1/graph.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 05a0912..b9f2d67 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -136,7 +136,7 @@ static bool createHashtable(NodeHashtable **hashtable, int capacity) { return true; } -bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance, bool *replacedValue); +bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance); static bool expandHashtable(NodeHashtable *hashtable) { int newCapacity = hashtable->capacity * 4; @@ -149,7 +149,7 @@ static bool expandHashtable(NodeHashtable *hashtable) { HashtableIterator iterator = getIterator(hashtable); while (moveNext(&iterator)) { NodeData data = getCurrent(iterator); - addDistanceToHashtable(newHashtable, data.node, data.distance, NULL); + addDistanceToHashtable(newHashtable, data.node, data.distance); } disposeBuckets(hashtable); @@ -166,7 +166,7 @@ static unsigned int getHashCode(GraphNode *node) { return (size_t)node / sizeof(GraphNode); } -bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance, bool *replacedValue) { +bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance) { if ((float)hashtable->count / hashtable->capacity > 4.0) { expandHashtable(hashtable); } @@ -176,10 +176,6 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista for (int i = 0; i < bucket.count; ++i) { if (bucket.data[i].node == node) { - if (replacedValue != NULL) { - *replacedValue = true; - } - bucket.data[i].distance = distance; return true; } @@ -194,10 +190,6 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista ++bucket.count; - if (replacedValue != NULL) { - *replacedValue = false; - } - return true; } @@ -435,7 +427,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou break; } - if (addDistanceToHashtable(countriesWithDistances[i], capitals[i], 0, NULL)) { + if (!addDistanceToHashtable(countriesWithDistances[i], capitals[i], 0)) { failed = true; break; } @@ -511,7 +503,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou newDistance = newDistance < storedDistance ? newDistance : storedDistance; } - if (!addDistanceToHashtable(countriesWithDistances[step], neighbor, newDistance, NULL)) { + if (!addDistanceToHashtable(countriesWithDistances[step], neighbor, newDistance)) { failed = true; break; } From 896ec306a7c43d7f8aa7cfcd25aaa7a36a0a5943 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:07:02 +0300 Subject: [PATCH 15/33] Create countries before capturing instead of after (hw10 task 1) --- homework_10/task_1/graph.c | 76 +++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index b9f2d67..2f4fbd3 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -381,22 +381,31 @@ void disposeNode(GraphNode *node) { typedef struct Country { GraphNode **nodes; int count; + int capacity; } Country; bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount) { + *countries = calloc(capitalsCount, sizeof(Country *)); + if (*countries == NULL) { + return false; + } + NodeHashtable *capturedCities = NULL; if (!createHashtable(&capturedCities, 64)) { + free(*countries); return false; } Queue **queues = calloc(capitalsCount, sizeof(Queue *)); if (queues == NULL) { + free(*countries); disposeHashtable(capturedCities); return false; } NodeHashtable **countriesWithDistances = calloc(capitalsCount, sizeof(NodeHashtable *)); if (countries == NULL) { + free(*countries); disposeHashtable(capturedCities); free(queues); return false; @@ -404,6 +413,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou int *nodesPerCountry = calloc(capitalsCount, sizeof(int)); if (nodesPerCountry == NULL) { + free(*countries); disposeHashtable(capturedCities); free(queues); free(countriesWithDistances); @@ -431,13 +441,31 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou failed = true; break; } + + Country *country = calloc(1, sizeof(Country)); + if (country == NULL) { + failed = true; + break; + } + + country->count = 0; + country->capacity = 8; + country->nodes = calloc(country->capacity, sizeof(GraphNode *)); + if (country->nodes == NULL) { + failed = true; + break; + } + + (*countries)[i] = country; } if (failed) { for (int i = 0; i < capitalsCount; ++i) { + disposeCountry((*countries)[i]); disposeQueue(queues[i]); disposeHashtable(countriesWithDistances[i]); } + free(*countries); disposeHashtable(capturedCities); return false; } @@ -514,6 +542,13 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou } ++nodesPerCountry[step]; + Country *country = (*countries)[step]; + if (!tryExtendArrayByOne((void **)&country->nodes, country->count, &country->capacity, sizeof(GraphNode *))) { + failed = true; + break; + } + country->nodes[country->count] = closestNode; + ++country->count; } for (int i = 0; i < capitalsCount; ++i) { @@ -524,45 +559,15 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou if (failed) { for (int i = 0; i < capitalsCount; ++i) { + disposeCountry((*countries)[i]); disposeHashtable(countriesWithDistances[i]); } - free(countriesWithDistances); - free(nodesPerCountry); - return false; - } - - *countries = calloc(capitalsCount, sizeof(Country *)); - if (*countries == NULL) { - for (int i = 0; i < capitalsCount; ++i) { - disposeHashtable(countriesWithDistances[i]); - } + free(*countries); free(countriesWithDistances); free(nodesPerCountry); return false; } - for (int i = 0; i < capitalsCount; ++i) { - Country *country = calloc(1, sizeof(Country)); - if (country == NULL) { - failed = true; - break; - } - - country->count = nodesPerCountry[i]; - country->nodes = calloc(country->count, sizeof(GraphNode *)); - if (country->nodes == NULL) { - failed = true; - break; - } - HashtableIterator iterator = getIterator(countriesWithDistances[i]); - int index = 0; - while (moveNext(&iterator)) { - country->nodes[index] = getCurrent(iterator).node; - ++index; - } - (*countries)[i] = country; - } - for (int i = 0; i < capitalsCount; ++i) { disposeHashtable(countriesWithDistances[i]); free(countriesWithDistances); @@ -571,12 +576,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou if (failed) { for (int i = 0; i < capitalsCount; ++i) { - Country *country = (*countries)[i]; - if (country == NULL) { - continue; - } - free(country->nodes); - free(country); + disposeCountry((*countries)[i]); } free(*countries); return false; From 2a4178e162f12f111b878bb7f0957d036f1130c2 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:09:17 +0300 Subject: [PATCH 16/33] Moved GraphNode declaration to the top (hw10 task 1) --- homework_10/task_1/graph.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 2f4fbd3..f36fbef 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -27,6 +27,10 @@ typedef struct { int capacity; } NodeList; +typedef struct GraphNode { + NodeList neighbors; +} GraphNode; + bool createList(NodeList *list) { list->count = 0; list->capacity = 8; @@ -314,10 +318,6 @@ void disposeQueue(Queue *queue) { #pragma endregion -typedef struct GraphNode { - NodeList neighbors; -} GraphNode; - bool createNode(GraphNode **node) { GraphNode *newNode = malloc(sizeof(GraphNode)); if (newNode == NULL) { From 48c1bfe7bd6047ea325aa2e9e6d253aabcc15f0c Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:09:43 +0300 Subject: [PATCH 17/33] Update count in buckets (hw10 task 1) --- homework_10/task_1/graph.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index f36fbef..e8b1466 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -193,6 +193,8 @@ bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int dista bucket.data[bucket.count].distance = distance; ++bucket.count; + ++hashtable->count; + hashtable->buckets[bucketIndex] = bucket; return true; } From 8951ab9e3e129e1124fb407ab00b457eedce9f22 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:12:24 +0300 Subject: [PATCH 18/33] Fixed memory disposing (hw10 task 1) --- homework_10/task_1/graph.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index e8b1466..14ae9bc 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -468,6 +468,8 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou disposeHashtable(countriesWithDistances[i]); } free(*countries); + free(queues); + free(countriesWithDistances); disposeHashtable(capturedCities); return false; } @@ -566,14 +568,13 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou } free(*countries); free(countriesWithDistances); - free(nodesPerCountry); return false; } for (int i = 0; i < capitalsCount; ++i) { disposeHashtable(countriesWithDistances[i]); - free(countriesWithDistances); } + free(countriesWithDistances); free(nodesPerCountry); if (failed) { From 0a8590234c012c02b2cf75e8f2c9e27e62e4cae2 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:14:22 +0300 Subject: [PATCH 19/33] Removed newDistance variable (hw10 task 1) --- homework_10/task_1/graph.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 14ae9bc..54bf5f0 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -529,13 +529,12 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou break; } - int newDistance = neighborDistanceToCapital; int storedDistance = 0; if (getDistanceFromHashtable(countriesWithDistances[step], neighbor, &storedDistance)) { - newDistance = newDistance < storedDistance ? newDistance : storedDistance; + neighborDistanceToCapital = neighborDistanceToCapital < storedDistance ? neighborDistanceToCapital : storedDistance; } - if (!addDistanceToHashtable(countriesWithDistances[step], neighbor, newDistance)) { + if (!addDistanceToHashtable(countriesWithDistances[step], neighbor, neighborDistanceToCapital)) { failed = true; break; } From 97cf9d4d15664903bf51f0ce62ac31dd7252bedc Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:15:26 +0300 Subject: [PATCH 20/33] Enqueue neighbor after distance update (hw10 task 1) --- homework_10/task_1/graph.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 54bf5f0..9ffa04e 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -524,11 +524,6 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou } int neighborDistanceToCapital = distanceToCapital + neighborData.distance; - if (!enqueue(countryQueue, neighbor, neighborDistanceToCapital)) { - failed = true; - break; - } - int storedDistance = 0; if (getDistanceFromHashtable(countriesWithDistances[step], neighbor, &storedDistance)) { neighborDistanceToCapital = neighborDistanceToCapital < storedDistance ? neighborDistanceToCapital : storedDistance; @@ -538,6 +533,11 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou failed = true; break; } + + if (!enqueue(countryQueue, neighbor, neighborDistanceToCapital)) { + failed = true; + break; + } } if (failed) { From 530ac222f3dc739a464afca2b5c730b234eaa15c Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:16:00 +0300 Subject: [PATCH 21/33] Add node to captured cities after checking neighbors (hw10 task 1) --- homework_10/task_1/graph.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 9ffa04e..8f5b0c7 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -545,6 +545,10 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou } ++nodesPerCountry[step]; + if (!addDistanceToHashtable(capturedCities, closestNode, distanceToCapital)) { + failed = true; + break; + } Country *country = (*countries)[step]; if (!tryExtendArrayByOne((void **)&country->nodes, country->count, &country->capacity, sizeof(GraphNode *))) { failed = true; From 318b03d2349a269a5d3c29c74619b7dc92d56ec6 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:16:33 +0300 Subject: [PATCH 22/33] Fixed getAllCities() parameters (hw10 task 1) --- homework_10/task_1/graph.c | 2 +- homework_10/task_1/graph.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 8f5b0c7..f7880cc 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -591,7 +591,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou return true; } -bool getAllCities(Country *country, GraphNode **nodes, int *length) { +bool getAllCities(Country *country, GraphNode ***nodes, int *length) { *nodes = calloc(country->count, sizeof(GraphNode *)); if (*nodes == NULL) { return false; diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index 336357d..30e8395 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -20,6 +20,6 @@ typedef struct Country Country; bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount); -bool getAllCities(Country *country, GraphNode **nodes, int *length); +bool getAllCities(Country *country, GraphNode ***nodes, int *length); void disposeCountry(Country *country); From 7b6d03903d7ebcc632fa955484660ea59e849654 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:22:01 +0300 Subject: [PATCH 23/33] Removed unnecessary disposing (hw10 task 1) --- homework_10/task_1/graph.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index f7880cc..4f62d96 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -511,6 +511,7 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou int distanceToCapital = 0; if (!getDistanceFromHashtable(countriesWithDistances[step], closestNode, &distanceToCapital)) { + // unreachable failed = true; break; } @@ -560,23 +561,10 @@ bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCou for (int i = 0; i < capitalsCount; ++i) { disposeQueue(queues[i]); + disposeHashtable(countriesWithDistances[i]); } free(queues); disposeHashtable(capturedCities); - - if (failed) { - for (int i = 0; i < capitalsCount; ++i) { - disposeCountry((*countries)[i]); - disposeHashtable(countriesWithDistances[i]); - } - free(*countries); - free(countriesWithDistances); - return false; - } - - for (int i = 0; i < capitalsCount; ++i) { - disposeHashtable(countriesWithDistances[i]); - } free(countriesWithDistances); free(nodesPerCountry); From cdd3bcb3750eac6ba36eb10b8dedef9b594eee0a Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:24:46 +0300 Subject: [PATCH 24/33] Added main functionality (hw10 task 1) --- homework_10/task_1/.gitignore | 1 + homework_10/task_1/main.c | 188 ++++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 homework_10/task_1/.gitignore diff --git a/homework_10/task_1/.gitignore b/homework_10/task_1/.gitignore new file mode 100644 index 0000000..3ad17f5 --- /dev/null +++ b/homework_10/task_1/.gitignore @@ -0,0 +1 @@ +graph.txt diff --git a/homework_10/task_1/main.c b/homework_10/task_1/main.c index 3da3074..3cd6fb2 100644 --- a/homework_10/task_1/main.c +++ b/homework_10/task_1/main.c @@ -1,5 +1,193 @@ #include "graph.h" +#include +#include + int main() { + FILE *file = fopen("graph.txt", "r"); + if (file == NULL) { + printf("couldn't open file\n"); + return 1; + } + + int nodeCount = 0; + if (fscanf(file, "%d", &nodeCount) != 1) { + printf("couldn't read node count\n"); + return 1; + } + + int connectionsCount = 0; + if (fscanf(file, "%d", &connectionsCount) != 1) { + printf("couldn't read connections count\n"); + return 1; + } + + GraphNode **nodes = calloc(nodeCount, sizeof(GraphNode *)); + if (nodes == NULL) { + printf("allocation error\n"); + return 1; + } + + bool failed = false; + for (int i = 0; i < nodeCount; ++i) { + if (!createNode(&nodes[i])) { + printf("allocation error\n"); + failed = true; + break; + } + } + + if (failed) { + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + + return 1; + } + + for (int i = 0; i < connectionsCount; ++i) { + int nodeAIndex = -1; + int nodeBIndex = -1; + int distance = -1; + if (fscanf(file, "%d %d %d", &nodeAIndex, &nodeBIndex, &distance) != 3) { + printf("couldn't read connection\n"); + failed = true; + break; + } + + if (nodeAIndex < 0 || nodeAIndex >= nodeCount) { + printf("warning: node #%d does not exist, connection skipped\n", nodeAIndex); + continue; + } + + if (nodeBIndex < 0 || nodeBIndex >= nodeCount) { + printf("warning: node #%d does not exist, connection skipped\n", nodeBIndex); + continue; + } + + switch (connect(nodes[nodeAIndex], nodes[nodeBIndex], distance)) + { + case CONNECTION_ALLOCATION_ERROR: + printf("allocation error\n"); + failed = true; + break; + + case CONNECTION_ALREADY_EXISTS: + printf("warning: connection between node #%d and #%d already exists, skipped\n", nodeAIndex, nodeBIndex); + break; + + case CONNECTION_OK: + break; + } + + if (failed) { + break; + } + } + + if (failed) { + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + + return 1; + } + + int capitalsCount = 0; + if (fscanf(file, "%d", &capitalsCount) != 1) { + printf("couldn't read capitals count\n"); + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + + return 1; + } + + GraphNode **capitals = calloc(capitalsCount, sizeof(GraphNode *)); + if (capitals == NULL) { + printf("allocation error\n"); + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + + return 1; + } + + for (int i = 0; i < capitalsCount; ++i) { + int capitalIndex = -1; + if (fscanf(file, "%d", &capitalIndex) != 1) { + printf("couldn't read capital index\n"); + failed = true; + break; + } + capitals[i] = nodes[capitalIndex]; + } + + if (failed) { + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + free(capitals); + + return 1; + } + + Country **countries = NULL; + if (!createCountries(capitals, &countries, capitalsCount)) { + printf("allocation error\n"); + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + free(capitals); + + return 1; + } + + printf("countries:\n"); + printf("\n"); + for (int i = 0; i < capitalsCount; ++i) { + printf("country #%d:\n", i + 1); + Country *country = countries[i]; + GraphNode **cities = NULL; + int cityCount = 0; + if (!getAllCities(country, &cities, &cityCount)) { + printf("allocation error\n"); + failed = true; + break; + } + + for (int j = 0; j < cityCount; ++j) { + GraphNode *node = cities[j]; + for (int k = 0; k < nodeCount; ++k) { + if (nodes[k] == node) { + printf(" city #%d\n", k); + break; + } + } + } + + free(cities); + } + + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + + free(nodes); + free(capitals); + + for (int i = 0; i < capitalsCount; ++i) { + disposeCountry(countries[i]); + } + free(countries); + if (failed) { + return 1; + } } From 10528b068615ee017033d3e227a866794890799c Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:25:27 +0300 Subject: [PATCH 25/33] Moved reading graph from file and country creation to separate file (hw10 task 1) --- homework_10/task_1/CMakeLists.txt | 2 +- homework_10/task_1/fileGraphReader.c | 165 +++++++++++++++++++++++++++ homework_10/task_1/fileGraphReader.h | 13 +++ homework_10/task_1/main.c | 152 +++--------------------- 4 files changed, 193 insertions(+), 139 deletions(-) create mode 100644 homework_10/task_1/fileGraphReader.c create mode 100644 homework_10/task_1/fileGraphReader.h diff --git a/homework_10/task_1/CMakeLists.txt b/homework_10/task_1/CMakeLists.txt index 8a35aa9..ff24ae7 100644 --- a/homework_10/task_1/CMakeLists.txt +++ b/homework_10/task_1/CMakeLists.txt @@ -1,6 +1,6 @@ project("${homeworkName}_task_1") -add_library(graph graph.c) +add_library(graph graph.c fileGraphReader.c) add_executable(${PROJECT_NAME} main.c) target_link_libraries(${PROJECT_NAME} graph) diff --git a/homework_10/task_1/fileGraphReader.c b/homework_10/task_1/fileGraphReader.c new file mode 100644 index 0000000..9397522 --- /dev/null +++ b/homework_10/task_1/fileGraphReader.c @@ -0,0 +1,165 @@ +#include "fileGraphReader.h" + +#include +#include + +#include "graph.h" + +ReadResult readFileFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput) { + int storedNodeCount = 0; + if (fscanf(file, "%d", &storedNodeCount) != 1) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "couldn't read node count\n"); + } + return READ_FILE_ERROR; + } + + int connectionsCount = 0; + if (fscanf(file, "%d", &connectionsCount) != 1) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "couldn't read connections count\n"); + } + return READ_FILE_ERROR; + } + + GraphNode **storedNodes = calloc(storedNodeCount, sizeof(GraphNode *)); + if (storedNodes == NULL) { + return READ_ALLOCATION_ERROR; + } + + ReadResult result = READ_OK; + for (int i = 0; i < storedNodeCount; ++i) { + if (!createNode(&storedNodes[i])) { + result = READ_ALLOCATION_ERROR; + break; + } + } + + if (result != READ_OK) { + for (int i = 0; i < storedNodeCount; ++i) { + disposeNode(storedNodes[i]); + } + free(storedNodes); + + return result; + } + + for (int i = 0; i < connectionsCount; ++i) { + int nodeAIndex = -1; + int nodeBIndex = -1; + int distance = -1; + if (fscanf(file, "%d %d %d", &nodeAIndex, &nodeBIndex, &distance) != 3) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "couldn't read connection\n"); + } + result = READ_FILE_ERROR; + break; + } + + if (nodeAIndex < 0 || nodeAIndex >= storedNodeCount) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "warning: node #%d does not exist, connection skipped\n", nodeAIndex); + } + continue; + } + + if (nodeBIndex < 0 || nodeBIndex >= storedNodeCount) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "warning: node #%d does not exist, connection skipped\n", nodeBIndex); + } + continue; + } + + switch (connect(storedNodes[nodeAIndex], storedNodes[nodeBIndex], distance)) + { + case CONNECTION_ALLOCATION_ERROR: + result = READ_ALLOCATION_ERROR; + break; + + case CONNECTION_ALREADY_EXISTS: + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "warning: connection between node #%d and #%d already exists, skipped\n", nodeAIndex, nodeBIndex); + } + break; + + case CONNECTION_OK: + break; + } + + if (result != READ_OK) { + break; + } + } + + if (result != READ_OK) { + for (int i = 0; i < storedNodeCount; ++i) { + disposeNode(storedNodes[i]); + } + free(storedNodes); + + return result; + } + + int capitalsCount = 0; + if (fscanf(file, "%d", &capitalsCount) != 1) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "couldn't read capitals count\n"); + } + + for (int i = 0; i < storedNodeCount; ++i) { + disposeNode(storedNodes[i]); + } + free(storedNodes); + + return READ_FILE_ERROR; + } + + GraphNode **capitals = calloc(capitalsCount, sizeof(GraphNode *)); + if (capitals == NULL) { + for (int i = 0; i < storedNodeCount; ++i) { + disposeNode(storedNodes[i]); + } + free((storedNodes)); + + return READ_ALLOCATION_ERROR; + } + + for (int i = 0; i < capitalsCount; ++i) { + int capitalIndex = -1; + if (fscanf(file, "%d", &capitalIndex) != 1) { + if (warningAndErrorOutput != NULL) { + fprintf(warningAndErrorOutput, "couldn't read capital index\n"); + } + result = READ_FILE_ERROR; + break; + } + capitals[i] = storedNodes[capitalIndex]; + } + + if (result != READ_OK) { + for (int i = 0; i < storedNodeCount; ++i) { + disposeNode(storedNodes[i]); + } + free(storedNodes); + free(capitals); + + return result; + } + + if (!createCountries(capitals, countries, capitalsCount)) { + for (int i = 0; i < storedNodeCount; ++i) { + disposeNode(storedNodes[i]); + } + free(storedNodes); + free(capitals); + + return READ_ALLOCATION_ERROR; + } + + *nodes = storedNodes; + *nodeCount = storedNodeCount; + *countryCount = capitalsCount; + + free(capitals); + return READ_OK; +} diff --git a/homework_10/task_1/fileGraphReader.h b/homework_10/task_1/fileGraphReader.h new file mode 100644 index 0000000..b24c85f --- /dev/null +++ b/homework_10/task_1/fileGraphReader.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "graph.h" + +typedef enum { + READ_OK, + READ_ALLOCATION_ERROR, + READ_FILE_ERROR, +} ReadResult; + +ReadResult readFileFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput); diff --git a/homework_10/task_1/main.c b/homework_10/task_1/main.c index 3cd6fb2..53519ac 100644 --- a/homework_10/task_1/main.c +++ b/homework_10/task_1/main.c @@ -1,8 +1,9 @@ -#include "graph.h" - #include #include +#include "graph.h" +#include "fileGraphReader.h" + int main() { FILE *file = fopen("graph.txt", "r"); if (file == NULL) { @@ -10,148 +11,25 @@ int main() { return 1; } + GraphNode **nodes = NULL; int nodeCount = 0; - if (fscanf(file, "%d", &nodeCount) != 1) { - printf("couldn't read node count\n"); - return 1; - } - - int connectionsCount = 0; - if (fscanf(file, "%d", &connectionsCount) != 1) { - printf("couldn't read connections count\n"); - return 1; - } - - GraphNode **nodes = calloc(nodeCount, sizeof(GraphNode *)); - if (nodes == NULL) { - printf("allocation error\n"); - return 1; - } - - bool failed = false; - for (int i = 0; i < nodeCount; ++i) { - if (!createNode(&nodes[i])) { - printf("allocation error\n"); - failed = true; - break; - } - } - - if (failed) { - for (int i = 0; i < nodeCount; ++i) { - disposeNode(nodes[i]); - } - free(nodes); - - return 1; - } - - for (int i = 0; i < connectionsCount; ++i) { - int nodeAIndex = -1; - int nodeBIndex = -1; - int distance = -1; - if (fscanf(file, "%d %d %d", &nodeAIndex, &nodeBIndex, &distance) != 3) { - printf("couldn't read connection\n"); - failed = true; - break; - } - - if (nodeAIndex < 0 || nodeAIndex >= nodeCount) { - printf("warning: node #%d does not exist, connection skipped\n", nodeAIndex); - continue; - } - - if (nodeBIndex < 0 || nodeBIndex >= nodeCount) { - printf("warning: node #%d does not exist, connection skipped\n", nodeBIndex); - continue; - } - - switch (connect(nodes[nodeAIndex], nodes[nodeBIndex], distance)) - { - case CONNECTION_ALLOCATION_ERROR: - printf("allocation error\n"); - failed = true; - break; - - case CONNECTION_ALREADY_EXISTS: - printf("warning: connection between node #%d and #%d already exists, skipped\n", nodeAIndex, nodeBIndex); - break; - - case CONNECTION_OK: - break; - } - - if (failed) { - break; - } - } - - if (failed) { - for (int i = 0; i < nodeCount; ++i) { - disposeNode(nodes[i]); - } - free(nodes); - - return 1; - } - - int capitalsCount = 0; - if (fscanf(file, "%d", &capitalsCount) != 1) { - printf("couldn't read capitals count\n"); - for (int i = 0; i < nodeCount; ++i) { - disposeNode(nodes[i]); - } - free(nodes); - - return 1; - } - - GraphNode **capitals = calloc(capitalsCount, sizeof(GraphNode *)); - if (capitals == NULL) { + Country **countries = NULL; + int countryCount = 0; + switch (readFileFromFileAndCreateCountries(file, &nodes, &nodeCount, &countries, &countryCount, stdout)) { + case READ_OK: + break; + case READ_ALLOCATION_ERROR: printf("allocation error\n"); - for (int i = 0; i < nodeCount; ++i) { - disposeNode(nodes[i]); - } - free(nodes); - return 1; - } - - for (int i = 0; i < capitalsCount; ++i) { - int capitalIndex = -1; - if (fscanf(file, "%d", &capitalIndex) != 1) { - printf("couldn't read capital index\n"); - failed = true; - break; - } - capitals[i] = nodes[capitalIndex]; - } - - if (failed) { - for (int i = 0; i < nodeCount; ++i) { - disposeNode(nodes[i]); - } - free(nodes); - free(capitals); - + case READ_FILE_ERROR: return 1; } - Country **countries = NULL; - if (!createCountries(capitals, &countries, capitalsCount)) { - printf("allocation error\n"); - for (int i = 0; i < nodeCount; ++i) { - disposeNode(nodes[i]); - } - free(nodes); - free(capitals); - - return 1; - } + bool failed = false; printf("countries:\n"); printf("\n"); - for (int i = 0; i < capitalsCount; ++i) { + for (int i = 0; i < countryCount; ++i) { printf("country #%d:\n", i + 1); Country *country = countries[i]; GraphNode **cities = NULL; @@ -178,11 +56,9 @@ int main() { for (int i = 0; i < nodeCount; ++i) { disposeNode(nodes[i]); } - free(nodes); - free(capitals); - for (int i = 0; i < capitalsCount; ++i) { + for (int i = 0; i < countryCount; ++i) { disposeCountry(countries[i]); } free(countries); From 56e051596c2d1a9998b9bb626ec4bfe3af2774e6 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:28:27 +0300 Subject: [PATCH 26/33] Added tests (hw10 task 1) --- homework_10/task_1/test.c | 106 ++++++++++++++++++ .../task_1/testFiles/complexA_countries.txt | 51 +++++++++ .../task_1/testFiles/complexA_graph.txt | 97 ++++++++++++++++ .../task_1/testFiles/complexB_countries.txt | 52 +++++++++ .../task_1/testFiles/complexB_graph.txt | 90 +++++++++++++++ .../fiveCitiesFiveCountries_countries.txt | 11 ++ .../fiveCitiesFiveCountries_graph.txt | 17 +++ .../fiveCitiesTwoCountries_countries.txt | 8 ++ .../fiveCitiesTwoCountries_graph.txt | 12 ++ .../task_1/testFiles/singleCity_countries.txt | 3 + .../task_1/testFiles/singleCity_graph.txt | 4 + .../task_1/testFiles/twoCities_countries.txt | 4 + .../task_1/testFiles/twoCities_graph.txt | 5 + 13 files changed, 460 insertions(+) create mode 100644 homework_10/task_1/testFiles/complexA_countries.txt create mode 100644 homework_10/task_1/testFiles/complexA_graph.txt create mode 100644 homework_10/task_1/testFiles/complexB_countries.txt create mode 100644 homework_10/task_1/testFiles/complexB_graph.txt create mode 100644 homework_10/task_1/testFiles/fiveCitiesFiveCountries_countries.txt create mode 100644 homework_10/task_1/testFiles/fiveCitiesFiveCountries_graph.txt create mode 100644 homework_10/task_1/testFiles/fiveCitiesTwoCountries_countries.txt create mode 100644 homework_10/task_1/testFiles/fiveCitiesTwoCountries_graph.txt create mode 100644 homework_10/task_1/testFiles/singleCity_countries.txt create mode 100644 homework_10/task_1/testFiles/singleCity_graph.txt create mode 100644 homework_10/task_1/testFiles/twoCities_countries.txt create mode 100644 homework_10/task_1/testFiles/twoCities_graph.txt diff --git a/homework_10/task_1/test.c b/homework_10/task_1/test.c index 059e20b..abb9a0c 100644 --- a/homework_10/task_1/test.c +++ b/homework_10/task_1/test.c @@ -3,7 +3,113 @@ #include "../../ctest/ctest.h" #include "graph.h" +#include "fileGraphReader.h" + +#define TEST_FILES "testFiles/" +#define GRAPH "_graph.txt" +#define COUNTRIES "_countries.txt" int main(int argc, const char *argv[]) { return ctest_main(argc, argv); } + +GraphNode *getNodeById(GraphNode **nodes, int nodeCount, int id) { + for (int i = 0; i < nodeCount; ++i) { + if (i == id) { + return nodes[i]; + } + } + ASSERT_FAIL(); + return NULL; +} + +void assertCountry(GraphNode **nodes, int nodeCount, Country *country, FILE *file) { + GraphNode **cities = NULL; + int cityCount = 0; + ASSERT_TRUE(getAllCities(country, &cities, &cityCount)); + + int expectedCityCount = 0; + ASSERT_EQUAL(fscanf(file, "%d", &expectedCityCount), 1); + ASSERT_EQUAL(expectedCityCount, cityCount); + + for (int i = 0; i < cityCount; ++i) { + int expectedCityId = -1; + ASSERT_EQUAL(fscanf(file, "%d", &expectedCityId), 1); + + GraphNode *expectedNode = getNodeById(nodes, nodeCount, expectedCityId); + + int foundCityIndex = -1; + for (int j = 0; j < cityCount; ++j) { + if (expectedNode == cities[j]) { + foundCityIndex = j; + break; + } + } + + ASSERT_NOT_EQUAL(foundCityIndex, -1); + cities[foundCityIndex] = NULL; + } + + for (int i = 0; i < cityCount; ++i) { + ASSERT_NULL(cities[i]); + } +} + +void testGraph(const char *inputFilename, const char *expectedOutputFilename) { + FILE *inputFile = fopen(inputFilename, "r"); + ASSERT_NOT_NULL(inputFile); + + FILE *expectedOutputFile = fopen(expectedOutputFilename, "r"); + ASSERT_NOT_NULL(expectedOutputFile); + + GraphNode **nodes = NULL; + int nodeCount = 0; + Country **countries = NULL; + int countryCount = 0; + ASSERT_EQUAL(READ_OK, readFileFromFileAndCreateCountries(inputFile, &nodes, &nodeCount, &countries, &countryCount, NULL)); + ASSERT_EQUAL(fclose(inputFile), 0); + + int expectedCountryCount = 0; + ASSERT_EQUAL(fscanf(expectedOutputFile, "%d", &expectedCountryCount), 1); + ASSERT_EQUAL(expectedCountryCount, countryCount); + + for (int i = 0; i < countryCount; ++i) { + assertCountry(nodes, nodeCount, countries[i], expectedOutputFile); + } + + ASSERT_EQUAL(fclose(expectedOutputFile), 0); + + for (int i = 0; i < nodeCount; ++i) { + disposeNode(nodes[i]); + } + free(nodes); + + for (int i = 0; i < countryCount; ++i) { + disposeCountry(countries[i]); + } + free(countries); +} + +CTEST(graphTests, graphTestSingleCity) { + testGraph(TEST_FILES "singleCity" GRAPH, TEST_FILES "singleCity" COUNTRIES); +} + +CTEST(graphTests, graphTestTwoCities) { + testGraph(TEST_FILES "singleCity" GRAPH, TEST_FILES "singleCity" COUNTRIES); +} + +CTEST(graphTests, graphTestFiveCitiesTwoCountries) { + testGraph(TEST_FILES "fiveCitiesTwoCountries" GRAPH, TEST_FILES "fiveCitiesTwoCountries" COUNTRIES); +} + +CTEST(graphTests, graphTestFiveCitiesFiveCountries) { + testGraph(TEST_FILES "fiveCitiesFiveCountries" GRAPH, TEST_FILES "fiveCitiesFiveCountries" COUNTRIES); +} + +CTEST(graphTests, graphTestComplexA) { + testGraph(TEST_FILES "complexA" GRAPH, TEST_FILES "complexA" COUNTRIES); +} + +CTEST(graphTests, graphTestComplexB) { + testGraph(TEST_FILES "complexB" GRAPH, TEST_FILES "complexB" COUNTRIES); +} diff --git a/homework_10/task_1/testFiles/complexA_countries.txt b/homework_10/task_1/testFiles/complexA_countries.txt new file mode 100644 index 0000000..aed53c5 --- /dev/null +++ b/homework_10/task_1/testFiles/complexA_countries.txt @@ -0,0 +1,51 @@ +4 +11 +7 +8 +11 +15 +32 +30 +14 +33 +34 +31 +35 +14 +17 +4 +1 +12 +3 +5 +10 +25 +22 +2 +23 +40 +24 +41 +11 +0 +27 +6 +28 +16 +37 +36 +26 +29 +39 +38 +10 +13 +20 +21 +9 +19 +44 +43 +18 +45 +42 diff --git a/homework_10/task_1/testFiles/complexA_graph.txt b/homework_10/task_1/testFiles/complexA_graph.txt new file mode 100644 index 0000000..281f72e --- /dev/null +++ b/homework_10/task_1/testFiles/complexA_graph.txt @@ -0,0 +1,97 @@ +46 +90 +0 15 7 +0 16 6 +0 6 5 +0 27 4 +0 28 5 +28 36 5 +28 27 5 +28 29 6 +29 36 5 +29 34 6 +29 15 6 +15 7 8 +15 11 7 +15 6 5 +15 34 5 +34 35 7 +34 30 5 +30 31 6 +30 7 8 +7 8 6 +7 11 6 +7 32 8 +7 14 8 +14 10 5 +14 11 5 +11 4 7 +11 5 6 +5 6 4 +5 17 8 +5 4 6 +5 16 5 +16 1 5 +16 17 10 +16 26 4 +26 27 7 +26 38 5 +26 39 4 +39 25 4 +39 38 6 +38 37 9 +37 36 8 +37 27 5 +36 35 8 +25 40 5 +25 1 5 +25 24 7 +24 2 4 +24 41 6 +24 23 5 +24 40 6 +23 3 6 +23 42 7 +23 2 5 +23 41 5 +2 3 5 +2 1 7 +1 17 5 +17 12 7 +17 4 5 +17 3 7 +3 13 10 +3 22 4 +22 21 8 +22 42 4 +22 43 8 +43 44 7 +43 21 4 +43 42 8 +21 13 5 +21 20 6 +20 19 5 +20 44 5 +20 13 4 +13 9 8 +13 12 7 +12 10 5 +10 4 4 +10 9 4 +9 8 7 +9 19 6 +9 18 4 +18 33 6 +18 45 8 +18 19 6 +18 8 7 +8 33 5 +8 32 8 +32 31 5 +32 33 7 +19 45 6 +4 +7 +17 +0 +13 diff --git a/homework_10/task_1/testFiles/complexB_countries.txt b/homework_10/task_1/testFiles/complexB_countries.txt new file mode 100644 index 0000000..fef44ea --- /dev/null +++ b/homework_10/task_1/testFiles/complexB_countries.txt @@ -0,0 +1,52 @@ +5 +8 +17 +42 +15 +6 +1 +41 +43 +22 +12 +10 +30 +44 +20 +13 +19 +31 +29 +28 +27 +32 +45 +7 +16 +38 +40 +37 +39 +36 +35 +8 +14 +2 +23 +25 +18 +12 +24 +26 +11 +9 +3 +5 +4 +8 +0 +7 +34 +21 +11 +33 diff --git a/homework_10/task_1/testFiles/complexB_graph.txt b/homework_10/task_1/testFiles/complexB_graph.txt new file mode 100644 index 0000000..7ce7218 --- /dev/null +++ b/homework_10/task_1/testFiles/complexB_graph.txt @@ -0,0 +1,90 @@ +46 +82 +0 5 5 +0 6 6 +0 1 6 +0 4 7 +4 2 6 +4 9 7 +4 18 8 +4 14 7 +14 18 7 +14 2 5 +14 23 5 +14 25 5 +25 26 7 +25 24 4 +25 19 5 +19 2 6 +19 13 5 +19 10 8 +19 26 5 +26 13 6 +13 10 7 +13 27 4 +27 45 4 +45 28 5 +45 29 5 +29 30 5 +29 28 5 +28 30 5 +30 31 5 +30 20 6 +30 10 4 +10 20 6 +10 44 5 +44 3 5 +3 7 7 +3 9 5 +3 20 5 +20 11 6 +20 21 8 +21 11 5 +21 7 6 +21 34 4 +21 33 8 +33 32 7 +32 11 5 +32 31 4 +31 11 6 +34 7 5 +7 8 8 +7 35 7 +35 36 5 +36 37 7 +36 8 4 +8 9 7 +8 5 5 +8 16 8 +16 6 7 +16 5 7 +16 38 4 +16 40 4 +16 37 5 +40 6 4 +40 39 3 +39 38 5 +6 17 6 +6 1 7 +1 17 6 +1 18 4 +18 17 8 +18 22 5 +18 23 5 +23 24 6 +22 15 5 +15 17 5 +15 43 4 +43 42 5 +43 41 7 +41 42 4 +42 17 3 +5 9 6 +9 12 7 +12 2 4 +5 +17 +10 +16 +14 +9 diff --git a/homework_10/task_1/testFiles/fiveCitiesFiveCountries_countries.txt b/homework_10/task_1/testFiles/fiveCitiesFiveCountries_countries.txt new file mode 100644 index 0000000..9b8dbae --- /dev/null +++ b/homework_10/task_1/testFiles/fiveCitiesFiveCountries_countries.txt @@ -0,0 +1,11 @@ +5 +1 +0 +1 +1 +1 +2 +1 +3 +1 +4 diff --git a/homework_10/task_1/testFiles/fiveCitiesFiveCountries_graph.txt b/homework_10/task_1/testFiles/fiveCitiesFiveCountries_graph.txt new file mode 100644 index 0000000..0869df9 --- /dev/null +++ b/homework_10/task_1/testFiles/fiveCitiesFiveCountries_graph.txt @@ -0,0 +1,17 @@ +5 +9 +0 1 9 +0 4 8 +0 3 11 +0 2 11 +2 3 6 +2 1 4 +1 4 15 +1 3 8 +3 4 11 +5 +0 +1 +2 +3 +4 diff --git a/homework_10/task_1/testFiles/fiveCitiesTwoCountries_countries.txt b/homework_10/task_1/testFiles/fiveCitiesTwoCountries_countries.txt new file mode 100644 index 0000000..435e914 --- /dev/null +++ b/homework_10/task_1/testFiles/fiveCitiesTwoCountries_countries.txt @@ -0,0 +1,8 @@ +2 +3 +0 +4 +1 +2 +2 +3 diff --git a/homework_10/task_1/testFiles/fiveCitiesTwoCountries_graph.txt b/homework_10/task_1/testFiles/fiveCitiesTwoCountries_graph.txt new file mode 100644 index 0000000..f793a08 --- /dev/null +++ b/homework_10/task_1/testFiles/fiveCitiesTwoCountries_graph.txt @@ -0,0 +1,12 @@ +5 +7 +0 4 6 +0 1 7 +1 4 9 +1 2 6 +2 4 8 +2 3 5 +3 4 6 +2 +0 +2 diff --git a/homework_10/task_1/testFiles/singleCity_countries.txt b/homework_10/task_1/testFiles/singleCity_countries.txt new file mode 100644 index 0000000..2f1465d --- /dev/null +++ b/homework_10/task_1/testFiles/singleCity_countries.txt @@ -0,0 +1,3 @@ +1 +1 +0 diff --git a/homework_10/task_1/testFiles/singleCity_graph.txt b/homework_10/task_1/testFiles/singleCity_graph.txt new file mode 100644 index 0000000..d80fc78 --- /dev/null +++ b/homework_10/task_1/testFiles/singleCity_graph.txt @@ -0,0 +1,4 @@ +1 +0 +1 +0 diff --git a/homework_10/task_1/testFiles/twoCities_countries.txt b/homework_10/task_1/testFiles/twoCities_countries.txt new file mode 100644 index 0000000..1b723b1 --- /dev/null +++ b/homework_10/task_1/testFiles/twoCities_countries.txt @@ -0,0 +1,4 @@ +1 +2 +0 +1 diff --git a/homework_10/task_1/testFiles/twoCities_graph.txt b/homework_10/task_1/testFiles/twoCities_graph.txt new file mode 100644 index 0000000..681c29c --- /dev/null +++ b/homework_10/task_1/testFiles/twoCities_graph.txt @@ -0,0 +1,5 @@ +2 +1 +0 1 8 +1 +0 From f8028e1c1df3b414c3a7debcb7cbbcfc2d2c557e Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:38:36 +0300 Subject: [PATCH 27/33] Removed unused getAllNeighbors() (hw10 task 1) --- homework_10/task_1/graph.c | 15 --------------- homework_10/task_1/graph.h | 2 -- 2 files changed, 17 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 4f62d96..d9614ab 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -356,21 +356,6 @@ ConnectionResult connect(GraphNode *nodeA, GraphNode *nodeB, int distance) { return addNeighbor(nodeB, nodeA, distance); } -bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length) { - int count = node->neighbors.count; - *neighbors = calloc(count, sizeof(GraphNode *)); - if (*neighbors == NULL) { - return false; - } - - for (int i = 0; i < count; ++i) { - (*neighbors)[count] = node->neighbors.data[i].node; - } - - *length = count; - return true; -} - void disposeNode(GraphNode *node) { if (node == NULL) { return; diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index 30e8395..4518162 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -12,8 +12,6 @@ bool createNode(GraphNode **node); ConnectionResult connect(GraphNode *nodeA, GraphNode *nodeB, int distance); -bool getAllNeighbors(GraphNode *node, GraphNode ***neighbors, int *length); - void disposeNode(GraphNode *node); typedef struct Country Country; From 57cd7d7febfbd25eacae61eb2c2eb3aeb12d02e5 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:49:44 +0300 Subject: [PATCH 28/33] Fixed typo (hw10 task 1) --- homework_10/task_1/fileGraphReader.c | 2 +- homework_10/task_1/fileGraphReader.h | 2 +- homework_10/task_1/main.c | 2 +- homework_10/task_1/test.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homework_10/task_1/fileGraphReader.c b/homework_10/task_1/fileGraphReader.c index 9397522..438e1f5 100644 --- a/homework_10/task_1/fileGraphReader.c +++ b/homework_10/task_1/fileGraphReader.c @@ -5,7 +5,7 @@ #include "graph.h" -ReadResult readFileFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput) { +ReadResult readGraphFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput) { int storedNodeCount = 0; if (fscanf(file, "%d", &storedNodeCount) != 1) { if (warningAndErrorOutput != NULL) { diff --git a/homework_10/task_1/fileGraphReader.h b/homework_10/task_1/fileGraphReader.h index b24c85f..2a3e7a0 100644 --- a/homework_10/task_1/fileGraphReader.h +++ b/homework_10/task_1/fileGraphReader.h @@ -10,4 +10,4 @@ typedef enum { READ_FILE_ERROR, } ReadResult; -ReadResult readFileFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput); +ReadResult readGraphFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput); diff --git a/homework_10/task_1/main.c b/homework_10/task_1/main.c index 53519ac..6a80bf2 100644 --- a/homework_10/task_1/main.c +++ b/homework_10/task_1/main.c @@ -15,7 +15,7 @@ int main() { int nodeCount = 0; Country **countries = NULL; int countryCount = 0; - switch (readFileFromFileAndCreateCountries(file, &nodes, &nodeCount, &countries, &countryCount, stdout)) { + switch (readGraphFromFileAndCreateCountries(file, &nodes, &nodeCount, &countries, &countryCount, stdout)) { case READ_OK: break; case READ_ALLOCATION_ERROR: diff --git a/homework_10/task_1/test.c b/homework_10/task_1/test.c index abb9a0c..c89e2d5 100644 --- a/homework_10/task_1/test.c +++ b/homework_10/task_1/test.c @@ -66,7 +66,7 @@ void testGraph(const char *inputFilename, const char *expectedOutputFilename) { int nodeCount = 0; Country **countries = NULL; int countryCount = 0; - ASSERT_EQUAL(READ_OK, readFileFromFileAndCreateCountries(inputFile, &nodes, &nodeCount, &countries, &countryCount, NULL)); + ASSERT_EQUAL(READ_OK, readGraphFromFileAndCreateCountries(inputFile, &nodes, &nodeCount, &countries, &countryCount, NULL)); ASSERT_EQUAL(fclose(inputFile), 0); int expectedCountryCount = 0; From 3d833005f5735aec3124c574cdec1b9b32f2ca88 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:53:26 +0300 Subject: [PATCH 29/33] Added comments (hw10 task 1) --- homework_10/task_1/fileGraphReader.h | 12 +++++++++++ homework_10/task_1/graph.h | 30 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/homework_10/task_1/fileGraphReader.h b/homework_10/task_1/fileGraphReader.h index 2a3e7a0..536fcdf 100644 --- a/homework_10/task_1/fileGraphReader.h +++ b/homework_10/task_1/fileGraphReader.h @@ -10,4 +10,16 @@ typedef enum { READ_FILE_ERROR, } ReadResult; +/// @brief Reads graph from file and creates countries +/// @param file File to read graph from +/// @param nodes Pointer to store array of nodes to +/// @param nodeCount Pointer to store nodes count +/// @param countries Pointer to store array of countries to +/// @param countryCount Pointer to store countries count +/// @param warningAndErrorOutput File to write warning or error messages, can be `NULL` +/// @return `READ_OK` if read file and created countries successfully +/// +/// `READ_FILE_ERROR` if file has incorrect format +/// +/// `READ_ALLOCATION_ERROR` if allocation failed ReadResult readGraphFromFileAndCreateCountries(FILE *file, GraphNode ***nodes, int *nodeCount, Country ***countries, int *countryCount, FILE *warningAndErrorOutput); diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index 4518162..21c7d59 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -6,18 +6,48 @@ typedef enum { CONNECTION_ALREADY_EXISTS } ConnectionResult; +/// @brief Node of a graph typedef struct GraphNode GraphNode; +/// @brief Creates new `GraphNode` +/// @param node Pointer to store `GraphNode` to +/// @return `true` if created successfully, `false` otherwise (allocation failed) bool createNode(GraphNode **node); +/// @brief Connect two graph nodes +/// @param nodeA First node +/// @param nodeB Second node +/// @param distance Distance between nodes +/// @return `CONNECTION_OK` if connected successfully +/// +/// `CONNECTION_ALREADY_EXISTS` if specified nodes were already connected +/// +/// `CONNECTION_ALLOCATION_ERROR` if allocation failed ConnectionResult connect(GraphNode *nodeA, GraphNode *nodeB, int distance); +/// @brief Disposes node +/// @note This method expects that ALL nodes created with `createNode()` will be disposed at once, for example in a single for loop +/// @param node Node to dispose void disposeNode(GraphNode *node); +/// @brief Country that contains array of cities typedef struct Country Country; +/// @brief Creates countries using specified capitals by capturing cities that are closest to a capital +/// @param capitals Capitals to base countries on +/// @param countries Pointer to store array of countries to +/// @param capitalsCount Capitals count (same as countries count) +/// @return `true` if created successfully, `false` otherwise (allocation failed) bool createCountries(GraphNode **capitals, Country ***countries, int capitalsCount); +/// @brief Gets all cities in a country +/// @param country Country to get cities from +/// @param nodes Pointer to store array of cities to +/// @param length Pointer to store length of array +/// @return `true` if created successfully, `false` otherwise (allocation failed) bool getAllCities(Country *country, GraphNode ***nodes, int *length); +/// @brief Disposes country +/// @note This method DOES NOT dispose cities in that country, dispose them separately +/// @param country Country to dispose void disposeCountry(Country *country); From 281edfa89bc78622ea35336fbe1871522f8a3e21 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 10 Dec 2024 03:35:39 +0300 Subject: [PATCH 30/33] Added stdbool.h includes (hw10 task 1) --- homework_10/task_1/graph.c | 1 + homework_10/task_1/graph.h | 2 ++ homework_10/task_1/main.c | 1 + 3 files changed, 4 insertions(+) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index d9614ab..6f5e9fa 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -1,5 +1,6 @@ #include "graph.h" +#include #include #include diff --git a/homework_10/task_1/graph.h b/homework_10/task_1/graph.h index 21c7d59..4562c1b 100644 --- a/homework_10/task_1/graph.h +++ b/homework_10/task_1/graph.h @@ -1,5 +1,7 @@ #pragma once +#include + typedef enum { CONNECTION_OK, CONNECTION_ALLOCATION_ERROR, diff --git a/homework_10/task_1/main.c b/homework_10/task_1/main.c index 6a80bf2..5e9de4d 100644 --- a/homework_10/task_1/main.c +++ b/homework_10/task_1/main.c @@ -1,3 +1,4 @@ +#include #include #include From 6fd94467d1bf87f14491ad8fe04a143a40019135 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Tue, 10 Dec 2024 03:37:49 +0300 Subject: [PATCH 31/33] Added stdlib.h include (hw10 task 1) --- homework_10/task_1/test.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homework_10/task_1/test.c b/homework_10/task_1/test.c index c89e2d5..affb8ea 100644 --- a/homework_10/task_1/test.c +++ b/homework_10/task_1/test.c @@ -2,6 +2,8 @@ #define CTEST_SEGFAULT #include "../../ctest/ctest.h" +#include + #include "graph.h" #include "fileGraphReader.h" From 2e0fa41cec35412254ae4ee06e74233c6fa09c06 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 30 Dec 2024 23:55:32 +0300 Subject: [PATCH 32/33] Check hashtable resize result (hw10 task 1) --- homework_10/task_1/graph.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index 6f5e9fa..e587066 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -173,7 +173,9 @@ static unsigned int getHashCode(GraphNode *node) { bool addDistanceToHashtable(NodeHashtable *hashtable, GraphNode *node, int distance) { if ((float)hashtable->count / hashtable->capacity > 4.0) { - expandHashtable(hashtable); + if (!expandHashtable(hashtable)) { + return false; + } } int bucketIndex = getHashCode(node) % hashtable->capacity; From 8ece014a84036e91eaab235cd12e43b0ce408fb4 Mon Sep 17 00:00:00 2001 From: ilya-krivtsov <180809461+ilya-krivtsov@users.noreply.github.com> Date: Mon, 30 Dec 2024 23:56:14 +0300 Subject: [PATCH 33/33] Simplified return in createQueue() (hw10 task 1) --- homework_10/task_1/graph.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/homework_10/task_1/graph.c b/homework_10/task_1/graph.c index e587066..0f5f4d0 100644 --- a/homework_10/task_1/graph.c +++ b/homework_10/task_1/graph.c @@ -241,10 +241,7 @@ typedef struct { bool createQueue(Queue **queue) { *queue = calloc(1, sizeof(Queue)); - if (*queue == NULL) { - return false; - } - return true; + return *queue != NULL; } bool enqueue(Queue *queue, GraphNode *node, int distance) {