91 lines
2.0 KiB
C++
91 lines
2.0 KiB
C++
#include "stdio.h"
|
|
#include <algorithm>
|
|
#include <climits> // for CHAR_BIT
|
|
#include <iostream>
|
|
#include <iterator>
|
|
#include <map>
|
|
#include <math.h>
|
|
#include <queue>
|
|
|
|
using namespace std;
|
|
|
|
const int UniqueSymbols = 1 << CHAR_BIT;
|
|
void printBits(unsigned int val, int numbits) {
|
|
for (int i = numbits - 1; i >= 0; i--)
|
|
putchar('0' + ((val >> i) & 1));
|
|
}
|
|
|
|
typedef vector<bool> HuffCode;
|
|
typedef map<unsigned char, HuffCode> HuffCodeMap;
|
|
|
|
class INode {
|
|
public:
|
|
const int f;
|
|
virtual ~INode() {}
|
|
|
|
protected:
|
|
INode(int f) : f(f) {}
|
|
};
|
|
|
|
class InternalNode : public INode {
|
|
public:
|
|
INode *const left;
|
|
INode *const right;
|
|
|
|
InternalNode(INode *c0, INode *c1)
|
|
: INode(c0->f + c1->f), left(c0), right(c1) {}
|
|
~InternalNode() {
|
|
delete left;
|
|
delete right;
|
|
}
|
|
};
|
|
|
|
class LeafNode : public INode {
|
|
public:
|
|
const char c;
|
|
|
|
LeafNode(int f, char c) : INode(f), c(c) {}
|
|
};
|
|
|
|
struct NodeCmp {
|
|
bool operator()(const INode *lhs, const INode *rhs) const {
|
|
return lhs->f > rhs->f;
|
|
}
|
|
};
|
|
|
|
INode *BuildTree(unsigned int (&frequencies)[UniqueSymbols]) {
|
|
std::priority_queue<INode *, std::vector<INode *>, NodeCmp> trees;
|
|
|
|
for (int i = 0; i < UniqueSymbols; ++i) {
|
|
if (frequencies[i] != 0)
|
|
trees.push(new LeafNode(frequencies[i], (char)i));
|
|
}
|
|
while (trees.size() > 1) {
|
|
INode *childR = trees.top();
|
|
trees.pop();
|
|
|
|
INode *childL = trees.top();
|
|
trees.pop();
|
|
|
|
INode *parent = new InternalNode(childR, childL);
|
|
trees.push(parent);
|
|
}
|
|
return trees.top();
|
|
}
|
|
|
|
void GenerateCodes(const INode *node, const HuffCode &prefix,
|
|
HuffCodeMap &outCodes) {
|
|
if (const LeafNode *lf = dynamic_cast<const LeafNode *>(node)) {
|
|
outCodes[lf->c] = prefix;
|
|
} else if (const InternalNode *in =
|
|
dynamic_cast<const InternalNode *>(node)) {
|
|
HuffCode leftPrefix = prefix;
|
|
leftPrefix.push_back(false);
|
|
GenerateCodes(in->left, leftPrefix, outCodes);
|
|
|
|
HuffCode rightPrefix = prefix;
|
|
rightPrefix.push_back(true);
|
|
GenerateCodes(in->right, rightPrefix, outCodes);
|
|
}
|
|
}
|