Skip to content

Commit c5f65b1

Browse files
committed
Use Huffman tree to encode and decode
encode and decode with huffman tree, using BitMap, HashTable, etc.
1 parent b954191 commit c5f65b1

12 files changed

+307
-10
lines changed

src/bitmap.c

+44-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ BitMap *bitmap_new(unsigned int num_bits)
4242
{
4343
BitMap *bitmap = (BitMap *)malloc(sizeof(BitMap));
4444
bitmap->num_bits = num_bits;
45-
if (num_bits % BITS_PER_WORD == 0) {
45+
if (num_bits != 0 && (num_bits % BITS_PER_WORD) == 0) {
4646
bitmap->num_words = num_bits / BITS_PER_WORD;
4747
} else {
4848
bitmap->num_words = num_bits / BITS_PER_WORD + 1;
@@ -51,6 +51,16 @@ BitMap *bitmap_new(unsigned int num_bits)
5151
return bitmap;
5252
}
5353

54+
BitMap *bitmap_clone(const BitMap *bitmap)
55+
{
56+
BitMap *clone = (BitMap *)malloc(sizeof(BitMap));
57+
clone->num_bits = bitmap->num_bits;
58+
clone->num_words = bitmap->num_words;
59+
clone->words = (word_t *)malloc(sizeof(word_t) * bitmap->num_words);
60+
memcpy(clone->words, bitmap->words, sizeof(word_t) * bitmap->num_words);
61+
return clone;
62+
}
63+
5464
void bitmap_free(BitMap *bitmap)
5565
{
5666
free(bitmap->words);
@@ -112,3 +122,36 @@ unsigned int bitmap_count(const BitMap *bitmap)
112122
}
113123
return count;
114124
}
125+
126+
BitMap *bitmap_append(BitMap *bitmap, int flag)
127+
{
128+
if (bitmap->num_words * BITS_PER_WORD <= bitmap->num_bits) {
129+
++(bitmap->num_words);
130+
bitmap->words =
131+
(word_t *)realloc(bitmap, sizeof(word_t) * bitmap->num_words);
132+
}
133+
134+
if (flag) {
135+
set_bit(bitmap->words, bitmap->num_bits);
136+
} else {
137+
clear_bit(bitmap->words, bitmap->num_bits);
138+
}
139+
140+
++(bitmap->num_bits);
141+
return bitmap;
142+
}
143+
144+
// BitMap *bitmap_concat(BitMap *bitmap, const BitMap *other) {
145+
// return bitmap;
146+
// }
147+
148+
char *bitmap_to_string(BitMap *bitmap)
149+
{
150+
char *string = (char *)malloc(sizeof(char) * (bitmap->num_bits + 1));
151+
for (unsigned int i = 0; i < bitmap->num_bits; ++i) {
152+
int flag = bitmap_get(bitmap, i);
153+
string[i] = '0' + flag;
154+
}
155+
string[bitmap->num_bits] = '\0';
156+
return string;
157+
}

src/bitmap.h

+34
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ typedef struct _BitMap {
9191
*/
9292
BitMap *bitmap_new(unsigned int num_bits);
9393

94+
/**
95+
* @brief Clone a BitMap and return it's clone.
96+
*
97+
* @param bitmap The BitMap.
98+
* @return BitMap* The clone.
99+
*/
100+
BitMap *bitmap_clone(const BitMap *bitmap);
101+
94102
/**
95103
* @brief Delete a BitMap and free back memory.
96104
*
@@ -169,4 +177,30 @@ void bitmap_xor(BitMap *bitmap, const BitMap *other);
169177
*/
170178
unsigned int bitmap_count(const BitMap *bitmap);
171179

180+
/**
181+
* @brief Append a bit (0 or 1) to a BitMap.
182+
*
183+
* @param bitmap The BitMap.
184+
* @param flag Bit flag 0 or 1 append to the BitMap.
185+
* @return BitMap* The BitMap.
186+
*/
187+
BitMap *bitmap_append(BitMap *bitmap, int flag);
188+
189+
/**
190+
* @brief Concat another BitMap to a BitMap.
191+
*
192+
* @param bitmap The BitMap.
193+
* @param other The BitMap.
194+
* @return BitMap* The concated BitMap.
195+
*/
196+
BitMap *bitmap_concat(BitMap *bitmap, const BitMap *other);
197+
198+
/**
199+
* @brief Convert a BitMap to a printable string.
200+
*
201+
* @param bitmap The BitMap.
202+
* @return char* The char string. (Need free by caller.)
203+
*/
204+
char *bitmap_to_string(BitMap *bitmap);
205+
172206
#endif /* #ifndef RETHINK_C_BITMAP_H */

src/dup.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,19 @@
99
*/
1010

1111
#include "dup.h"
12-
#include "def.h"
1312
#include <stdlib.h>
13+
#include "def.h"
1414

1515
int *intdup(int value)
1616
{
1717
int *dup = (int *)malloc(sizeof(int));
1818
*dup = value;
1919
return dup;
2020
}
21+
22+
char *char_dup(char value)
23+
{
24+
char *dup = (char *)malloc(sizeof(char));
25+
*dup = value;
26+
return dup;
27+
}

src/dup.h

+8
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,12 @@
2424
*/
2525
int *intdup(int value);
2626

27+
/**
28+
* @brief Duplicate a char and return it's pointer.
29+
*
30+
* @param value The original value.
31+
* @return int* The pointer.
32+
*/
33+
char *char_dup(char value);
34+
2735
#endif /* #ifndef RETHINK_C_DUP_H */

src/hash.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
unsigned int hash_char(void *pointer)
1616
{
17-
return *(unsigned int *)pointer;
17+
return *(unsigned char *)pointer;
1818
}
1919

2020
unsigned int hash_int(void *pointer)

src/huffman.c

+91-4
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@
99
*/
1010

1111
#include "huffman.h"
12+
#include "compare.h"
1213
#include "def.h"
14+
#include "hash.h"
15+
#include "hash_table.h"
1316

14-
static inline int huffman_node_compare(HuffmanNode *node1,
15-
HuffmanNode *node2)
17+
static inline int huffman_node_compare(HuffmanNode *node1, HuffmanNode *node2)
1618
{
17-
if (node1->weight > node2->weight) {
19+
if (node1->weight < node2->weight) {
1820
return -1;
1921
} else if (node1->weight > node2->weight) {
2022
return 1;
@@ -57,7 +59,7 @@ static inline HuffmanNode *huffman_heap_pop(Heap *heap)
5759
HuffmanTree *huffman_tree_new(Heap *heap)
5860
{
5961
HuffmanTree *tree = (HuffmanTree *)malloc(sizeof(HuffmanTree));
60-
62+
6163
HuffmanNode *node1 = NULL;
6264
HuffmanNode *node2 = NULL;
6365

@@ -71,6 +73,7 @@ HuffmanTree *huffman_tree_new(Heap *heap)
7173

7274
unsigned int weight = node1->weight + node2->weight;
7375
HuffmanNode *node = huffman_node_new('\0', weight);
76+
heap_insert(heap, node);
7477

7578
if (node1->weight < node2->weight) {
7679
node->left = node1;
@@ -102,3 +105,87 @@ void huffman_tree_free(HuffmanTree *tree)
102105
huffman_tree_postorder_free(tree->root);
103106
free(tree);
104107
}
108+
109+
static inline huffman_node_is_leave(HuffmanNode *node)
110+
{
111+
return node->left == NULL && node->right == NULL;
112+
}
113+
114+
static void huffman_tree_postorder_to_hash_table(HuffmanNode *node,
115+
HashTable *hash_table,
116+
BitMap *bitmap)
117+
{
118+
if (node == NULL) {
119+
return;
120+
}
121+
122+
if (node->left != NULL) {
123+
BitMap *left_bitmap = bitmap_clone(bitmap);
124+
bitmap_append(left_bitmap, 0);
125+
huffman_tree_postorder_to_hash_table(
126+
node->left, hash_table, left_bitmap);
127+
}
128+
129+
if (node->right != NULL) {
130+
BitMap *right_bitmap = bitmap_clone(bitmap);
131+
bitmap_append(right_bitmap, 1);
132+
huffman_tree_postorder_to_hash_table(
133+
node->right, hash_table, right_bitmap);
134+
}
135+
136+
if (huffman_node_is_leave(node)) {
137+
// todo: char_dup is not valid here.!!!
138+
char *ch = (char *)malloc(sizeof(char));
139+
*ch = node->value;
140+
hash_table_insert(hash_table, ch, bitmap);
141+
} else {
142+
bitmap_free(bitmap);
143+
}
144+
}
145+
146+
static HashTable *huffman_tree_to_hash_table(HuffmanTree *tree)
147+
{
148+
/** key: char, value: bitmap */
149+
HashTable *hash_table =
150+
hash_table_new(hash_char, char_equal, free, bitmap_free);
151+
HuffmanNode *node = tree->root;
152+
BitMap *bitmap = bitmap_new(0);
153+
huffman_tree_postorder_to_hash_table(tree->root, hash_table, bitmap);
154+
return hash_table;
155+
}
156+
157+
BitMap *huffman_encode(HuffmanTree *tree, Text *text)
158+
{
159+
/** key: char, value: bitmap */
160+
HashTable *hash_table = huffman_tree_to_hash_table(tree);
161+
BitMap *bitmap = bitmap_new(0);
162+
163+
for (unsigned int i = 0; i < text_length(text); ++i) {
164+
char ch = text_char_at(text, i);
165+
BitMap *bits = (BitMap *)hash_table_get(hash_table, &ch);
166+
for (unsigned int j = 0; j < bits->num_bits; ++j) {
167+
bitmap_append(bitmap, bitmap_get(bits, j));
168+
}
169+
}
170+
hash_table_free(hash_table);
171+
return bitmap;
172+
}
173+
174+
Text *huffman_decode(HuffmanTree *tree, BitMap *code)
175+
{
176+
Text *text = text_new();
177+
HuffmanNode *node = tree->root;
178+
for (unsigned int i = 0; i < code->num_bits; ++i) {
179+
if (bitmap_get(code, i)) {
180+
node = node->right;
181+
} else {
182+
node = node->left;
183+
}
184+
185+
if (huffman_node_is_leave(node)) {
186+
text_append(text, node->value);
187+
node = tree->root;
188+
}
189+
}
190+
return text;
191+
}

src/huffman.h

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define RETHINK_C_HUFFMAN_H
1919

2020
#include "heap.h"
21+
#include "bitmap.h"
22+
#include "text.h"
2123

2224
/**
2325
* @brief Definition of a @ref HuffmanNode.
@@ -80,4 +82,7 @@ HuffmanTree *huffman_tree_new(Heap *heap);
8082
*/
8183
void huffman_tree_free(HuffmanTree *tree);
8284

85+
BitMap *huffman_encode(HuffmanTree *tree, Text *text);
86+
Text *huffman_decode(HuffmanTree *tree, BitMap *code);
87+
8388
#endif /* #ifndef RETHINK_C_HUFFMAN_H */

src/text.c

+15-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
/**
1717
* @brief All ways append '\0' to text, for dapat c string.
18-
*
18+
*
1919
*/
2020

2121
/**
@@ -30,7 +30,7 @@ struct _Text {
3030

3131
static inline Text *text_new_with_size(unsigned int size)
3232
{
33-
Text *text= (Text *)malloc(sizeof(Text));
33+
Text *text = (Text *)malloc(sizeof(Text));
3434
text->_allocated = size;
3535
text->length = 0;
3636
text->data = (char *)malloc(text->_allocated * sizeof(char));
@@ -118,3 +118,16 @@ int text_equal(const Text *text1, const Text *text2)
118118
{
119119
return text_compare(text1, text2) == 0;
120120
}
121+
122+
Text *text_append(Text *text, char ch)
123+
{
124+
if ((text->length + 1) >= text->_allocated) {
125+
text->_allocated += 16;
126+
text->data = (char *)realloc(text->data, text->_allocated);
127+
}
128+
129+
text->data[text->length] = ch;
130+
++(text->length);
131+
text->data[text->length] = '\0';
132+
return text;
133+
}

src/text.h

+9
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,13 @@ int text_compare(const Text *text1, const Text *text2);
110110
*/
111111
int text_equal(const Text *text1, const Text *text2);
112112

113+
/**
114+
* @brief Append a charactor to a Text.
115+
*
116+
* @param text The Text.
117+
* @param ch The charactor.
118+
* @return Text* The appended Text.
119+
*/
120+
Text *text_append(Text *text, char ch);
121+
113122
#endif /* #ifndef RETHINK_C_TEXT_H */

test/CMakeLists.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_library(testcases alloc-testing.c test_helper.c test_arraylist.c test_list.c
22
test_queue.c test_bitmap.c test_matrix.c
33
test_bstree.c test_avltree.c test_rbtree.c test_heap.c
44
test_bignum.c test_dijkstra.c test_prime.c test_hash_table.c
5-
test_kmp.c test_bm.c test_sunday.c test_trie.c test_ac.c test_text.c)
5+
test_kmp.c test_bm.c test_sunday.c test_trie.c test_ac.c test_text.c
6+
test_huffman.c)
67
target_compile_options(testcases PRIVATE ${COMPILE_OPTIONS})
78
target_include_directories(testcases PRIVATE ${INCLUDE_DIRECTORIES})

0 commit comments

Comments
 (0)