I'm currently writing a Huffman compressor for educational purposes.

I want it to compress/decompress files less then 5mb. The time limit is 5 seconds. 

Now it compresses a 5mb file in almost 8 seconds. The decompression speed is really awful. It requires almost 6 seconds on a file of the size approx 0.1mb.

The problem is in reading/writing. I can get all code tables in less than 1 second, but then writing subroutine works about 6 seconds on 5mb file.

How can I improve speed of compression/decompression?

**main.cpp** 


    #include <iostream>
    #include <bits/stdc++.h> 
    #include "huffman.h"
    #include "archiver.h"

    using namespace std::chrono;

    int main() {
         high_resolution_clock::time_point t1 = 
         high_resolution_clock::now();
         Archiver ar;

         //encoding

         /*

         std::map<char, int32_t> m;
         ar.createFreqTable("test.pdf", m);
         HuffmanTree t(m);
         std::ifstream ifs("test.pdf");
         std::ofstream ofs("test.out");
         ar.compress(ifs, ofs, &t);

         */

         //decoding

         // /*

         //test.out - 123 930 bytes
         HuffmanTree nt;
         std::ifstream ifs2("test.out");
         std::ofstream ofs2("result.pdf");
         ar.decompress(ifs2, ofs2, &nt);

         //*/

         high_resolution_clock::time_point t2 = high_resolution_clock::now();
         auto duration = duration_cast<milliseconds>( t2 - t1 ).count();
         std::cout << duration;  // 5349
         return 0;
     }

**archiver.h**

    #include "huffman.h"
    #include "bitstring.h"
    #ifndef HUFFMAN_ARCHIVER_H
    #define HUFFMAN_ARCHIVER_H

    class Archiver{
    private:
         std::map<std::vector <bool>, char> codes;

         std::map<char, std::vector<bool> > lookup;

    public:
         Archiver(){};

         void compress(std::ifstream&, std::ofstream&, HuffmanTree*);

         void decompress(std::ifstream&, std::ofstream&, HuffmanTree*);

         void encodeTree(BitStringWrite&, TreeNode*);

         TreeNode* decodeTree(BitStringRead&);

         void buildCodes(TreeNode*, std::vector<bool>);

         std::map<std::vector <bool>, char>& getCodes(){
             return codes;
         };

         std::map<char, int32_t>& createFreqTable(const std::string&, std::map<char, int32_t>&);

         void buildTable(TreeNode*);

         std::map<char, std::vector<bool> >& getTable(){
             return lookup;
         };

    };
    #endif //HUFFMAN_ARCHIVER_H



**archiver.cpp**

    #include "archiver.h"
    #include <fstream>
    #include <deque>

    std::map<char, int32_t>& Archiver::createFreqTable(const std::string &name, std::map<char, int32_t>& freq){
        std::ifstream file(name);
        int next = 0;

        while ((next = file.get()) != EOF) {
            char uc = static_cast <char> (next);
            std::map<char, int32_t>::iterator iter;
            iter = freq.find(uc);
            if (iter != freq.end())
                iter->second += 1;
            else
                freq[uc] = 1;
        }

        return freq;
     };

    void Archiver::encodeTree(BitStringWrite& bw, TreeNode* node){
        if (node -> isLeaf()) {
            bw.writeBit(1);
            bw.writeByte(node->getChar());
            return;
        }
        else {
            bw.writeBit(0);
            encodeTree(bw, node->getLeftTree());
            encodeTree(bw, node->getRightTree());
        }
    }

    TreeNode* Archiver::decodeTree(BitStringRead& br){
        if (br.readBit()) {
            return new TreeNode(br.readByte(), 0, true, NULL, NULL);
        }
        else {
            TreeNode* left = decodeTree(br);
            TreeNode* right = decodeTree(br);
            return new TreeNode(0, 0, false, left, right);
        }
    }

    void Archiver::buildCodes(TreeNode* n, std::vector<bool> cur) {
        if (n -> isLeaf()) {
            codes[cur] = n->getChar();
            return;
        }

        cur.push_back(0);
        buildCodes(n->getLeftTree(), cur);
        cur.pop_back();
        cur.push_back(1);
        buildCodes(n->getRightTree(), cur);

        return;
    }

    void Archiver::buildTable(TreeNode* root) {
        std::deque< std::pair<TreeNode *, std::vector<bool> > > q;
        q.push_back(make_pair(root, std::vector<bool>()));

        while (!q.empty()) {
            TreeNode *node, *lc, *rc;
            std::vector<bool> code;
            node = q.front().first;
            code = q.front().second;
            q.pop_front();
            lc = node->getLeftTree();
            rc = node->getRightTree();
            if (lc) {
                 std::vector<bool> code_cp(code);
                 q.push_back(make_pair(lc, (code.push_back(0), code)));
                 q.push_back(make_pair(rc, (code_cp.push_back(1), code_cp)));
            }
            else
                 lookup.insert(make_pair(node->getChar(), code));
            }
       }

    void Archiver::compress(std::ifstream &ifs, std::ofstream &ofs, HuffmanTree *tree) {
        ifs.clear();
        ifs.seekg(0, ifs.beg);
        BitStringRead br(ifs);
        BitStringWrite bw(ofs);
        buildTable(tree->getRoot());
        encodeTree(bw, tree -> getRoot());

        while(!ifs.eof()){
            br.readByte();
            int sz = getTable()[br.getByte()].size();
            std::vector<bool> out = getTable()[br.getByte()];
            for(int i = 0; i < sz; i++)
                bw.writeBit(out[i]);
        }
    }

    void Archiver::decompress(std::ifstream &ifs, std::ofstream &ofs, HuffmanTree *tree) {
        ifs.clear();
        ifs.seekg(0, ifs.beg);
        BitStringRead br(ifs);
        BitStringWrite bw(ofs);
        TreeNode* t = decodeTree(br);
        std::vector<bool> cur;
        buildCodes(t, cur);
        std::vector<bool> v;
        bool b = false;

        while(!ifs.eof()) {
             while (!(getCodes().count(v)) && !ifs.eof()) {
                  b = br.readBit();
                  v.push_back(b);
             }
            if (ifs.eof())
                break;
            char s = getCodes()[v];
            v.clear();
            bw.writeByte(s);
        }
    }


**huffman.h**

    #ifndef HUFFMAN_HUFFMAN_H
    #define HUFFMAN_HUFFMAN_H
    
    #include <sys/param.h>
    #include <iostream>
    #include <map>
    #include <vector>
    
    class TreeNode{
    public:
        TreeNode(char c, int cnt, bool l, TreeNode* lc, TreeNode* rc): character(c), count(cnt), is_leaf(l), left(lc), right(rc){};
    
        TreeNode(): character(0), count(0), is_leaf(false), left(NULL), right(NULL){}
    
        int getCount() const{
            return this -> count;
        };
    
        char getChar() const{
            return this -> character;
        };
    
        TreeNode* getLeftTree() const{
            return this -> left;
        };
    
        TreeNode* getRightTree() const{
            return this -> right;
        };
    
        void setLeftTree(TreeNode* n){
            this -> left = n;
        };
    
        void setRightTree(TreeNode* n){
            this -> right = n;
        };
    
        void setChar(char c){
            this -> character = c;
        };
    
        bool isLeaf(){
            return is_leaf;
        }
    
        void setLeaf(bool num){
            this->is_leaf = num;
        }
    
    private:
        char character;
        int count;
        bool is_leaf;
        TreeNode* left;
        TreeNode* right;
    };
    
    class HuffmanTree{
    public:
    
        HuffmanTree(std::map<char , int>&);
    
        HuffmanTree(){
            root = new TreeNode(0, 0, false, NULL, NULL);
        };
    
        ~HuffmanTree();
    
        TreeNode* getRoot() const{
            return this -> root;
        };
    
        class NodeComparator {
        public:
            bool operator()(const TreeNode *const lhs, const TreeNode *const rhs) {
                if (lhs->getCount() == rhs->getCount()) {
                    return lhs->getChar() > rhs->getChar();
                }
    
                return lhs->getCount() > rhs->getCount();
            }
        };
    
        TreeNode* merge(TreeNode* node1, TreeNode* node2);
        void recursiveNodeDelete(TreeNode* node);
       // uint32_t check_count(uint32_t count);
    
    private:
        TreeNode* root;
    };
    
    
    #endif //HUFFMAN_HUFFMAN_H


**huffman.cpp**


    #include "huffman.h"
    #include <sstream>
    #include <queue>
    using namespace std;
    
    HuffmanTree::HuffmanTree(std::map<char, int>& count_map) {
        if (count_map.empty()) {
            std::stringstream ss;
            ss << "Compressor requires a non-empty text.";
            throw std::runtime_error{ss.str()};
        }
    
        std::priority_queue<TreeNode*, std::vector<TreeNode*>, HuffmanTree::NodeComparator> queue;
    
        for(auto a : count_map)
            queue.push(new TreeNode(a.first, a.second, true, NULL, NULL));
    
        while (queue.size() > 1) {
            TreeNode* node1 = queue.top(); queue.pop();
            TreeNode* node2 = queue.top(); queue.pop();
            queue.push(merge(node1, node2));
        }
    
        root = queue.top(); queue.pop();
    }
    
    void HuffmanTree::recursiveNodeDelete(TreeNode* node) {
        if (node == NULL) {
            return;
        }
    
        recursiveNodeDelete(node->getLeftTree());
        recursiveNodeDelete(node->getRightTree());
    
        delete node;
    }
    
    HuffmanTree::~HuffmanTree() {
        recursiveNodeDelete(root);
    }
    
    TreeNode* HuffmanTree::merge(TreeNode* node1, TreeNode* node2) {
        TreeNode* new_node = new TreeNode(0, node1->getCount() + node2->getCount(), false, NULL, NULL);
    
        if (node1->getCount() < node2->getCount()) {
            new_node->setLeftTree(node1);
            new_node->setRightTree(node2);
        }
        else {
            new_node->setLeftTree(node2);
            new_node->setRightTree(node1);
        }
    
        new_node->setChar(std::max(node1->getChar(), node2->getChar()));
    
        return new_node;
    }


**bitstring.h**

    #ifndef HUFFMAN_BITSTRING_H
    #define HUFFMAN_BITSTRING_H
    #include <iostream>
    #include <vector>
    
    class BitStringWrite {
    
    private:
        char _byte;
        int _pos;
        std::ostream &_out_f;
    
    public:
        BitStringWrite(std::ostream &_out_f);
    
        ~BitStringWrite();
    
        void writeBit(bool bit);
    
        void writeByte(char b);
    
        void flush();
    };
    
    class BitStringRead {
    
    private:
        char _byte;
        int _pos;
        std::istream &_in_f;
    
    public:
    
        BitStringRead(std::istream &_in_f);
    
        char readByte();
    
        bool readBit();
    
        char getByte(){
            return _byte;
        }
    
    };
    #endif //HUFFMAN_BITSTRING_H


**bitstring.cpp**


    #include "bitstring.h"
    
    BitStringWrite::BitStringWrite(std::ostream &_out_f) : _byte(0), _pos(0), _out_f(_out_f) {}
    
    void BitStringWrite::writeBit(bool bit) {
        if (_pos == 8)
            flush();
        if (bit == 1) {
            _byte |= (1 <<  _pos);
        }
        _pos++;
    }
    
    void BitStringWrite::writeByte(char b){
        for(int i = 0; i < 8; i++)
            writeBit((b >> i) & 1);
    }
    
    void BitStringWrite::flush() {
        if (_pos != 0) {
            _out_f.write(&_byte, sizeof(char));
            _pos = 0;
            _byte = 0;
        }
    }
    
    BitStringRead::BitStringRead(std::istream &_in_f) : _pos(8), _in_f(_in_f) {}
    
    bool BitStringRead::readBit() {
        if (_pos == 8) {
            _in_f.read(&_byte, sizeof(char));
            _pos = 0;
        }
        return (_byte >>  _pos++) & (char)1;
    }
    
    char BitStringRead::readByte() {
        char sym = (char)0;
        for (int i = 0; i < 8; i++){
            sym |= ((1 & readBit()) << (i));
        }
        return sym;
    }
    
    BitStringWrite::~BitStringWrite() {
        flush();
    }