最优二叉树
最优二叉树又称哈夫曼(Huffman)树,在编码和决策等方面有着广泛的应用。
相关概念
- 路径:树中两个结点之间所经过的分支,称为它们之间的路径。
- 路径长度:一条路径上的分支数,称为该路径的长度。
- 结点的权:给二叉树中的结点赋一个数,该数称为该结点的权。
- 结点带权路径长度:从根结点到一个结点的路径长度与该结点的权值的乘积,称为该结点的带权路径长度。
- 树的带权路径长度:一棵树中所有叶子结点的带权路径长度之和,称为该树的带权路径长度WPL,WPL的公式如下:
其中,n为树中叶子结点的个数,wi和pi分别为第i个叶子结点的权值和从根结点到该路径的长度。 - 最优二叉树:在具有n个带权叶子结点的所有二叉树中,称带权路径长度WPL最小的二叉树为最优二叉树。
下图所示为3棵具有4个叶子结点的二叉树,叶子结点中的数字表示该叶子结点的权值。这3棵二叉树的带权路径长度分别为48、59和47。从此例可以看出,具有相同叶子结点的不同二叉树,其带权路径长度有着较大的差别。
最优二叉树的构造
在构造二叉树的时候,如果使权值大的叶子结点离根结点近,权值小的叶子结点离根结点远,则能够减小二叉树的带权路径长度。哈夫曼最早根据这个思路提出了构造最优二叉树的算法,称为哈夫曼算法。哈夫曼算法的基本思路如下。
(1)用给定的n个权值(w1,w2,,wn)构造n棵二叉树,每棵二叉树Fi只有一个根结点,其权值为wi,将n棵二叉树放在集合S中。
(2)当S中的二叉树数量大于1时,从中选择根结点权值最小的两棵二叉树,并以它们为左右子树构造一棵新的二叉树,新二叉树根结点的权值为其左右子树根结点权值之和。
(3)从S中删除选择的两棵二叉树,并将新二叉树放到集合S中,继续步骤(2)。
当哈夫曼算法结束时,集合S中只有一棵二叉树,该二叉树就是最优二叉树,也称哈夫曼树。在所有具有权值分别为(w1,w2,,wn)n 个叶子结点的二叉树中,哈夫曼树的带权路径长度最短。
例如,以4个给定权值3、5、7、9构造最优二叉树的过程如下图所示。
初始时,集合S中有4棵只有根结点的二叉树,如下图(a)所示。首先,选择权值最小(分别为3和5)的两棵二叉树构造一棵新二叉树,其根结点的权值为8,并把它放到集合S中,然后删除根结点权值为3和5的两棵二叉树,如下图(b)所示。其次,选择根结点权值为7和8的两棵二叉树构造一个新的二叉树并将其加入集合S,其根结点权值为15,并删除根结点权值为7和8的两棵二叉树,如下图(c)所示。最后,选择根结点权值为9和15的两棵二叉树构造一个新的二叉树并将其加入集合S,其根结点权值为24,并删除根结点权值为9和15的两棵二叉树,如下图(d)所示。
至此,集合S中只有一棵二叉树,该树就是所求的最优二叉树。
最优二叉树的应用
在数据通信系统中,信息是以0、1组成的位流形式进行传送的,所以在传送信息之前需要用0、1串来表示信息,称为对信息进行编码。对信息编码后得到的0、1串的长度称为编码长度。对同一段信息,不同的编码能够得到不同的编码长度,对传输效率有着较大的影响。对信息进行编码可以采用定长编码和不定长编码两种方式。
定长编码就是对每个字符都采用相同长度的二进制位进行编码的方式。例如,对4个字符A、B、C、D,每个字符用两位二进制数即可实现编码,A、B、C、D的编码分别是11、10、01、00。如果要传输的信息是AAABBBCD,则发送方发送的位流为1111111010100100,总的编码长度为16位,这个过程称为编码。接收方收到该位流时,只需要将两个二进制为一组转换成一个字母,就可以得到发送方发送的信息,这个过程称为译码。定长编码的优点是编码及译码的过程比较简单,缺点是当发送信息中各个字符出现的频率差别比较大时,编码的长度较长,传输效率较低。
不定长编码就是对不同的字符采用不同长度的二进制位进行编码的方式。对出现频率较高的字符采用较短的编码,对出现频率较低的字符采用较长的编码,这样能够缩短总的编码长度,进而提高传输效率。例如,对于要传输的信息AAABBBCD,字符A、B的出现频率要高于字符C、D的出现频率,如果分别给A、B、C、D的编码为0、1、01、00,则发送方发送的位流为0001110100,总的编码长度为10位,小于定长编码方式。
但是,当接收方收到0001110100时无法对它进行译码,因为会有多种方式对它进行译码,如,“AAA”,“AD”,“DC”等。这种方式不能保证译码的唯一性,故不能使用。
在变长编码中,如果任意一个字符的编码都不是其他字符编码的前缀,则这种编码称为前缀编码。前缀编码能够保证译码的唯一性。如对A、B、C、D的编码为0、10、110、111,则每个字符的编码都不是其他字符编码的前缀,故是前缀编码。如对A、B、C、D的编码为0、1、01、00,则A的编码是C和D的前缀,故不是前缀编码。
可以利用二叉树设计前缀编码。具体过程如下:以需要编码的字符为叶子结点,构造一棵二叉树,然后给二叉树的所有结点分支加上标记,结点的左分支标记为0,右分支标记为1,从根结点到一个叶子结点的路径上所有分支上的标记按顺序组成的二进制串就构成了该叶子结点的编码。
例如,对于A、B、C、D4个字符,可以构造两棵二叉树,如图6-22所示。根据下图(a),4个字符A、B、C、D的编码分别为00、01、10、11。根据下图(b),4个字符A、B、C、D的编码分别为0、10、110、111。这两种编码均属于前缀编码。
一个信息中有n个字符,出现的概率分别为(p1,p2,,pn),其编码长度分别为(k1,k2,,kn),则该信息的平均编码长度可以用如下公式计算。
例如,对于给定的信息AAABBBCD,4个字符A、B、C、D的出现概率分别为0.375、0.375、0.125、0.125。如果使用上图(a)的编码,则平均编码长度为
如果使用上图(b)的编码,则平均编码长度为
对于给定的一个信息,平均编码长度小则传输效率高,反之则低。
对于一种给定的编码,如果把各字符的出现概率看做其权值,则一个信息的平均编码长度就是该二叉树的带权路径长度。
对于给定权值且只有n个叶子结点的二叉树,哈夫曼树的带权路径长度最短。给定一个信息,以其中各字符的出现概率为其权值,建立哈夫曼树并设计编码,则能够得到最短的平均编码长度,利用哈夫曼树设计的编码称为哈夫曼编码。
设计哈夫曼编码的步骤如下。
- 统计每个字符的出现概率,以出现概率作为各字符的权值,建立一棵哈夫曼树。
- 给哈夫曼的分支做标记,结点的左分支标记为0,右分支标记为1。
- 记录编码,从根结点到各叶子结点的路径上的标记按顺序组成的二进制串就是相应字符的编码。