【SSL 1407】哈夫曼树(一)【树】

在这里插入图片描述


哈弗曼编码

在这里插入图片描述
在这里插入图片描述
H u f f m a n Huffman Huffman编码是一种无损压缩编码方案。
思想:根据源字符出现的(估算)概率对字符编码,概率高的字符使用较短的编码,概率低的字符使用较长的编码,从而使得编码后的字符串长度期望最小。

H u f f m a n Huffman Huffman是一种贪心算法:每次总选择两个最小概率字符结点合并。称字符出现的次数为频数,则概率等于频数处于字符串总长;因此,频率可以用频数替代。

PS:一个文本,统计出 A , B , C , D , E A,B,C,D,E A,B,C,D,E,出现次数为 15 , 7 , 6 , 6 , 5 15,7,6,6,5 157665

根据上面定义,每次贪心选择最小的两个,如图:
在这里插入图片描述
最优Huffman编码为

A:0 B:100 C:101 D:110 E:111


哈夫曼树

在这里插入图片描述
在这里插入图片描述
如何构造最优叶子二叉树?

H u f f m a n Huffman Huffman给出了一个简单而又漂亮的算法,这个算法称为哈夫曼算法。它的基本思想是要让权大的叶子离根最近。具体作法是:
   (1)根据给定的n个权值{w1,w2,…,wn},构造n棵二叉树的集合F={T1,T2,…,Tn},其中每棵二叉树中均只含一个带权值为wi的根结点,其左、右子树为空树;
   (2)在F中选取其根结点的权值为最小的两棵二叉树,分别作为左、右子树构造一棵新的二叉树,并置这棵新的二叉树根结点的权值为其左、右子树根结点的权值之和;
   (3)从F中删去这两棵树,同时加入刚生成的新树;
   (4)重复(2)和(3)两步,直到F中只含一棵树为止。

从上述算法中可以看出,F实际上是森林,该算法的思想是不断地进行森林F中的二叉树的“合并”,最终得到哈夫曼树。

实际上,哈夫曼算法的实现与实际问题所采用的存储结构有关。现假设用数组F来存储哈夫曼树,其中第i个数组元素 F [ i ] F[i] F[i]是哈夫曼树中的一个结点,其地址为i,有3个域,Data域存放该结点的权值, l C h i l d lChild lChild域和 r C h i l d rChild rChild域分别存放该结点左、右子树的根结点的地址(下标)。在初始状态下: F [ i ] . D a t a = W i , F [ i ] . l C h i l d = F [ i ] . r C h i l d = 0 , i = 1 , 2 , … , n F[i].Data=Wi,F[i].lChild=F[i].rChild=0,i=1,2,…,n F[i].Data=WiF[i].lChild=F[i].rChild=0i=1,2,,n

即先构造了n个方形叶子。在以后每步构造一棵新二叉树时,都需要对森林中所有二叉树的根结点进行排序,因此可用数组 a a a作为排序暂存空间,其中第i个数组元素 a [ i ] a[i] a[i]是森林F中第i棵二叉树的根结点,有2个域, D a t a Data Data是根结点所对应的权值, A d d r Addr Addr是根结点在 F F F中的地址(下标)。


代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;

int n;

struct c{
	int x,p;
	int ls,rs;
}f[100010],a[100010];

void out(int t,string s)//中序遍历,s是编码
{
	if(f[t].x==0)return;
	out(f[t].ls,s+'0');//往左儿子的编码为0
	if(f[t].ls==0&&f[t].rs==0)//叶子结点就是插入的数
	{
		printf("%d:",f[t].x);
		cout<<s<<endl;	
	}
	out(f[t].rs,s+'1');//往右儿子的编码为0
}

bool cmp(c l,c r)
{
	if(l.x==r.x)return l.p<r.p;//快排不稳定,要多加一个下标的关键字
	return l.x<r.x;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i].x);
		f[i].x=a[i].x,f[i].ls=0,f[i].rs=0;
		a[i].p=i;
	}
	int i=n,t=n;
	while(i>1)
	{
		sort(a+1,a+i+1,cmp);
		f[++t].x=a[1].x+a[2].x;
		f[t].ls=a[1].p,f[t].rs=a[2].p;
		a[1].x=f[t].x,a[1].p=t;
		a[2].x=a[i].x,a[2].p=a[i].p;
		i--;
	}
	out(t,"");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值