diff --git a/homework_4/CMakeLists.txt b/homework_4/CMakeLists.txt index 944093a..5624f58 100644 --- a/homework_4/CMakeLists.txt +++ b/homework_4/CMakeLists.txt @@ -4,3 +4,4 @@ set(homeworkName "${PROJECT_NAME}") add_subdirectory(task_1) add_subdirectory(task_2) +add_subdirectory(task_3) diff --git a/homework_4/README.md b/homework_4/README.md index e7fc184..688863e 100644 --- a/homework_4/README.md +++ b/homework_4/README.md @@ -3,3 +3,5 @@ [Task 1. Binary representation](/homework_4/task_1) [Task 2. Phone database](/homework_4/task_2) + +[Task 3. Modules and files](/homework_4/task_3) diff --git a/homework_4/task_3/CMakeLists.txt b/homework_4/task_3/CMakeLists.txt new file mode 100644 index 0000000..ab54a54 --- /dev/null +++ b/homework_4/task_3/CMakeLists.txt @@ -0,0 +1,10 @@ +project("${homeworkName}_task_3") + +add_library(newFrequencySearch frequencySearch.c) +add_library(arrayIO arrayIO.c) + +add_executable(${PROJECT_NAME} main.c) +target_link_libraries(${PROJECT_NAME} newFrequencySearch arrayIO) + +add_executable(${PROJECT_NAME}_test test.c) +target_link_libraries(${PROJECT_NAME}_test newFrequencySearch arrayIO) diff --git a/homework_4/task_3/arrayIO.c b/homework_4/task_3/arrayIO.c new file mode 100644 index 0000000..16a1a48 --- /dev/null +++ b/homework_4/task_3/arrayIO.c @@ -0,0 +1,34 @@ +#include "arrayIO.h" + +#include +#include +#include + +bool readFromStream(FILE *file, int **array, int *arrayLength) { + int arrayCapacity = 4; + *arrayLength = 0; + *array = malloc(arrayCapacity * sizeof(int)); + + if (array == NULL) { + return false; + } + + while (!feof(file)) { + int value = -1; + if (fscanf(file, "%d", &value) != 1) { + continue; + } + + if (*arrayLength == arrayCapacity) { + arrayCapacity *= 2; + *array = realloc(*array, arrayCapacity * sizeof(int)); + if (*array == NULL) { + return false; + } + } + (*array)[*arrayLength] = value; + ++*arrayLength; + } + + return true; +} diff --git a/homework_4/task_3/arrayIO.h b/homework_4/task_3/arrayIO.h new file mode 100644 index 0000000..80ec6ce --- /dev/null +++ b/homework_4/task_3/arrayIO.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +bool readFromStream(FILE *file, int **array, int *arrayLength); diff --git a/homework_4/task_3/frequencySearch.c b/homework_4/task_3/frequencySearch.c new file mode 100644 index 0000000..a12b4ca --- /dev/null +++ b/homework_4/task_3/frequencySearch.c @@ -0,0 +1,84 @@ +#include "frequencySearch.h" + +#include +#include + +int partition(int *array, int left, int right) { + int first = array[left], middle = array[(left + right) / 2], last = array[right]; + + int pivot = first; + if (first <= middle && middle <= last) { + pivot = middle; + } else if (middle <= first && first <= last) { + pivot = first; + } else { + pivot = last; + } + + --left; + ++right; + + while (true) { + do { + ++left; + } while (array[left] < pivot); + do { + --right; + } while (array[right] > pivot); + + if (left >= right) break; + + int t = array[left]; + array[left] = array[right]; + array[right] = t; + } + + return right; +} + +void quickSort(int *array, int left, int right) { + if (left >= right) { + return; + } + + int part = partition(array, left, right); + quickSort(array, left, part); + quickSort(array, part + 1, right); +} + +bool findMostFrequentElement(int *array, int arrayLength, int *mostFrequentElement, int *occurrences) { + if (arrayLength == 0) { + return false; + } + + quickSort(array, 0, arrayLength - 1); + + int element = array[0], count = 0; + int maxCountElement = element, maxCount = count; + + for (int i = 0; i < arrayLength; ++i) { + if (array[i] != element) { + if (count > maxCount) { + maxCount = count; + maxCountElement = element; + } + count = 0; + element = array[i]; + } + ++count; + } + + if (count > maxCount) { + maxCount = count; + maxCountElement = element; + } + + if (mostFrequentElement != NULL) { + *mostFrequentElement = maxCountElement; + } + if (occurrences != NULL) { + *occurrences = maxCount; + } + + return true; +} diff --git a/homework_4/task_3/frequencySearch.h b/homework_4/task_3/frequencySearch.h new file mode 100644 index 0000000..f087b91 --- /dev/null +++ b/homework_4/task_3/frequencySearch.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +bool findMostFrequentElement(int *array, int arrayLength, int *mostFrequentElement, int *occurrences); diff --git a/homework_4/task_3/main.c b/homework_4/task_3/main.c new file mode 100644 index 0000000..d713f1e --- /dev/null +++ b/homework_4/task_3/main.c @@ -0,0 +1,43 @@ +#include +#include + +#include "frequencySearch.h" +#include "arrayIO.h" + +int main(void) { + char buffer[1024]; + printf("input file path: "); + if (scanf("%1023s", buffer) != 1) { + printf("couldn't open file\n"); + return 1; + } + + FILE *file = fopen(buffer, "r"); + if (file == NULL) { + perror("opening file failed"); + return 1; + } + + int *array; + int arrayLength; + if (!readFromStream(file, &array, &arrayLength)) { + printf("allocation error\n"); + return 1; + } + + if (ferror(file)) { + perror("read error"); + fclose(file); + return 1; + } + fclose(file); + + int mostFrequentElement, occurrences; + if (findMostFrequentElement(array, arrayLength, &mostFrequentElement, &occurrences)) { + printf("most frequent element is %d (appears %d time%s)\n", mostFrequentElement, occurrences, occurrences == 1 ? "" : "s"); + } else { + printf("couldn't find most frequent element: array is empty\n"); + } + + free(array); +} diff --git a/homework_4/task_3/test.c b/homework_4/task_3/test.c new file mode 100644 index 0000000..19f1709 --- /dev/null +++ b/homework_4/task_3/test.c @@ -0,0 +1,77 @@ +#define CTEST_MAIN +#define CTEST_SEGFAULT +#include "../../ctest/ctest.h" + +#include + +#include "frequencySearch.h" +#include "arrayIO.h" + +int main(int argc, const char *argv[]) { + return ctest_main(argc, argv); +} + +CTEST(frequencySearchTests, emptyArrayTest) { + ASSERT_FALSE(findMostFrequentElement(NULL, 0, NULL, NULL)); +} + +CTEST(frequencySearchTests, oneElementArrayTest) { +#define size 1 + int array[size] = { 42 }; + int mostFrequentExpected = 42; + int mostFrequentResult = 0; + ASSERT_TRUE(findMostFrequentElement(array, size, &mostFrequentResult, NULL)); + ASSERT_EQUAL(mostFrequentResult, mostFrequentExpected); +#undef size +} + +CTEST(frequencySearchTests, sameElementsArrayTest) { +#define size 8 + int array[size] = { 42, 42, 42, 42, 42, 42, 42, 42 }; + int mostFrequentExpected = 42, occurrencesExpected = size; + int mostFrequentResult = 0, occurrencesResult = 0; + ASSERT_TRUE(findMostFrequentElement(array, size, &mostFrequentResult, &occurrencesResult)); + ASSERT_EQUAL(mostFrequentResult, mostFrequentExpected); + ASSERT_EQUAL(occurrencesResult, occurrencesExpected); +#undef size +} + +CTEST(frequencySearchTests, constantArrayTest) { +#define size 10 + int array[size] = { 1, 2, 3, 3, 3, 7, 9, 12, 8, 3 }; + int mostFrequentExpected = 3, occurrencesExpected = 4; + int mostFrequentResult = 0, occurrencesResult = 0; + ASSERT_TRUE(findMostFrequentElement(array, size, &mostFrequentResult, &occurrencesResult)); + ASSERT_EQUAL(mostFrequentResult, mostFrequentExpected); + ASSERT_EQUAL(occurrencesResult, occurrencesExpected); +#undef size +} + +void loadFile(const char *path, int **array, int *arrayLength) { + FILE *file = fopen(path, "r"); + ASSERT_NOT_NULL(file); + ASSERT_TRUE(readFromStream(file, array, arrayLength)); + ASSERT_EQUAL(fclose(file), 0); +} + +CTEST(arrayIOTests, emptyArrayTest) { + int *array, arrayLength; + loadFile("./testFiles/emptyArray", &array, &arrayLength); + ASSERT_EQUAL(arrayLength, 0); +} + +CTEST(arrayIOTests, singleElementTest) { + int *array, arrayLength; + loadFile("./testFiles/singleElement", &array, &arrayLength); + ASSERT_EQUAL(arrayLength, 1); + ASSERT_EQUAL(array[0], 8192); +} + +CTEST(arrayIOTests, incrementalArrayTest) { + int *array, arrayLength; + loadFile("./testFiles/incrementalArray", &array, &arrayLength); + ASSERT_EQUAL(arrayLength, 8); + for (int i = 0; i < arrayLength; ++i) { + ASSERT_EQUAL(i, array[i]); + } +} diff --git a/homework_4/task_3/testFiles/emptyArray b/homework_4/task_3/testFiles/emptyArray new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/homework_4/task_3/testFiles/emptyArray @@ -0,0 +1 @@ + diff --git a/homework_4/task_3/testFiles/incrementalArray b/homework_4/task_3/testFiles/incrementalArray new file mode 100644 index 0000000..95caba1 --- /dev/null +++ b/homework_4/task_3/testFiles/incrementalArray @@ -0,0 +1,8 @@ +0 +1 +2 +3 +4 +5 +6 +7 diff --git a/homework_4/task_3/testFiles/singleElement b/homework_4/task_3/testFiles/singleElement new file mode 100644 index 0000000..252cb66 --- /dev/null +++ b/homework_4/task_3/testFiles/singleElement @@ -0,0 +1 @@ +8192