-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHuffmanTree.cpp
More file actions
157 lines (133 loc) · 5.44 KB
/
HuffmanTree.cpp
File metadata and controls
157 lines (133 loc) · 5.44 KB
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
/*Daud Ahmad Nisar (U37366522) & Adesh Kessani (U69434322)
This code implements Huffman coding for lossless data compression and decompression,
including functions for building a Huffman tree, generating compressed binary output,
serializing the tree, and reconstructing the tree for decompression.*/
#include "HuffmanTree.hpp"
#include <map>
#include <iostream>
#include <stack>
std::string HuffmanTree::compress(const std::string inputStr) {
std::map<char, size_t> charMap;
std::map<char, size_t>::iterator it;
size_t count[256] = {0};
//counting frequency of charaacters in input string
for (int i = 0; inputStr[i] != '\0'; i++) {
count[inputStr[i]]++;
}
for (int i = 0; i < 256; i++) {
if (count[i] != 0) {
charMap.insert(std::pair<char, size_t>((char)i, count[i]));
}
}
//create heap priority queue and populate it
HeapQueue<HuffmanNode*, HuffmanNode::Compare> PQ;
for (it = charMap.begin(); it != charMap.end(); ++it) {
HuffmanNode* node = new HuffmanNode(it->first, it->second);
PQ.insert(node);
}
//huffman tree creation from PQ
while (PQ.size() != 1) {
HuffmanNode* node1 = PQ.min();
PQ.removeMin();
HuffmanNode* node2 = PQ.min();
PQ.removeMin();
size_t frequencyT = (node1->getFrequency() + node2->getFrequency());
HuffmanNode* parentN1N2 = new HuffmanNode('\0', frequencyT, nullptr, node1, node2);
node1->parent = parentN1N2;
node2->parent = parentN1N2;
PQ.insert(parentN1N2);
}
root = PQ.min();
//encoding of each character in the string
std::map<char, std::string> codeMap;
std::string code = "";
std::string output = "";
//finding the Huffman codes for each character
for (it = charMap.begin(); it != charMap.end(); ++it) {
findCode(PQ.min(), codeMap, code);
}
//construct the compressed output
for (auto i : inputStr) {
output += codeMap[i];
}
return output;
}
//tree serialization
std::string HuffmanTree::serializeTree() const {
if (root == nullptr) {
return "";
}
std::string output = "";
serialize(root, output);
return output;
}
//tree decompression
std::string HuffmanTree::decompress(const std::string inputCode, const std::string serializedTree) {
std::string output = "";
size_t len = serializedTree.length();
std::stack<HuffmanNode*> treeStack;
std::cout << "Decompressing... Start reconstructing tree from serialized string." << std::endl;
//reconstruct the tree from serializedTree
for (size_t i = 0; i < len; ++i) {
char character = serializedTree[i];
std::cout << "Processing character: " << character << std::endl;
if (character == 'L') {
if (i + 1 < len) {
char leafValue = serializedTree[++i]; //increment to get the next character as the leaf value
HuffmanNode* huffNode = new HuffmanNode(leafValue, 0);
treeStack.push(huffNode);
std::cout << "Created Leaf Node: " << leafValue << std::endl;
}
} else if (character == 'B') {
if (treeStack.size() < 2) {
std::cout << "Error: Insufficient nodes in stack, cannot process 'B'." << std::endl;
return ""; //return empty if the tree is invalid
}
HuffmanNode* right = treeStack.top();
treeStack.pop();
HuffmanNode* left = treeStack.top();
treeStack.pop();
HuffmanNode* branch = new HuffmanNode('\0', 0, nullptr, left, right);
treeStack.push(branch);
right->parent = branch;
left->parent = branch;
std::cout << "Created Branch Node: Left (" << left->getCharacter() << "), Right (" << right->getCharacter() << ")" << std::endl;
}
}
//copy the remaining stack to be the root of the newly constructed Huffman Tree
if (treeStack.empty()) {
std::cout << "Error: Tree reconstruction failed. Stack is empty." << std::endl;
return ""; // prevent accessing invalid memory
}
HuffmanNode* root = treeStack.top();
treeStack.pop();
std::cout << "Reconstructed root node." << std::endl;
//reconstructing the text from the code using the built Huffman tree
HuffmanNode* curr = root;
for (auto character : inputCode) {
std::cout << "Processing code: " << character << std::endl;
if (character == '0') {
if (curr->left != nullptr) {
curr = curr->left;
} else {
std::cout << "Error: Left child is null. Stopping." << std::endl;
break; //prevent null pointer access if left child is null
}
} else if (character == '1') {
if (curr->right != nullptr) {
curr = curr->right;
} else {
std::cout << "Error: Right child is null. Stopping." << std::endl;
break; //prevent null pointer access if right child is null
}
}
//once we hit the leaf add the char to output, start over from the root
if (curr->isLeaf()) {
output += curr->getCharacter();
std::cout << "Added character to output: " << curr->getCharacter() << std::endl;
curr = root; //reset to root for the next character
}
}
std::cout << "Decompression complete. Output: " << output << std::endl;
return output;
}