I decided to take up learning c++ recently, so I coded a Huffman compression algorithm. I'm particularly interested in critique of my c++ techniques (pointers, references, best practices, etc), but I am open to any comments you have.
Thanks for you time!
#include <map>
#include <iostream>
#include <vector>
#include <deque>
#include <string>
#include <algorithm>
typedef std::pair<char, int> weight_pair;
struct node {
int weight;
node *parent = NULL;
node *children[2] = {NULL, NULL};
std::string content;
};
bool compareNodeWeights(const node *node1, const node *node2) {
return (node1 -> weight) < (node2 -> weight);
}
//builds a binary tree from an alphabet and an associated set of weights
node *build_tree(const std::map<char, int> &weights){
std::deque<node*> nodes;
for (auto const &x : weights) {
node *leaf_node = new node;
leaf_node -> weight = x.second;
leaf_node -> content = std::string(1, x.first);
nodes.push_back(leaf_node);
}
while (nodes.size() > 1) {
std::sort(nodes.begin(), nodes.end(), compareNodeWeights);
node* new_node = new node;
new_node -> weight = nodes[0] -> weight + nodes[1] -> weight;
new_node -> content = nodes[0] -> content + nodes[1] -> content;
nodes[0] -> parent = new_node;
nodes[1] -> parent = new_node;
new_node -> children[0] = nodes[0];
new_node -> children[1] = nodes[1];
nodes.erase(nodes.begin());
nodes.erase(nodes.begin());
nodes.push_back(new_node);
}
return nodes[0];
}
//traverses the tree to find the prefix code for a given leaf node in a tree
std::deque<bool> find_prefix_code(const node *leaf) {
std::deque<bool> result;
const node *curr_node = leaf;
while (curr_node -> parent != NULL) {
if (curr_node -> parent -> children[0] -> content == curr_node -> content) {
result.push_front(0);
}
else {
result.push_front(1);
}
curr_node = curr_node -> parent;
}
return result;
}
std::vector<bool> compress(const std::string &message, const node *tree) {
std::vector<bool> result;
std::vector<const node*> open;
open.push_back(tree);
std::map<char, std::deque<bool>> prefix_codes;
while (open.size() > 0) {
const node* curr_node = open[0];
if (curr_node -> content.size() == 1){
prefix_codes.insert( std::pair<char, std::deque<bool>>(curr_node -> content[0], find_prefix_code(curr_node)) );
}
else {
open.push_back(curr_node -> children[0]);
open.push_back(curr_node -> children[1]);
}
open.erase(open.begin());
}
for (const char c : message) {
for (const bool &b : prefix_codes[c]) {
result.push_back(b);
}
}
return result;
}
std::string decompress(const std::vector<bool> &data, const node *tree) {
const node *curr_node = tree;
std::string result = "";
for (const bool b : data) {
int direction = b;
curr_node = curr_node -> children[direction];
if (curr_node ->content.size() == 1) {
result += curr_node -> content;
curr_node = tree;
}
}
return result;
}
void print_compressed(const std::vector<bool> &data) {
std::cout << "Compressed data: ";
for (const bool b : data) {
std::cout << b;
}
std::cout << std::endl;
}
void delete_tree(node *tree) {
for (int i = 0; i <= 1; i++) {
if (tree -> children[i] != NULL) {
delete_tree(tree -> children[i]);
}
}
delete tree;
}
int main() {
std::map<char, int> weights;
weights.insert(weight_pair(' ', 3));
weights.insert(weight_pair('a', 3));
weights.insert(weight_pair('d', 3));
weights.insert(weight_pair('b', 1));
weights.insert(weight_pair('c', 1));
node *tree = build_tree(weights);
std::vector<bool> compressed_message = compress("a cab dab bad", tree);
print_compressed(compressed_message);
std::string message = decompress(compressed_message, tree);
std::cout << "Decompressed data: " << message << std::endl;
delete_tree(tree);
return 0;
}
for
loop. \$\endgroup\$