Update sk1/compressor.c
This commit is contained in:
parent
dea7942391
commit
3935a5851e
149
sk1/compressor.c
149
sk1/compressor.c
@ -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]]++;
|
||||
}
|
||||
|
||||
HuffmanSymbol symbols[256];
|
||||
size_t num_symbols = 0;
|
||||
// Створюємо дерево Хаффмана
|
||||
Node* root = create_huffman_tree(data, file_size);
|
||||
|
||||
// Генерація кодів Хаффмана
|
||||
HuffmanCode codes[256];
|
||||
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++;
|
||||
codes[i].code = NULL;
|
||||
}
|
||||
|
||||
char current_code[256];
|
||||
generate_huffman_codes(root, codes, current_code, 0);
|
||||
|
||||
// Стиснення даних
|
||||
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; // Не реалізовано повністю
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user