数据结构 _ 基础练习 _ 7-9 Huffman Codes

原题

点此链接1

题目分析

本题其实一共有三个点:

  1. 不等长编码可以得到多个最优解,其带权路径长度(WPL)是一致的
  2. 编码树所有的字符必须是叶子结点
  3. 所有的字符不存在二义性(即一个叶子结点只能表示一个字符)

程序1

按照课本(高等教育出版社 - 陈越 - 《数据结构》)P153部分,根据上述三个点分别计算最优解的WPL,随后根据递交的作业计算其WPL并进一步判断是否满足点2和点3。
这种方法比较死板,程序书写较多,不适合测试,但通用性更强。

#include <iostream>
#include <memory>
#include <list>
#include <queue>
#include <map>
#include <string>

using namespace std;

class Node;
typedef shared_ptr<Node> PNode;

class Node
{
public:
    char v = 0;
    int f = -1;
    PNode l;
    PNode r;
    PNode fa;
    Node() = default;
    Node(char c, int f) : v(c), f(f) {}
};

int Height(PNode node)
{
    int counter = 0;
    while (node->fa)
    {
        counter++;
        node = node->fa;
    }
    return counter;
}

int Freq(PNode node)
{
    auto res = node->f * Height(node);
    return res;
}

int Check(PNode node, map<char, int> raw)
{
    char s;
    string code;
    std::cin >> s >> code;
    auto sum = code.size() * raw.at(s);

    for (const auto r : code)
    {
        // 0 in the left and 1 in ther right
        if (r == '0')
        {
            // if the node is empty
            if (!node->l)
                node->l = make_shared<Node>(Node('\n', 0));
            node = node->l;
        }
        else
        {
            // if the node is empty
            if (!node->r)
                node->r = make_shared<Node>(Node('\n', 0));
            node = node->r;
        }
    }
    if (node->v != '\n')
	{
		//cout << string(10,'*') << "\trepeat" << endl;
		return -1;
	}
    if (node->l || node->r)
    {
        //cout << string(10,'*') << "\tnot leaf" << endl;
        return -1;
    }
    node->v = s;
    return sum;
}

int main()
{
    int min = 0;
    int charSum;
    map<char, int> raw;
    {
        list<PNode> data;
        std::cin >> charSum;
        for (auto i = 0; i < charSum; i++)
        {
            char charTmp;
            int intTmp;
            std::cin >> charTmp >> intTmp;
            data.push_back(make_shared<Node>(Node(charTmp, intTmp)));
            raw.insert({charTmp, intTmp});
        }

        // create huffman tree to calculate the optimal size
        while(data.size()>1)
        {
            data.sort([](PNode pl, PNode pr) { return pl->f < pr->f; });
            auto a = data.front();
            data.pop_front();
            auto b = data.front();
            data.pop_front();

            auto sum = a->f + b->f;
            data.push_back(make_shared<Node>(Node('\n', sum)));
            data.back()->l = a;
            data.back()->r = b;
            a->fa = data.back();
            b->fa = data.back();
        }
        queue<PNode> q;
        q.push(data.front());

        while (!q.empty())
        {
            auto sub = q.front();
            q.pop();
            if (!sub->l && !sub->r)
                min += Freq(sub);
            else
            {
                if (sub->l)
                    q.push(sub->l);
                if (sub->r)
                    q.push(sub->r);
            }
        }
    }

    int n;
    std::cin >> n;
    vector<bool> resBool(n, true);
    for (auto i = 0; i < n; i++)
    {
        int sum = 0;
        auto head = make_shared<Node>(Node('\n', -1));
        for (auto j = 0; j < charSum; j++)
        {
            // 1.check 1, if all the node in the leaf node.
            auto res = Check(head, raw);
            if (res == -1)
                resBool[i] = false;
            sum += res;
        }
        // 2. check 2, if it is optimal of the sum
        if (sum != min)
        {
            //cout << string(10,'*') << "\tnot the optimal" << endl;
            resBool[i] = false;
        }
    }
    for (bool r : resBool)
        if (r)
            cout << "Yes" << endl;
        else
            cout << "No" << endl;

    return 0;
}

程序2

程序可以优化,参考这篇博文2,可以得知哈弗曼树的WPL计算并不需要构造哈弗曼树然后计算。只需要计算所有的非叶子结点权值和即可。
参考这篇博文3的第二种解法,可以确定C++标准库中可以用优先序列定义最小堆随后再计算WPL。


#include <functional>
#include <iostream>
#include <memory>
#include <list>
#include <queue>
#include <map>
#include <string>

using namespace std;

class Node;
typedef shared_ptr<Node> PNode;

class Node
{
public:
    PNode l;
    PNode r;
    char v = 0;
};

int Check(PNode node, map<char, int> raw)
{
    char s;
    string code;
    std::cin >> s >> code;

    for (const auto r : code)
    {
        // 0 in the left and 1 in ther right
        if (r == '0')
        {
            if (!node->l)
                node->l = make_shared<Node>(Node());
            node = node->l;
        }
        else
        {
            if (!node->r)
                node->r = make_shared<Node>(Node());
            node = node->r;
        }
    }
    if (node->v)
    {
        // cout << string(10, '*') << "\trepeat" << endl;
        return -1;
    }
    if (node->l || node->r)
    {
        // cout << string(10, '*') << "\tnot leaf" << endl;
        return -1;
    }
    node->v = s;
    return code.size() * raw.at(s);
}

int main()
{
    map<char, int> raw; // raw data
    auto wsl = 0;       // wsl
    {
        priority_queue<int,vector<int>,greater<>> fre;
        auto num = 0;
        cin >> num;
        for (auto i = 0; i < num; i++)
        {
            pair<char, int> pairTmp;
            std::cin >> pairTmp.first >> pairTmp.second;
            fre.push(pairTmp.second);
            raw.insert(pairTmp);
        }

        // calculate the wsl
        while (fre.size() > 1)
        {
            auto a = fre.top();
            fre.pop();
            auto b = fre.top();
            fre.pop();
            wsl += a + b;
            fre.push(a + b);
        }
    }

    int n;
    std::cin >> n;
    vector<bool> resBool(n, true);
    for (auto i = 0; i < n; i++)
    {
        auto sum = 0;
        auto head = make_shared<Node>(Node());
        for (size_t j = 0; j < raw.size(); j++)
        {
            // 1.check 1, if all the node in the leaf node.
            auto res = Check(head, raw);
            if (res == -1)
                resBool[i] = false;
            sum += res;
        }
        // 2. check 2, if it is optimal of the sum
        if (sum != wsl)
        {
            // cout << string(10, '*') << "\tnot the optimal" << endl;
            resBool[i] = false;
        }
    }
    for (bool r : resBool)
        if (r)
            cout << "Yes" << endl;
        else
            cout << "No" << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值