2. 计算WPL

2023-10-24 12:04
文章标签 计算 wpl

本文主要是介绍2. 计算WPL,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

Huffman编码是通信系统中常用的一种不等长编码,它的特点是:能够使编码之后的电文长度最短。

更多关于Huffman编码的内容参考教材第十章。

输入:
    第一行为要编码的符号数量n
    第二行~第n+1行为每个符号出现的频率

输出:
    对应哈夫曼树的带权路径长度WPL

解释

①哈夫曼树的构造

哈夫曼树,也称为最优二叉树,是一种带权路径长度(WPL)最短的二叉树。这里的带权路径长度就是叶子节点的权值与它到根节点的路径长度之积的总和。

哈夫曼树的构造方法是基于贪心算法,步骤如下:

1. 将每个权值看作是独立的一棵树,这些权值通常来自要编码字符的频率。

2. 在所有未构造二叉树的集合中选出两个权值最小的树作为左右子树,构造出一棵新的二叉树,同时这两个权值之和作为新的父节点的权值。

3. 在集合中删除这两个已经被使用的节点,将新构造的二叉树(父节点)加入到集合中。

4. 重复其中的步骤2-3,直到集合中只剩下一棵树,这棵树就是最终的哈夫曼树。

哈夫曼树常见的应用是哈夫曼编码,它是一种被广泛用于数据压缩的编码方式。根据哈夫曼树,我们可以为叶子节点分配相应的哈夫曼编码,使得编码长度短的更常见,这样可以有效地减少编码的总长度,达到数据压缩的目的。

②WPL的计算

带权路径长度(Weighted Path Length,简称 WPL),它是所有叶子节点的权值乘以其到根节点的路径长度之和。

以二叉树为例,叶子节点是没有子节点的节点,而根节点是最顶层的节点。路径长度则是从一个节点到另一个节点之间的边的数量。

具体计算过程如下:

1. 对每个叶子节点,计算根节点到该叶子节点的路径长度,即从根节点到叶子节点所经过的边的数量。

2. 将每个叶子节点的权值与其对应的路径长度相乘。

3. 将上述所有的乘积相加,得到的总和就是这棵树的带权路径长度。

在哈夫曼编码中,我们通常希望带权路径长度尽可能的小,这样可以让编码更加高效。

C++代码

#include <iostream>  
#include <queue>     using namespace std;struct Node {           // 定义节点结构体int freq;           // 频率Node* left;         // 左子节点Node* right;        // 右子节点
};// 创建新的节点
Node* newNode(int freq)  // 定义新节点的创建函数,输入是频率值,返回创建的新节点的指针
{Node* node = new Node(); // 动态创建新节点node->left = node->right = NULL; // 初始化左右子节点为空node->freq = freq; // 设置新节点的频率return (node);     // 返回新节点的指针
}// 比较节点的频率
struct compare {     // 定义比较结构体,作为优先级队列的比较函数bool operator()(Node* l, Node* r)     // 重载括号运算符,用以比较两个节点的频率{return (l->freq > r->freq);   // 如果第一个节点频率大于第二个,返回真,否则假}
};// 计算哈夫曼树的权值路径长度
int calculateWPL(Node* root, int depth = 0)  // 定义计算WPL的函数,输入是根节点的指针和路径深度(默认为0),返回路径长度值
{if (!root) return 0;   // 如果节点为空,返回0if (!root->left && !root->right) return depth * root->freq; // 如果是叶子节点(无左右子节点),返回当前深度乘以节点频率// 如果不是叶子节点,递归计算左右子树的WPL,返回两者之和return calculateWPL(root->left, depth + 1) + calculateWPL(root->right, depth + 1);
}int main() { int n;cin >> n; priority_queue<Node*, vector<Node*>, compare> pq; // 定义一个优先队列,用于存储节点指针,利用 compare 结构体比较节点频率for (int i = 0; i < n; ++i){int freq;cin >> freq;      // 输入每个节点的频率值pq.push(newNode(freq)); // 创建新的节点,并将其添加到优先队列中}while (pq.size() != 1) {   // 当优先队列中只有一个元素时,结束循环Node* left = pq.top();  // 获取频率最小的节点,作为左子节点pq.pop();               // 将该节点从优先队列中移除Node* right = pq.top(); // 获取频率次小的节点,作为右子节点pq.pop();               // 将该节点从优先队列中移除int sum = left->freq + right->freq; // 计算左右子节点频率之和Node* top = newNode(sum);  // 以这个频率和创建新节点top->left = left;          // 将左子节点连接到新节点top->right = right;        // 将右子节点连接到新节点pq.push(top); // 将新节点添加到优先队列中}cout << "WPL=" << calculateWPL(pq.top()) << endl; // 输出哈夫曼树的带权路径长度return 0;   // 程序执行成功,返回0
}

这篇关于2. 计算WPL的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/275047

相关文章

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

XTU 1237 计算几何

题面: Magic Triangle Problem Description: Huangriq is a respectful acmer in ACM team of XTU because he brought the best place in regional contest in history of XTU. Huangriq works in a big compa

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

计算数组的斜率,偏移,R2

模拟Excel中的R2的计算。         public bool fnCheckRear_R2(List<double[]> lRear, int iMinRear, int iMaxRear, ref double dR2)         {             bool bResult = true;             int n = 0;             dou

GPU 计算 CMPS224 2021 学习笔记 02

并行类型 (1)任务并行 (2)数据并行 CPU & GPU CPU和GPU拥有相互独立的内存空间,需要在两者之间相互传输数据。 (1)分配GPU内存 (2)将CPU上的数据复制到GPU上 (3)在GPU上对数据进行计算操作 (4)将计算结果从GPU复制到CPU上 (5)释放GPU内存 CUDA内存管理API (1)分配内存 cudaErro

Java - BigDecimal 计算分位(百分位)

日常开发中,如果使用数据库来直接查询一组数据的分位数,就比较简单,直接使用对应的函数就可以了,例如:         PERCENT_RANK() OVER(PARTITION BY 分组列名 ORDER BY 目标列名) AS 目标列名_分位数         如果是需要在代码逻辑部分进行分位数的计算,就需要我们自己写一个工具类来支持计算了 import static ja

OpenStack离线Train版安装系列—2计算节点-环境准备

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

新一代车载(E/E)架构下的中央计算载体---HPC软件架构简介

老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节能减排。 无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事.而不是让内心的烦躁、焦虑、毁掉你本就不多的热情和定力。 时间不知不觉中,快要来到夏末秋初。一年又过去了一大半,成