前言
哈夫曼编码是根据一段数据的成员的占比,来对其编码,频率高的成员编码应该尽量短,这样整体所占的内存就比固定长度编码要小。
字母 | A | B | C | D | E |
---|---|---|---|---|---|
普通编码 | 000 | 001 | 010 | 011 | 100 |
那么一个长度为N的字符串,仅由ABCDE组成,进行编码,则占用3N位空间大小。
哈夫曼树
假如一个长度为26的字符串中,A有2个,B有3个,C有6个,D有7个,E有8个。
(1)首先找到出现频率最小的,即A和B,将它们作为一个新的结点AB的左右孩子,频率小的作为左孩子,大的作为右孩子。新的结点AB则包含A和B,出现的频率为5。
(2)现在频率最小的是AB和C,它们再组成一个子树,新结点ABC的频率为11。
(3)当前各部分的频率分别为ABC(11)、D(7)、E(8),因此D和E组成新的子树,新结点DE的频率为15。
(4)最后ABC和DE组成哈夫曼树,ABC为左子树,DE为右子树。
(5)将树的左分支权值设为0,右分支权值设为1。
哈夫曼编码
我们将从哈夫曼树的树根到叶子所经过的路径作为叶子的编码。
字母 | A | B | C | D | E |
---|---|---|---|---|---|
哈夫曼编码 | 000 | 001 | 01 | 10 | 11 |
普通编码所占用的空间大小:3 × \times × 26 = 78。
哈夫曼编码所占用的空间大小:3 × \times × 2 + 3 × \times × 3 + 2 × \times × 6 + 2 × \times × 7 + 2 × \times × 8 = 57。
减小了27%的存储空间大小。
哈夫曼树的创建
思路:
(1)首先树的创建,应该先定义树的结点;
(2)结点的成员包括此结点的权重weight
,初始化为0;以及该结点的左右孩子,这里以结点在数组中位置表示,亦可以用指针表示,初始化为-1;
(3)为了方便从叶向根遍历,因此需要访问其父节点,因此包括parent
成员,初始化为-1。
class Node
{
public:
int lchild = -1, rchild = -1;
int parent = -1;
int weight = 0;