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;
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; // Не реалізовано повністю
}