Update sk1/compressor.c

This commit is contained in:
Yurii Chechur 2024-12-24 18:41:40 +00:00
parent dea7942391
commit 3935a5851e

View File

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