解决关于哈夫曼编码计算带权路径长度问题

这是在做一道编程提示遇到的,学习了一位博主的编码,其中有些问题未能理解,分析解决掉。

首先什么是哈夫曼树:

哈夫曼树,又称最优二叉树,是一类带权路径长度最短的树。

也就是根节点到节点的中的长度最小,当然条件就是,每条路径都是有权重的,

所谓树的带权路径长度,就是树中所有的叶结点的权值乘上其到根结点的 路径长度(若根结点为0层,叶结点到根结点的路径长度为叶结点的层数)。树的带权路径长度记为WPL= (W1*L1+W2*L2+W3*L3+…+Wn*Ln)

此时WPL=32×1+24×2+2×3+7×3

一般建立哈夫曼树的步骤为

1,将所有左,右子树都为空的作为根节点。

2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。

3,从森林中删除这两棵树,同时把新树加入到森林中。

4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。

太原理工网站给出了动画演示

http://www.tyut.edu.cn/kecheng1/site01/suanfayanshi/Huffman.asp

上面提到的根据权重排序,选出权重最小的两个,这个功能在优先队列中完全可以做到。所以在构建哈夫曼树时可以利用优先队列

然后看看题目吧

Input
The input file will contain a list of text strings, one per line. The text strings will consist only of uppercase alphanumeric characters and underscores (which are used in place of spaces). The end of the input will be signalled by a line containing only the word “END” as the text string. This line should not be processed.

Output
For each text string in the input, output the length in bits of the 8-bit ASCII encoding, the length in bits of an optimal prefix-free variable-length encoding, and the compression ratio accurate to one decimal point.

Sample Input
AAAAABCD
THE_CAT_IN_THE_HAT
END

Sample Output
64 13 4.9
144 51 2.8

这里直接给出网上参考代码,然后分析

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<functional>
#include<queue>
using namespace std;
#define M 1000050
char str[M];   //全局变量中 默认初始化为0;
int list[27];  

priority_queue< int,vector<int>,greater<int> >que;  

int main()
{
    int ans,sum;
    int i,a,b,c;
    while(scanf("%s",str),strcmp(str,"END")){
        memset(list,0,sizeof(list));
        for(i=0;str[i];i++){
            if(isalpha(str[i]))
                list[str[i]-‘A‘]++;
            else
                list[26]++;
        }
        sum=i*8;ans=i;c=0;  //sum 为原等长编码需要的bit位 ans为hfm编码
        for(i=0;i<27;i++){
            if(list[i]){
                que.push(list[i]);
                c++;
            }
        }
        if(c>1) //c==1时,只有一种字母
        {
            ans=0;//注意只有一种字符的情况
            while(que.size()!=1)
            {
                a=que.top();
                que.pop();
                b=que.top();
                que.pop();
                ans+=a+b;
                que.push(a+b);
            }
            while(!que.empty())//使用后清空队列
                que.pop();
        }
        printf("%d %d %.1f\n",sum,ans,1.0*sum/ans);
    }
    return 0;
}  

1、输入字符串部分

for(i=0;str[i];i++){
   if(isalpha(str[i]))
    list[str[i]-‘A‘]++;
   else
    list[26]++;
  }

在ctype.h中,是一个宏,判读是否为大写字母

list是一个数组int list[27]统计26个字母和下划线字符,用来统计多少个A、B,用字母到A的绝对距离作为数组的下标,数组对应的元素存放字母出现

的次数。这里的写法非常简洁,数组元素++的写法,

2、编码计数

sum=i*8;ans=i;c=0;

sum 为原等长编码需要的bit位 ans为hfm编码,i为字母的个数

3、利用优先队列来考虑权重问题

for(i=0;i<27;i++){
   if(list[i]){
    que.push(list[i]);
    c++;
   }
  }

将字母出现的次数作为权重,压如队列中,C用于记录出现不同字母的个数。

3、模拟建立哈夫曼树

if(c>1) //c==1时,只有一种字母
  {
   ans=0;//注意只有一种字符的情况
   while(que.size()!=1)
   {
    a=que.top();
    que.pop();
    b=que.top();
    que.pop();
    ans+=a+b;
    que.push(a+b);
   }
   while(!que.empty())//使用后清空队列
    que.pop();
  }  

while中的过程完全按照,上面提到的步骤来

如果加入输入AAAABBBCCD,根据上面步骤会得到这样一棵树

这样编码出来为

A: 0 1bit

B: 10 2bit

C: 110 3bit

D: 111 3bit

所以中的编码位数就是出现次数×编码bit

1×4+2×3+3×2+3×1=19

这个就是带权路径长度,因为出现的次数就是权重,编码长度就是节点到根节点的层数,

如何在不把树建立起来,求带权路径长度,只要将这些权重全部加起来即可,正如程序中所做的那样

程序中

ans=(1+2)+(3+3)+(4+6);

这样分解出来

(1+2)+((1+2)+3)+(4+((1+2)+3))

将(1+2)加了3次,实际就是加的层数。

所以ans就是这个哈夫曼树的带权路径和。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 21:04:44

解决关于哈夫曼编码计算带权路径长度问题的相关文章

优先级队列优化的霍夫曼编码(带中文压缩)

利用STL中的优先级队列进行优化 我将压缩和解压分为两部分,其实一些还是是一样的 压缩的时候通过bitset将每8个01串压缩成一个字节,如果最后一个不满足8个,用0补齐,但是要记录最后一个字节实际有多少个有效位,将其存入文件最后一个字节,解压的时候先将文件定位到最后一个字节,取出有效位的个数,压缩文件真正有效的是倒数第二个字节,倒数第一个字节只是记录倒数第二个字节中有几位是有效的,解压的时候根据密码本(记录每个字节的权值)建立哈夫曼树,然后更具哈夫曼树解压文件 压缩代码部分: #include

哈夫曼编码问题再续(下篇)——优先队列求解

上篇描述了哈夫曼编码问题的基本描述以及建造一个哈夫曼树的过程分析,那么当算法已经描述清楚之后,我们要怎么样来实现 代码呢?或者说,给你一些带有权值的叶子节点,要怎么样利用程序快速算出所对应的哈夫曼树的带权路径WPL呢? 我们首先回顾一下上篇讲到的那个问题: 例如有这一个字符串"good good study day day up",现在我们要对字符串进行哈夫曼编码,该字符串一共有 26 个字符,10 种字符,我们首先统计出每个字符的频率,然后按从大到小顺序排列如下(第二列的字符是空格)

哈弗曼树的构建,哈夫曼编码、译码

哈夫曼树的基本概念 哈夫曼树(Huffman Tree),又叫最优二叉树,指的是对于一组具有确定权值的叶子结点的具有最小带权路径长度的二叉树. (1)路劲(Path):从树中的一个结点到另一个结点之间的分支构成两个结点间的路径. (2)路径长度(Path Length):路径上的分支树. (3)树的路径长度(Path Length of Tree):从树的根结点到每个结点的路径长度之和.在结点数目相同的二叉树中,完全二叉树的路径长度最短. (4)结点的权(Weight of  Node):在一些

求哈夫曼的带权路径长度

[问题描述] 已知输入两行正整数,第二行正整数之间用空格键分开,请建立一个哈夫曼树,以输入的数字为叶节点,求这棵哈夫曼树的带权路径长度. [输入形式] 首先第一行为输入正整数的个数,然后接下来的一行正整数,代表叶结点,正整数个数不超过1000个 [输出形式] 输出相应的权值 [样例输入] 5 4 5 6 7 8 [样例输出] 69 关于哈夫曼树-- 1. 路径长度 从树中一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称做路径长度. 图1  从根节点到D节点的路径长度为4

java 哈夫曼编码

//哈夫曼树类 public class HaffmanTree { //最大权值 static final int MAXVALUE=1000; int nodeNum ; //叶子结点个数 public HaffmanTree(int n) { this.nodeNum = n; } //构造哈夫曼树算法 public void haffman(int[] weight,HaffNode[] nodes)//权值数组,所有节点数组 { int n = this.nodeNum; //m1,m

二叉树的基本操作及哈夫曼编码系统的实现

实验环境:win10,VC++ 6.0  使用语言:C/C++ 实验内容一:编写程序,完成二叉树的先序创建.先序遍历.中序遍历和后序遍历等操作 Binary.h 1 #include<iostream> 2 #include<stdlib.h> 3 #include<stack> 4 #include<queue> 5 using namespace std; 6 7 typedef char ElemType; 8 9 typedef struct BiT

哈夫曼编码(Huffman coding)的那些事,(编码技术介绍和程序实现)

前言 哈夫曼编码(Huffman coding)是一种可变长的前缀码.哈夫曼编码使用的算法是David A. Huffman还是在MIT的学生时提出的,并且在1952年发表了名为<A Method for the Construction of Minimum-Redundancy Codes>的文章.编码这种编码的过程叫做哈夫曼编码,它是一种普遍的熵编码技术,包括用于无损数据压缩领域.由于哈夫曼编码的运用广泛,本文将简要介绍: 哈夫曼编码的编码(不包含解码)原理 代码(java)实现过程 一

哈夫曼树以及哈夫曼编码的问题

今天看到一个哈夫曼编码的题目,给定一个字符串abcdabaa,问哈夫曼编码后的二进制串的总长度是多少,答案是14 对于哈夫曼树我是一点都不了解啊,所以一顿查找,总结出以下知识点,与大家分享:当然部分内容参考了下百度 哈夫曼树又称为最优二叉树,是一种带权路径最短的二叉树.哈夫曼树是二叉树的一种应用,在信息检索中很常用. 一些相关的概念: 1.节点之间的路径长度:从一个节点到另一个节点之间的分支数量称为两个节点之间的路径长度. 2.树的路径长度:从根节点到树中每一个节点的路径长度之和. 3.节点的带

【数据结构】树与树的表示、二叉树存储结构及其遍历、二叉搜索树、平衡二叉树、堆、哈夫曼树与哈夫曼编码、集合及其运算

1.树与树的表示 什么是树? 客观世界中许多事物存在层次关系 人类社会家谱 社会组织结构 图书信息管理 分层次组织在管理上具有更高的效率! 数据管理的基本操作之一:查找(根据某个给定关键字K,从集合R 中找出关键字与K 相同的记录).一个自然的问题就是,如何实现有效率的查找? 静态查找:集合中记录是固定的,没有插入和删除操作,只有查找 动态查找:集合中记录是动态变化的,除查找,还可能发生插入和删除 静态查找--方法一:顺序查找(时间复杂度O(n)) int SequentialSearch(St