基本介绍:
H u f f m a n Huffman Huffman树是一种树结构,它的出现是为了解决根据字符出现频率对字符进行“不等长编码”的问题,提高编码效率。“不等长编码”需要满足任何一个字符的编码不能是另外一个字符编码的前缀,否则将产生二义性。为了使最终的编码长度最短,所以出现了 H u f f m a n Huffman Huffman树。
性质特点(以二叉 H u f f m a n Huffman Huffman树为例):
1.树的叶子节点表示字符,节点的权值表示字符在字符串中出现的次数。
2.二叉树的左右分支的边分别表示
0
0
0和
1
1
1,最终某个字符的编码就是根节点到叶子节点的路径。(原理同字典树)
3.对于带权二叉树,某节点的带权路径长度为
w
[
i
]
×
l
[
i
]
w[i] \times l[i]
w[i]×l[i],
w
[
i
]
w[i]
w[i]表示权值,
l
[
i
]
l[i]
l[i]表示路径长度。其带权路径长度定义为树中所有叶节点的带权路径长度之和,即
∑
w
[
i
]
×
l
[
i
]
\sum w[i] \times l[i]
∑w[i]×l[i]。
4.所以最终经过编码的字符串的长度就是带权二叉树的带权路径长度即
∑
w
[
i
]
×
l
[
i
]
\sum w[i] \times l[i]
∑w[i]×l[i]。
5.可以证明当二叉树是一棵完全二叉树的时候带权二叉树的带权路径长度最小,对于
H
u
f
f
m
a
n
Huffman
Huffman树,即经过
H
u
f
f
m
a
n
Huffman
Huffman树编码的字符串长度最小。
构造方法:
1.根据给定的
n
n
n个
w
[
i
]
w[i]
w[i],构造
n
n
n个二叉树的集合,其中每棵二叉树只含一个权值为
w
[
i
]
w[i]
w[i]的根节点,其左、右子树为空树。
2.在所有二叉树中选择根节点权值最小的两棵二叉树,分别作为左、右子树构造一个新的二叉树,新二叉树的根节点权值即为其左、右子树根节点的权值之和。
3.从二叉树集合中删去,并加入刚生成的新树。
4.重复过程
2
2
2,
3
3
3,直到集合中只剩一棵树。
核心代码:
typedef long long ll;
const ll maxn=100010;
struct node
{
ll data;
ll lchild,rchild;
ll pos;
bool operator>(const node a)const
{
return data>a.data;
}
}tree[maxn],num[maxn];
priority_queue<node,vector<node>,greater<node> > q;//利用优先队列维护一个data递增的序列
ll w[maxn];
void createhuffmantree(ll n)
{
for(ll i=1;i<=n;i++)//初始化
{
tree[i].pos=i;
tree[i].data=w[i];
tree[i].lchild=tree[i].rchild=0;
q.push(tree[i]);
}
ll t=n;//可用的位置
for(ll i=2;i<=n;i++)
{
node x,y;
x=q.top();q.pop();
y=q.top();q.pop();
++t;
//构造新树
tree[t].data=x.data+y.data;
tree[t].pos=t;
tree[t].lchild=x.pos;
tree[t].rchild=y.pos;
q.push(tree[t]);
}
}