-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhuffstuff.c
202 lines (190 loc) · 4.97 KB
/
huffstuff.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#include "huffstuff.h"
/*takes frequency so it doesn't depend on a file pointer
input which isn't used by hencode or hdecode,
returns the ordered node list with their codes */
huffnode **allhuff(int freqlist[]) {
huffnode **nodelist;
int size = 0;
/* 2 so easy to distinguish errors */
char codes[ASCIIVALS] = {'2'};
int i;
huffnode *tempnode;
huffnode *huffll;
nodelist = calloc(ASCIIVALS, sizeof(huffnode *));
if (nodelist == NULL) {
perror("Nodelist calloc failed");
exit(3);
}
/* creates list of huffnodes */
for (i = 0; i < ASCIIVALS; i++) {
if (freqlist[i] != 0) {
tempnode = malloc(sizeof(huffnode));
if (tempnode == NULL) {
perror("Tempnode malloc failed");
exit(3);
}
tempnode->freq = freqlist[i];
tempnode->char_val = i;
tempnode->left = NULL;
tempnode->right = NULL;
nodelist[size] = tempnode;
size++;
}
}
/* empty case */
if (nodelist[0] == NULL) {
fprintf(stderr, "empty input");
return 0;
}
/* resize nodelist down to size */
nodelist = realloc(nodelist, size*sizeof(huffnode *));
if (nodelist == NULL) {
perror("Nodelist realloc failed");
exit(3);
}
/* sort nodelist */
qsort(nodelist, size, sizeof(huffnode *), comp);
/* convert list into a linked list */
for (i = 0; i < size - 1; i++) {
nodelist[i]->next = nodelist[i + 1];
}
nodelist[size - 1]->next = NULL;
/* build tree */
huffll = build_tree(nodelist, size);
/* make codes */
if (huffll != NULL) {
create_codes(huffll, codes, 0);
}
/* re-sort nodelist by ascii value */
qsort(nodelist, size, sizeof(huffnode *), comp2);
/*need a way to pass size back */
nodelist[0]->size = size;
return nodelist;
}
/* takes in a huffnode and a list and inserts the node
to the correct spot in the list by increasing frequency,
tie-breaking by the newest node first */
huffnode *insert(huffnode *list, huffnode *item) {
huffnode *cur;
huffnode *prev;
/* check if last item */
if (list == NULL) {
return item;
}
cur = list->next;
prev = list;
/* check for insert at 0 */
if (prev->freq >= item->freq) {
item->next = prev;
return item;
}
/* general insert */
while (cur != NULL) {
if (cur->freq >= item->freq) {
prev->next = item;
item->next = cur;
return list;
}
prev = cur;
cur = cur->next;
}
/* insert at end */
prev->next = item;
item->next = NULL;
return list;
}
/* takes two huffnodes and combines them into a parent node
with the input nodes as children and freqency as the sum
of the children nodes' frequencies*/
huffnode *combine(huffnode *a, huffnode *b) {
unsigned char char_val;
huffnode *node = malloc(sizeof(huffnode));
if (node == NULL) {
perror("Combine malloc failed");
exit(3);
}
if (a->char_val < b->char_val) {
char_val = a->char_val;
} else {
char_val = b->char_val;
}
/* include char val for debugging purposes */
node->char_val = char_val;
node->freq = a->freq + b->freq;
node->left = a;
node->right = b;
return node;
}
/* compares two huffnodes by frequency then by ascii val,
returns the lesser for both cases */
int comp(const void *a, const void *b) {
huffnode **node1 = (huffnode **)a;
huffnode **node2 = (huffnode **)b;
if ((*node1)->freq != (*node2)->freq) {
return ((*node1)->freq - (*node2)->freq);
} else {
return ((*node1)->char_val - (*node2)->char_val);
}
}
/* compares two huffnoes by ascii val, returns lesser */
int comp2(const void *a, const void *b) {
huffnode **node1 = (huffnode **)a;
huffnode **node2 = (huffnode **)b;
return ((*node1)->char_val - (*node2)->char_val);
}
/* Recursively creates codes for each nodes in the tree,
left is 0, right is 1 */
void create_codes(huffnode *node, char codes[], int i) {
char *code;
int j;
if (node != NULL) {
if (node->left == NULL && node->right == NULL) {
codes[i] = '\0';
code = malloc(i + 1);
if (code == NULL) {
perror("Code malloc failed");
exit(3);
}
for (j = 0; j < (i + 1); j++) {
code[j] = codes[j];
}
node->code = code;
}
if (node->left != NULL) {
codes[i] = '0';
create_codes(node->left, codes, i + 1);
}
if (node->right != NULL) {
codes[i] = '1';
create_codes(node->right, codes, i + 1);
}
}
}
char **codelist(huffnode **nodelist) {
int size = nodelist[0]->size;
int i;
char **codelist = calloc(ASCIIVALS, sizeof(char *));
if (codelist == NULL) {
perror("Codelist calloc failed");
exit(3);
}
for (i = 0; i < size; i++) {
codelist[nodelist[i]->char_val] = nodelist[i]->code;
}
return codelist;
}
/* builds huffman tree, returns head of tree */
huffnode *build_tree(huffnode **nodelist, int size) {
huffnode *huffll;
huffnode *tempnode;
int i = size;
huffll = nodelist[0];
while (i > 1) {
tempnode = combine(huffll, huffll->next);
huffll = huffll->next->next;
/* insert into huffll */
huffll = insert(huffll, tempnode);
i--;
}
return huffll;
}