path-packer-c/huffman.c

156 lines
2.8 KiB
C

#include "huffman.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static int
find_smallest (struct huffman_node **nodes, int count, int different)
{
int smallest;
int i;
for (i = 0; nodes[i]->weight == -1; i++);
if (i == different) {
for (i++; nodes[i]->weight == -1; i++);
}
smallest = i;
for (i = smallest + 1; i < count; i++) {
if (i == different || nodes[i]->weight == -1) {
continue;
}
if (nodes[i]->weight < nodes[smallest]->weight) {
smallest = i;
}
}
return smallest;
}
struct huffman_node *
huffman_build_tree(void **values, int count)
{
int i;
struct huffman_node **nodes;
nodes = malloc (sizeof (struct huffman_node *) * count);
for (i = 0; i < count; i++) {
struct huffman_node *node =
malloc (sizeof (struct huffman_node));
node->value = values[i];
node->weight = i + 1;
node->left = NULL;
node->right = NULL;
nodes[i] = node;
}
int tree1;
int tree2;
for (i = 1; i < count; i++) {
struct huffman_node *tmp;
tree1 = find_smallest (nodes, count, -1);
tree2 = find_smallest (nodes, count, tree1);
tmp = nodes[tree1];
nodes[tree1] = malloc (sizeof (struct huffman_node));
nodes[tree1]->weight = tmp->weight + nodes[tree2]->weight;
nodes[tree1]->value = NULL;
nodes[tree1]->left = tmp;
nodes[tree1]->right = nodes[tree2];
nodes[tree2]->weight = -1;
}
return nodes[tree1];
}
void *
huffman_lookup (struct huffman_node *tree, unsigned char *bits, int *bits_read,
bool print)
{
struct huffman_node *node = tree;
while (true) {
if (node == NULL) {
return NULL;
}
if (node->value != NULL) {
return node->value;
}
if ((bits[0] << *bits_read % 8 & 0x80) == 0) {
node = node->left;
if (print) {
putchar ('0');
}
} else {
node = node->right;
if (print) {
putchar ('1');
}
}
(*bits_read)++;
if (*bits_read % 8 == 0) {
bits++;
}
}
}
struct stack {
struct stack *next;
bool val;
};
static void
huffman_lookup_driver (struct huffman_node *tree, void *value,
struct stack *head, struct stack *cur)
{
if (tree->value == value) {
struct stack *x = head->next;
while (x != NULL) {
if (x->val) {
putchar ('1');
} else {
putchar ('0');
}
x = x->next;
}
return;
}
struct stack *next = malloc (sizeof (struct stack));
next->next = NULL;
cur->next = next;
if (tree->left != NULL) {
next->val = false;
huffman_lookup_driver (tree->left, value, head, next);
}
if (tree->right != NULL) {
next->val = true;
huffman_lookup_driver (tree->right, value, head, next);
}
cur->next = NULL;
free (next);
}
// given a value, print its code to stdout.
void
huffman_reverse_lookup (struct huffman_node *tree, void *value)
{
struct stack head;
head.next = NULL;
huffman_lookup_driver (tree, value, &head, &head);
}