c语言遍历huffman编码树,树 - Huffman树的创建与Huffman编码的造成(C语言)

Huffman树的存储结构:结构数组。

Huffman树造成的关键:如何在一堆带权节点中每次选取两个权值最小的节点。

1.哈夫曼树

哈夫曼树又称最优二叉树。它是 n 个带权叶子结点构成的全部二叉树中,带权路径长度 WPL 最小的二叉树。html

以下图为一哈夫曼树示意图。node

07b04733f3322c0550f5822f9678d22e.png

二、构造哈夫曼树

假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w一、w二、…、wn,则哈夫曼树的构造规则为:ios

(1) 将w一、w二、…,wn当作是有n 棵树的森林(每棵树仅有一个结点);数组

(2) 在森林中选出两个根结点的权值最小的树合并,做为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;编码

(3)从森林中删除选取的两棵树,并将新树加入森林;spa

(4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。

.net

如:对 下图中的六个带权叶子结点来构造一棵哈夫曼树,步骤以下:设计

9912be32fd8b8012dac1b8438c3d192d.png

图片来源:点击打开连接指针

下面采用暴力求解的方法构建HuffmanTree和HuffmanCode

完整代码以下:

/* 根据Huffman编码的原理,编写一个程序,在用户输入节点权重的基础上创建他的Huffman编码 */

//解题思路:先构造一棵Huffman树,由此获得的二进制前缀便为Huffman

//因为Huffman树没有度为1的节点,则一棵有着n个节点的Huffman树共有2n-1个节点,设计一个结构数组,存储2n-1个节点的值

//包括权重,父节点、左节点、右节点等

#include

using namespace std;

#define MAX 21

typedef struct

{

char data; //节点值

int weight; //权重

int parent; //父节点下标位置

int left; //左节点

int right; //右节点

} huffnode;

typedef struct

{

char cd[MAX];

int start; //叶节点的Huffman code的起始位置

} huffcode;

int main()

{

huffnode ht[2*MAX];

huffcode hcd[MAX], d;

int i, k , f, l, r, n, c, m1, m2;

cout << "元素个数:";

cin >> n;

for( i = 1; i <= n; i++ )

{

cout << "第" << i << "个元素=>\t节点值:";

cin >> ht[i].data;

cout << "\t\t权重:";

cin >> ht[i].weight;

}

//初始化Huffman叶节点和分支节点

//数组为静态存储空间,其最大的特征为 - 预先分配所需空间

for( i = 1; i <= 2*n-1; i++ )

{

ht[i].parent = ht[i].left = ht[i].right = 0;

}

//构造哈夫曼树

for( i = n+1; i <= 2*n-1; i++ )

{

m1 = m2 = 32767; //m1 - 最小权值,m2 - 次小权值

l = r = 0; //l - 最小权值节点的位置,r - 次小权值节点的位置

for( k = 1; k <= i-1; k++ )

{

if(ht[k].parent == 0)

{

if(ht[k].weight < m1)

{

m2 = m1; //更新最小、次小权值并记录其所在位置

r = l;

m1 = ht[k].weight;

l = k;

}

else if(ht[k].weight < m2)

{

m2 = ht[k].weight;

r = k;

}

}

}

//设置找到的2个子节点的父节点信息

ht[l].parent = i;

ht[r].parent = i;

ht[i].weight = ht[l].weight + ht[r].weight;

ht[i].left = l;

ht[i].right = r;

}

//根据Huffman树求Huffman编码

//注意:因为HuffmanCode的生成过程为自底向上,因此咱们这里采用-倒着存方式

for( i = 1; i <= n; i++ )

{

d.start = n+1; //start - 记录HuffmanCode的起始位置

c = i; //当前叶节点在结构数组中的下标

f = ht[i].parent; //当前叶节点的父节点

while( f != 0) //到达根节点则HuffmanCode创建完毕,循环退出

{

if( ht[f].left == c ) //若当前叶节点的父节点的左指针指向了当前叶节点,则记录0 - 左儿子

d.cd[--d.start] = '0';

else //若当前叶节点的父节点的右指针指向了当前叶节点,则记录1 - 右儿子

d.cd[--d.start] = '1';

c = f; //更新儿子节点(分支节点) - 自叶节点到根节点创建HuffmanCode

f = ht[f].parent; //更新当前儿子节点的父节点 直到根节点为止

}

hcd[i] = d;

}

//输出HuffmanCode

cout << "输出HuffmanCode:\n" ;

for( i = 1; i <= n; i++ )

{

cout << " " << ht[i].data << ": ";

for( k = hcd[i].start; k <= n; k++ )

cout << hcd[i].cd[k];

cout << endl;

}

return 0;

}

运行结果:

bd48eef834064c5349b5135fe6115b3c.png

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值