Cod sursa(job #2638597)

Utilizator andreioneaAndrei Onea andreionea Data 29 iulie 2020 02:38:00
Problema Coduri Huffman Scor 50
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.23 kb
#include <fstream>
#include <cstdint>
#include <vector>
#include <queue>
#include <functional>
#include <unordered_map>

struct Huffman {
    struct Encoding {
        uint64_t val;
        uint32_t len;
    };
    using FrequencyType = uint64_t;
    using ElementType = uint32_t;
    using EncodingType = Encoding;
    struct Node {
        struct Children {
            Node* left;
            Node* right;
        };
        enum class NodeType : char {
            Regular,
            Leaf
        };
        NodeType type;
        union {
            Children children;
            ElementType leafValue;
        };
        FrequencyType freq;
        Node(FrequencyType freq)
        : freq(freq), type(NodeType::Regular), children({nullptr, nullptr}) {}
        Node(FrequencyType freq, ElementType element)
        : freq(freq), type(NodeType::Leaf), leafValue(element) {}
    };
private:

    uint64_t numCharacters;
    std::vector<EncodingType> encodings;
    uint64_t totalLength;

    Huffman(uint64_t numCharacters) : numCharacters(numCharacters) {
        encodings.reserve(numCharacters);
    }
    static uint64_t Traverse(Huffman& h, Node* node, uint64_t currMask, uint32_t height) {
        if (node->type == Node::NodeType::Leaf) {
            h.encodings[node->leafValue] = Encoding{currMask, height};
            return height * node->freq;
        } else {
            const auto h1 = Traverse(h, node->children.left, currMask << 1, height + 1);
            const auto h2 = Traverse(h, node->children.right, (currMask << 1) | 1, height + 1);
            return h1 + h2;
        }
    }
public:
    uint64_t NumCharacters() const { return numCharacters; }
    uint64_t TotalLength() const { return totalLength; }
    EncodingType EncodingFor(ElementType el) const { return encodings[el]; }
    static Huffman Construct(std::ifstream& f) {
        std::vector<Node> nodes;
        Node* root = nullptr;
        uint64_t numNodes;
        f >> numNodes;
        nodes.reserve(2 * numNodes);
        std::vector<Node*> q;
        Huffman h{numNodes};

        auto newNode = [&](FrequencyType freq) -> Node* {
            nodes.emplace_back(freq);
            return &nodes.back();
        };
        auto newLeaf = [&](FrequencyType freq, ElementType element) -> Node* {
            nodes.emplace_back(freq, element);
            return &nodes.back();
        };
        uint64_t currIdx = 0;
        Node* lastReadNode = nullptr;
        auto readNode = [&]() -> void {
            if (currIdx >= numNodes) {
                lastReadNode = nullptr;
                return;
            }
            uint64_t freq;
            f >> freq;
            lastReadNode = newLeaf(freq, currIdx++);
        };
        readNode();
        auto popReadNode = [&]() -> Node* {
            auto ret = lastReadNode;
            readNode();
            return ret;
        };

        auto popQueue = [&] () -> Node* {
            if (q.empty()) {
                return nullptr;
            }
            auto ret = q.front();
            q.erase(q.begin());
            return ret;
        };

        auto popNode = [&]() -> Node* {
            if (!lastReadNode) {
                if (q.empty()) {
                    return nullptr;
                }
                return popQueue();
            }
            if (q.empty()) {
                return popReadNode();
            }
            if (lastReadNode->freq < q.front()->freq) {
                return popReadNode();
            }
            return popQueue();
        };

        while (true) {
            Node* left = popNode();
            Node* right = popNode();
            if (!right) {
                root = left;
                break;
            }
            Node* n = newNode(left->freq + right->freq);
            n->children.left = left;
            n->children.right = right;
            q.push_back(n);
        }
        h.totalLength = Traverse(h, root, 0u, 0);
        return h;
    }
};

int main() {
    std::ifstream fin("huffman.in");
    Huffman h = Huffman::Construct(fin);
    std::ofstream fout("huffman.out");
    fout << h.TotalLength() << '\n';
    for (uint32_t i = 0; i < h.NumCharacters(); ++i) {
        const auto encoding = h.EncodingFor(i);
        fout << encoding.len << ' ' << encoding.val << '\n';
    }
    return 0;
}