1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
|
# include <algorithm>
# include <iomanip>
# include <iostream>
# include <iterator>
# include <map>
# include <memory>
# include <queue>
template<typename Iter>
auto symbol_frequencies(Iter begin, Iter end) {
using value_type = typename std::iterator_traits<Iter>::value_type;
std::map<value_type, std::size_t> result;
std::for_each(begin, end, [&](auto const elt){ ++result[elt]; });
return result;
}
/* Huffman tree node */
struct Node {
Node(char sym, int freq,
std::unique_ptr<Node>&& l = nullptr,
std::unique_ptr<Node>&& r = nullptr)
: sym(sym) , freq(freq)
, lchild{std::move(l)} , rchild{std::move(r)}
{}
char sym{}; /* Character represented by the node */
int freq; /* Number of times the symbol appears */
std::unique_ptr<Node> lchild, rchild;
};
// print a node
inline std::ostream& operator<<(std::ostream& s, Node const& n)
{ return s << "('" << n.sym << "', " << n.freq << ')'; }
// compare two nodes through unique_ptrs
struct Cmp {
inline bool operator()(std::unique_ptr<Node> const& lhs,
std::unique_ptr<Node> const& rhs)
{ return lhs->freq > rhs->freq; }
};
template<typename Iter>
std::unique_ptr<Node> huffman_tree(Iter begin, Iter end) {
using value_type = std::unique_ptr<Node>;
std::priority_queue<value_type, std::vector<value_type>, Cmp> heap;
for (auto sym_freq: symbol_frequencies(begin, end))
heap.push(std::make_unique<Node>(sym_freq.first, sym_freq.second));
while (heap.size() > 1) {
value_type l = std::move(const_cast<value_type&>(heap.top())); heap.pop();
value_type r = std::move(const_cast<value_type&>(heap.top())); heap.pop();
heap.emplace(std::make_unique<Node>('\0', l->freq + r->freq,
std::move(l), std::move(r)));
}
return heap.size()? std::move(const_cast<value_type&>(heap.top())): nullptr;
}
void display_codes(std::unique_ptr<Node> const& n, std::string acc = "") {
if (!n) return;
if (n->sym) {
std::cout << n->sym << " = " << std::setw(8) << std::left << acc
<< ' ' << *n << '\n';
}
display_codes(n->lchild, acc + "0"); // DFS
display_codes(n->rchild, acc + "1");
}
int main() {
std::string line; std::getline(std::cin, line);
display_codes(huffman_tree(line.begin(), line.end()));
}
|