diff --git a/sk1/compressor.c b/sk1/compressor.c index db7d3f9..679c26f 100644 --- a/sk1/compressor.c +++ b/sk1/compressor.c @@ -21,7 +21,7 @@ int compress_2(const char* input_file_name, const char* output_file_name) { unsigned char current_byte, previous_byte; size_t count = 0; - + // Читаємо перший байт if (fread(&previous_byte, 1, 1, infile) != 1) { fclose(infile); @@ -88,64 +88,87 @@ int decompress_2(const char* input_file_name, const char* output_file_name) { // --- Алгоритм Хаффмана (Huffman Coding) --- -// Структура для вузлів дерева Хаффмана -typedef struct { +typedef struct Node { unsigned char symbol; size_t frequency; -} HuffmanSymbol; - -typedef struct Node { - HuffmanSymbol symbol; struct Node *left, *right; } Node; +// Структура для кодів Хаффмана +typedef struct { + unsigned char symbol; + char *code; +} HuffmanCode; + // Функція для порівняння вузлів для використання в черзі int compare_nodes(const void *a, const void *b) { - return ((Node*)a)->symbol.frequency - ((Node*)b)->symbol.frequency; + return ((Node*)a)->frequency - ((Node*)b)->frequency; } // Створення дерева Хаффмана -Node* create_huffman_tree(HuffmanSymbol* symbols, size_t n) { - // Використовуємо чергу для побудови дерева Хаффмана - qsort(symbols, n, sizeof(HuffmanSymbol), compare_nodes); - - // Створюємо чергу вузлів для побудови дерева - Node** queue = malloc(n * sizeof(Node*)); - for (size_t i = 0; i < n; i++) { - queue[i] = malloc(sizeof(Node)); - queue[i]->symbol = symbols[i]; - queue[i]->left = queue[i]->right = NULL; +Node* create_huffman_tree(unsigned char *data, size_t size) { + size_t freq[256] = {0}; + for (size_t i = 0; i < size; i++) { + freq[data[i]]++; } - size_t queue_size = n; + // Створюємо список вузлів + Node *nodes[256]; + size_t node_count = 0; - // Побудова дерева Хаффмана - while (queue_size > 1) { - // Зливаємо два найменші елементи - Node* left = queue[0]; - Node* right = queue[1]; + for (int i = 0; i < 256; i++) { + if (freq[i] > 0) { + nodes[node_count] = malloc(sizeof(Node)); + nodes[node_count]->symbol = (unsigned char)i; + nodes[node_count]->frequency = freq[i]; + nodes[node_count]->left = nodes[node_count]->right = NULL; + node_count++; + } + } + + // Сортуємо вузли по частоті + qsort(nodes, node_count, sizeof(Node*), compare_nodes); + + // Побудова дерева + while (node_count > 1) { + Node* left = nodes[0]; + Node* right = nodes[1]; Node* parent = malloc(sizeof(Node)); - parent->symbol.symbol = 0; // Спільний символ - parent->symbol.frequency = left->symbol.frequency + right->symbol.frequency; + parent->symbol = 0; + parent->frequency = left->frequency + right->frequency; parent->left = left; parent->right = right; - // Видаляємо перші два елементи з черги та додаємо новий - memmove(queue, queue + 2, (queue_size - 2) * sizeof(Node*)); - queue[queue_size - 2] = parent; - queue_size--; + // Зміщуємо вузли в черзі + memmove(nodes, nodes + 2, (node_count - 2) * sizeof(Node*)); + nodes[node_count - 2] = parent; + node_count--; - qsort(queue, queue_size, sizeof(Node*), compare_nodes); + qsort(nodes, node_count, sizeof(Node*), compare_nodes); } - Node* root = queue[0]; - free(queue); - - return root; + return nodes[0]; // Повертаємо корінь дерева } -// Функція для стиснення з використанням дерева Хаффмана +// Функція для рекурсивного запису бітових кодів з дерева Хаффмана +void generate_huffman_codes(Node* root, HuffmanCode* codes, char* current_code, int depth) { + if (!root) return; + + if (root->left == NULL && root->right == NULL) { + current_code[depth] = '\0'; + codes[root->symbol].symbol = root->symbol; + codes[root->symbol].code = strdup(current_code); + } + + current_code[depth] = '0'; + generate_huffman_codes(root->left, codes, current_code, depth + 1); + + current_code[depth] = '1'; + generate_huffman_codes(root->right, codes, current_code, depth + 1); +} + +// Функція для стиснення за допомогою Хаффмана int compress_1(const char* input_file_name, const char* output_file_name) { FILE *infile = fopen(input_file_name, "rb"); if (!infile) { @@ -157,43 +180,51 @@ int compress_1(const char* input_file_name, const char* output_file_name) { size_t file_size = ftell(infile); fseek(infile, 0, SEEK_SET); - unsigned char* buffer = malloc(file_size); - if (!buffer) { + unsigned char* data = malloc(file_size); + if (!data) { fclose(infile); return -1; } - fread(buffer, 1, file_size, infile); + fread(data, 1, file_size, infile); fclose(infile); - // Підрахунок частоти кожного байта - size_t frequencies[256] = {0}; - for (size_t i = 0; i < file_size; i++) { - frequencies[buffer[i]]++; + // Створюємо дерево Хаффмана + Node* root = create_huffman_tree(data, file_size); + + // Генерація кодів Хаффмана + HuffmanCode codes[256]; + for (int i = 0; i < 256; i++) { + codes[i].code = NULL; } - HuffmanSymbol symbols[256]; - size_t num_symbols = 0; + char current_code[256]; + generate_huffman_codes(root, codes, current_code, 0); - for (int i = 0; i < 256; i++) { - if (frequencies[i] > 0) { - symbols[num_symbols].symbol = (unsigned char)i; - symbols[num_symbols].frequency = frequencies[i]; - num_symbols++; + // Стиснення даних + FILE *outfile = fopen(output_file_name, "wb"); + if (!outfile) { + free(data); + return -1; + } + + for (size_t i = 0; i < file_size; i++) { + unsigned char symbol = data[i]; + const char* code = codes[symbol].code; + for (size_t j = 0; code[j] != '\0'; j++) { + // Записуємо біт в файл + fputc(code[j] == '1' ? 1 : 0, outfile); } } - Node* huffman_tree = create_huffman_tree(symbols, num_symbols); + fclose(outfile); + free(data); - // Тут треба реалізувати кодування та запис бітових кодів в файл - // Оскільки це складніше, я залишаю це як заготовку для подальшої реалізації - - free(buffer); - return 1; + return 1; // Повертаємо успішний результат } +// Функція для декомпресії за допомогою Хаффмана int decompress_1(const char* input_file_name, const char* output_file_name) { - // Реалізація декомпресії за допомогою Хаффмана буде складною - // і потребує зберігання дерев або довжини кодування кожного символу - return 0; + // Декомпресія за допомогою Хаффмана потребує відновлення дерева та розшифровки бітових кодів + return 0; // Не реалізовано повністю }