首页 > 其他分享 >哈夫曼树学习笔记

哈夫曼树学习笔记

时间:2023-08-24 16:33:51浏览次数:31  
标签:编码 哈夫曼 int 笔记 学习 权值 节点 pus

定义:

  • 1.二叉哈夫曼树:对于一个数列,构建一棵树上带权路径之和最小的二叉树(当然可以\(k\)叉)
  • 2.树上带权路径:每个叶子节点到根节点的路径上所有节点的点权\(w\)和到跟的路径长度\(dis\)的乘积之和
    简单来说,哈夫曼树满足\(\sum w_i\times dis_i\)最小

基本构造方法:

前置知识(没做过也可以,但至少要会优先队列):合并果子
一点没错,就是合并果子。你考虑这么一件事,我们想要的就是权值越大的店越靠近根节点,这样\(w_i\)越大\(dis_i\)越小显然更优。那每次找两个最小权值合并就行了。

具体的步骤如下:

  • 1.将\(n\)个元素创建\(n\)个节点并视为\(n\)棵树,权值\(w_i\)即为元素\(a_i\)
  • 2.选择权值最小的两个根节点\(x,y\),创建一个虚拟节点,并将左右子树设为\(x,y\),权值为\(x+y\)(相当于把这两棵树合并了)
  • 3.重复步骤2直到成为一棵树

拿一个序列过来演示一下:\(1\) \(9\) \(8\) \(0\) \(4\)

image
把\(0\)和\(1\)合并:
image
继续合并:
image
image
image
完成!

哈夫曼编码:

哈夫曼树通常和哈夫曼编码一起使用,什么是哈夫曼编码呢?

我们截取小明一天给他同学发的短信:

  • 1.我今天又爆零了
  • 2.我中午吃的面
  • 3.今天考试爆零的好多
    这些消息在二进制下就是一堆\(01\)串,而且在正常编码的情况下每个汉字占的字节都一样多。我们知道传输信息要消耗能量,那么能不能让传输的字符串短一点呢。

一种思路是:让使用更为频繁的汉字编码尽可能的短,比如上文的三句话中,“我”这个字出现次数多,编成\(0\),“面”这个字不怎么常用,编成\(10101100\)。

可还有一个问题,假设“我”是\(0\),“今”是\(1\),“天”是\(10\),那么\(10\)既可以表示“天”,同时也是“我今”。

怎么解决这个问题呢?我们观察上面构造的哈夫曼树,发现每个原节点都是叶子节点,这是显然的,那么就不可能出现一个节点的编码是另一个的前缀。我们只需要把每个字的使用次数当作权值建立哈夫曼树,从根节点开始,向左在字符串后加一位\(0\)向右走加一位\(1\),每个叶子节点的哈夫曼编码就构造完成了。

\[ps:哈夫曼编码可能有前导零 \]

例题:

1.HDU - 1053 Entropy

第一个答案是正常编码的长度,众所周知一个字符长度为\(8\)个比特,直接输出$8\times $长度

第二个答案是哈弗曼编码的长度,你不用真的建树(建了当然也可以),直接用合并果子就行。但要特判只有一种字符的情况(根本不合并)

第三个答案是前两个的比值

CODE:

#include<iostream>
#include<queue>
#define int long long
using namespace std;
int ans1,ans2;
double ans3;
string s;
priority_queue<int, vector<int> , greater<int> > q;
int times[100];

signed main(){
	while(cin>>s && s!="END"){
		ans2=0;
		ans1=s.size()*8;
		for(int i=0;i<=26;i++) times[i]=0;
		for(int i=0;i<s.size();i++){
			if(s[i]!='_') times[s[i]-'A']++;
			else times[26]++;
		}
		for(int i=0;i<=26;i++){
			if(times[i]) q.push(times[i]);
		}
		while(q.size()>1){
			int aa=q.top();
			q.pop();
			int bb=q.top();
			q.pop();
			q.push(aa+bb);
			ans2+=(aa+bb);
		}
		if(!ans2) ans2=q.top();
		ans3=(1.0*ans1)/(1.0*ans2);
		cout<<ans1<<" "<<ans2<<" ";
		printf("%.1lf",ans3);
		cout<<endl;
		while(q.size()) q.pop();
	}
	return 0;
}

2.P2168 [NOI2015] 荷马史诗

一眼哈夫曼树,可是是\(k\)叉。
其他都没有区别,第一问就是最大深度减一。值得注意的是因为最后一次合并不一定有\(k\)个根节点,所以可能出现这种情况(k=3):
image
显然\(3,4\)号节点应该放上去。

于是我们一开始不停插入权值为\(0\)的节点直到最后一次合并有\(k\)个根节点,因为其他的权值都比\(0\)大,所以\(0\)会在最下面,其他的节点自然就上去了。

CODE:

#include<bits/stdc++.h>
#define int long long
using namespace std;

int ans=0;
int n,k;

struct node{
	int w,deep;
	bool operator<(const node &a)const{
		if(w==a.w) return deep>a.deep;
		return w>a.w;
	}
};

priority_queue<node> q;

signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		int siz;
		cin>>siz;
		node pus;
		pus.deep=1;
		pus.w=siz;
		q.push(pus);
	}
	while((q.size()-1)%(k-1)!=0){
		node pus;
		pus.deep=1;
		pus.w=0;
		q.push(pus);
	}
    while(q.size()>=k){
        int h=0,w=0;
        for(int i=1;i<=k;++i){
            node t=q.top();
			q.pop();
            h=max(h,t.deep);
            w+=t.w;
        }
        ans+=w;
        node pus;
        pus.deep=h+1;
        pus.w=w;
        q.push(pus);
    }
	cout<<ans<<endl<<q.top().deep-1;
	return 0;
}

标签:编码,哈夫曼,int,笔记,学习,权值,节点,pus
From: https://www.cnblogs.com/wangwenhan/p/17654467.html

相关文章

  • H5学习
    什么是H5文章一中总结一句话:只要知道HTML5相比以前最重要的特性,就是增强对移动设备的支持。我们可以用它开发出更符合移动端操作的界面,调用手机的特殊硬件支持。文章二从手机APP角度介绍了H5的概念。......
  • 中间件学习 - Rabbit MQ 概念及特殊MQ实现
    RabbitMQ官方文档介绍RabbitMQ是一个消息队列组件,使用Erlang开发,消息队列中间件是分布式系统中重要的组件,主要解决应用耦合,异步消息,流量削锋等问题安装使用安装Erlang(RabbitMQ基于Erlang开发)Downloads-Erlang/OTP配置Erlang环境erl-version验证安装rabbitMQDownl......
  • MongoDB :第七章:总结一下学习MongoDB的心得
    创建了数据库runoob:userunoobswitchedtodbrunoobdbrunoob查看所有数据库>showdbsadmin0.000GBlocal0.000GB>注意:MongoDB中默认的数据库为test,如果你没有创建新的数据库,集合将存放在test数据库中。在MongoDB中,集合只有在内容插入后才会创建!就是......
  • h5(html5)+css3前端笔记五
    盒子模型网页布局本质网页布局过程先准备好相关的网页元素,网页元素基本都是盒子Box。利用CSS设置好盒子样式,然后摆放到相应位置PS基本操作综合案例圆角边框盒子阴影文字阴影......
  • 华为ENSP学习之设置VLAN间通信
    1、同交换机vlan间通信拓扑图如下:同交换机vlan间通信的关键:为每个vlan设置ip地址步骤:配置pc1和pc2的ip地址配置lsw1的vlan100和200设置vlan100和200的ip地址配置pc1和pc2的网关地址为vlan100和200的ip地址配置lsw1的g0/0/1和g0/0/2端口的连接类型和所属vlan交换......
  • 学习JAVA的第一天:熟悉IDEA结构并新建工程、模块、包、类。
    新建工程、模块、包、类创建模块:新建package包:包的命名也有要求,一般使用公司域名的倒写,如果公司域名是:www.baidu.com,那么包的命名则是:com.baidu.XXXXXX新建类:IDEA快捷输入mainsout编译总结IDEA的结构分为:项目project-模块module-包package-类class。项目proj......
  • git学习记录
    git推荐学习网址图解git推荐git基本指令的可视化练手网址git配置1.安装git主程序2.创建git总仓库文件,此文件下放置各仓库3.生成公钥ssh-keygen-trsa-C秘钥名然后可以选择公钥文件名。路径:C:\Users\test\.ssh\id_rsa.pub生成成功后,将公钥内容,复制到github的setting里......
  • Selenium 学习笔记
    Selenium学习笔记Selenium框架是时下在Web领域中被使用得最为广泛的自动化测试工具集之一,它能帮助程序员们面向指定的Web前端应用快速地开发出自动化测试用例,且能实现跨各种平台、各种编程语言地在多种浏览器上开展测试工作。除此之外,由于该框架的学习曲线比较平缓,开发测试......
  • Rust语言学习再理解
    利用ChatGPT辅助学习,对初学者懂其晦涩语法很方便usestd::iter::IntoIterator;structMyStruct{data:Vec<u32>}implMyStruct{//Thishasthesamenameas`std::iter::FromIterator::from_iter`fnfrom_iter(iter:implIntoIterator<Item=u32>)->Self......
  • 算法工程师学习运筹学 笔记四 运输问题
    运输问题运输问题是一种特殊的线性规划问题,可以解决如类似把商品从一些产地运往另一些销售地使总运输成本最低的问题。由于其场景特殊性,找到比单纯型法更搞笑简便的算法,这便是研究运输问题的目的所在。下面是运输问题的思维导图 一、运输问题的数学模型对于单一商品的调度运......