Skip to content

your_huffman_code.h

#ifndef HUFFMAN_YOUR_HUFFMAN_CODE_H  
#define HUFFMAN_YOUR_HUFFMAN_CODE_H  

#include <map>  
#include "huffman_helper.h"  
using namespace std;  

struct TreeNode {  
    char ch;  
    int weight;  
    TreeNode *left;  
    TreeNode *right;  
};  
struct CompareTreeNode  
{  
    bool operator()(const TreeNode* lhs, const TreeNode* rhs) const  
    {  
        return lhs->weight > rhs->weight;  
    }  
};  
/* You need the unusual CompareTreeNode struct above if you want to make  
 * a priority queue of TreeNodes.  (Hint: You do!)  This struct defines an * operator for comparing TreeNode*, which makes it possible for the * underlying heap for a priority queue to work correctly.  It's weird, * but here's the syntax you'll need:       priority_queue<TreeNode*, vector<TreeNode*>, CompareTreeNode> pq; * The first parameter describes what it is a priority queue of, the * second parameter describes the underlying heap implementation ("I'm * using a vector for this heap"), and the third parameter specifies a * way to compare TreeNode*.  Phew... */  
// NOTE: The struct EncodedData is defined in the huffman_helper.h file  

void destroyTree(TreeNode* root){  
    if(root == nullptr) return;  
    destroyTree(root->left);  
    destroyTree(root->right);  
    delete root;  
}  

void recursivePaths(TreeNode* root, map<char, queue<Bit>>& paths, queue<Bit> currPath){  
    if(root->left == nullptr && root->right == nullptr){  
        paths[root->ch] = currPath;  
        return;  
    }  
    if(root->left != nullptr){  
        queue<Bit> leftPath = currPath;  
        leftPath.push(0);  
        recursivePaths(root->left, paths, leftPath);  
    }  
    if(root->right != nullptr){  
        queue<Bit> rightPath = currPath;  
        rightPath.push(1);  
        recursivePaths(root->right, paths, rightPath);  
    }  
}  

void populateShapeAndLeaves(EncodedData &data, TreeNode* root){  
    if(root->left == nullptr && root->right == nullptr){  
        data.treeShape.push(0);  
        data.treeLeaves.push(root->ch);  
        return;  
    } else {  
        data.treeShape.push(1);  
        populateShapeAndLeaves(data, root->left);  
        populateShapeAndLeaves(data, root->right);  
    }  
}  

void huffmanAlgo(priority_queue<TreeNode*, vector<TreeNode*>, CompareTreeNode> &pq){  
    while(pq.size() > 1){  
        TreeNode* left = pq.top();  
        pq.pop();  
        TreeNode* right = pq.top();  
        pq.pop();  
        TreeNode* parent = new TreeNode();  
        parent->left = left;  
        parent->right = right;  
        parent->weight = left->weight + right->weight;  
        pq.push(parent);  
    }  
}  

EncodedData createEncodedData(map<char, queue<Bit>> &code, const string &text, TreeNode* &root){  
    queue<Bit> encoded;  
    for(char ch : text){  
        queue<Bit> q = code[ch];  
        while(!q.empty()){  
            encoded.push(q.front());  
            q.pop();  
        }  
    }  

    EncodedData data;  
    data.messageBits = encoded;  
    populateShapeAndLeaves(data, root);  
    destroyTree(root);  
    return data;  
}  

priority_queue<TreeNode *, vector<TreeNode *>, CompareTreeNode> getPriorityQueue(map<char, int> &freq) {  
    priority_queue<TreeNode*, vector<TreeNode*>, CompareTreeNode> pq;  

    for (auto it = freq.begin(); it != freq.end(); it++) {  
        TreeNode* node = new TreeNode();  
        node->ch = it->first;  
        node->weight = it->second;  
        pq.push(node);  
    }  
    return pq;  
}  

map<char, int> getFreqMap(const string &text) {  
    map<char, int> freq;  
    for (char ch : text)  
        freq[ch]++;  
    return freq;  
}  

EncodedData compress(const string &text) {  
    map<char, int> freq = getFreqMap(text);  

    priority_queue<TreeNode *, vector<TreeNode *>, CompareTreeNode> pq = getPriorityQueue(freq);  

    huffmanAlgo(pq);  

    TreeNode* root = pq.top();  
    map<char, queue<Bit>> code;  
    recursivePaths(root, code, queue<Bit>());  

    return createEncodedData(code, text, root);  
}  



TreeNode* treeBuildingHelper(EncodedData& data){  
    if(data.treeLeaves.empty()) return nullptr;  

    TreeNode* root = new TreeNode;  
    if(data.treeShape.front() == 0) {  
        data.treeShape.pop();  
        root->ch = data.treeLeaves.front();  
        root->left = nullptr;  
        root->right = nullptr;  
        data.treeLeaves.pop();  
    } else {  
        data.treeShape.pop();  
        root->left = treeBuildingHelper(data);  
        root->right = treeBuildingHelper(data);  
    }  
    return root;  
}  

string decompress(EncodedData& data) {  
    //build huffman tree  
    TreeNode* root = treeBuildingHelper(data);  
    string result = "";  

    //cout << "size : " << size(root) << endl;  
    while(!data.messageBits.empty()){  
        TreeNode* cur = root;  
        while(cur->left != nullptr && cur->right != nullptr){  
            if(data.messageBits.front() == 0)  
                cur = cur->left;  
            else  
                cur = cur->right;  
            data.messageBits.pop();  
        }  
        result += cur->ch;  
    }  
    return result;  
}
#endif //HUFFMAN_YOUR_HUFFMAN_CODE_H