Some encode/decode practice.
This commit is contained in:
parent
8a41337e2d
commit
ff962a6b16
29 changed files with 727 additions and 305 deletions
|
@ -1,77 +1,100 @@
|
|||
#include "HuffmanEncoder.h"
|
||||
|
||||
#include "Tree.h"
|
||||
#include "RawTree.h"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <iostream>
|
||||
|
||||
void HuffmanEncoder::dumpNode(RawNode<CountPair>* node, unsigned depth) const
|
||||
{
|
||||
if (!node)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = node->getData();
|
||||
|
||||
std::string prefix(depth, '_');
|
||||
|
||||
if (node->isLeaf())
|
||||
{
|
||||
std::cout << prefix << "Leaf with value: " << data.first << " and sum " << data.second << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << prefix << "Intermediate with sum " << data.second << std::endl;
|
||||
std::cout << prefix << "Doing Left.." << std::endl;
|
||||
dumpNode(node->getLeftChild(), depth+1);
|
||||
|
||||
std::cout << prefix << "Doing Right.." << std::endl;
|
||||
dumpNode(node->getRightChild(), depth+1);
|
||||
|
||||
std::cout << prefix << "*****" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void HuffmanEncoder::dumpTree(const RawTree<CountPair>& tree) const
|
||||
{
|
||||
dumpNode(tree.getRootNode(), 0);
|
||||
}
|
||||
|
||||
void HuffmanEncoder::encode(const HuffmanEncoder::DataStream& stream)
|
||||
{
|
||||
std::unordered_map<unsigned char, unsigned> counts;
|
||||
for (auto c : stream)
|
||||
{
|
||||
counts[c]++;
|
||||
}
|
||||
|
||||
using CountPair = std::pair<unsigned char, unsigned>;
|
||||
auto cmp = [](CountPair left, CountPair right)
|
||||
{
|
||||
return left.second > right.second;
|
||||
};
|
||||
std::priority_queue<CountPair, std::vector<CountPair>, decltype(cmp)> q(cmp);
|
||||
for (const auto& entry : counts)
|
||||
{
|
||||
q.push({entry.first, entry.second});
|
||||
}
|
||||
|
||||
NodePtr<CountPair> lastNode;
|
||||
while(!q.empty())
|
||||
{
|
||||
const auto charData = q.top();
|
||||
auto characterNode = std::make_unique<Node<CountPair> >(charData);
|
||||
q.pop();
|
||||
|
||||
if (!lastNode)
|
||||
{
|
||||
const auto rightCharData = q.top();
|
||||
auto rightCharacterNode = std::make_unique<Node<CountPair> >(rightCharData);
|
||||
q.pop();
|
||||
|
||||
const auto sum = charData.second + rightCharData.second;
|
||||
CountPair data{0, sum};
|
||||
auto midNode = std::make_unique<Node<CountPair> >(data);
|
||||
|
||||
midNode->addChild(std::move(characterNode));
|
||||
midNode->addChild(std::move(rightCharacterNode));
|
||||
lastNode = std::move(midNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto sum = lastNode->getData().second;
|
||||
CountPair data{0, sum};
|
||||
auto midNode = std::make_unique<Node<CountPair> >(data);
|
||||
|
||||
if (charData.second < lastNode->getData().second)
|
||||
{
|
||||
midNode->addChild(std::move(lastNode));
|
||||
midNode->addChild(std::move(characterNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
midNode->addChild(std::move(characterNode));
|
||||
midNode->addChild(std::move(lastNode));
|
||||
}
|
||||
lastNode = std::move(midNode);
|
||||
}
|
||||
}
|
||||
|
||||
Tree<CountPair> tree;
|
||||
tree.addRootNode(std::move(lastNode));
|
||||
|
||||
//using TableEntry = std::tuple<>
|
||||
|
||||
|
||||
std::cout << "********" << std::endl;
|
||||
std::unordered_map<unsigned char, unsigned> counts;
|
||||
for (auto c : stream)
|
||||
{
|
||||
counts[c]++;
|
||||
}
|
||||
encode(counts);
|
||||
}
|
||||
|
||||
void HuffmanEncoder::encode(const std::unordered_map<unsigned char, unsigned>& counts)
|
||||
{
|
||||
std::cout << "Counts" << std::endl;
|
||||
for (const auto& data: counts)
|
||||
{
|
||||
std::cout << data.first << " | " << data.second << std::endl;
|
||||
}
|
||||
std::cout << "*******" << std::endl;
|
||||
|
||||
auto cmp = [](RawNode<CountPair>* left, RawNode<CountPair>* right)
|
||||
{
|
||||
return left->getData().second > right->getData().second;
|
||||
};
|
||||
|
||||
std::priority_queue<RawNode<CountPair>*, std::vector<RawNode<CountPair>* >, decltype(cmp)> q(cmp);
|
||||
for (const auto& entry : counts)
|
||||
{
|
||||
q.push(new RawNode<CountPair>(entry));
|
||||
}
|
||||
|
||||
while(q.size() > 1)
|
||||
{
|
||||
auto node0 = q.top();
|
||||
q.pop();
|
||||
|
||||
auto node1 = q.top();
|
||||
q.pop();
|
||||
|
||||
const auto sum = node0->getData().second + node1->getData().second;
|
||||
auto new_node = new RawNode<CountPair>(CountPair{0, sum});
|
||||
|
||||
new_node->addChild(node0);
|
||||
new_node->addChild(node1);
|
||||
q.push(new_node);
|
||||
}
|
||||
|
||||
auto root = q.top();
|
||||
q.pop();
|
||||
|
||||
RawTree<CountPair> tree;
|
||||
tree.addRootNode(root);
|
||||
|
||||
//using TableEntry = std::tuple<>
|
||||
|
||||
dumpTree(tree);
|
||||
|
||||
std::cout << "********" << std::endl;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue