哈夫曼树的构造
数据类型的定义
typedef struct {
ELMETYPE data;
int weight;
int parent;
int leftchild;
int rightchild;
}HuffNode; //哈夫曼树结构体类型
哈夫曼树的创建
int HuffTreeCreate(HuffNode* ht) {
int i, k, n, min1, min2, lnode, rnode;
// i, k -->后面for循环需要用到的变量
// n-->保存元素的个数
// min1, min2 -->记录树中权值最小的值
// lnode, rnode -->记录左右子树的编码
printf("请输入元素个数\n");
scanf("%d", &n);
printf("元素的个数为:%d\n", n);
for (i = 1; i <= n; i++) { //输入叶子结点的权值
getchar(); //用来吸收上一个scanf留下的\n
printf("第%d个元素的 =>\n\t结点值:",i);
scanf("%c", &ht[i].data);
getchar(); //吸收上面的scanf留下的\n
printf("\t权 重");
scanf("%d", &ht[i].weight);
}
for (i = 1; i <= 2 * n - 1; i++) { //初始化双亲,孩子数组
ht[i].parent = -1;
ht[i].leftchild = -1;
ht[i].rightchild = -1;
}
for (i = n + 1; i <= 2 * n - 1; i++) {
min1 = min2 = 32767; //先将变量赋为最大值
lnode = rnode = 1; //表示都从1下标开始
for (k = 1; k <= i - 1; k++) {
if (ht[k].parent == -1) { //没有父母的结点
if (ht[k].weight < min1) {//小于min1,作为左子树
min2 = min1; //原先的左子树变成右子树
rnode = lnode; //记录该结点的下标
min1 = ht[k].weight;
lnode = k;
}
else if (ht[k].weight < min2) {
min2 = ht[k].weight;
rnode = k;
}
}
}
ht[i].weight = min1 + min2; //将叶子结点的权值相加
ht[i].leftchild = lnode;//记录左右孩子的下标
ht[i].rightchild = rnode;
ht[lnode].parent = i;//孩子结点记录母亲下标
ht[rnode].parent = i;
}
printf("哈夫曼树已成功建立\n");
return n; //最后返回元素个数
}
哈夫曼树的输出
void PrintfHuff(HuffNode* Hf, int index, int level)
{ //index:当前所处结点的索引,初始值为 2*n - 1 ;
//level层级, 一般从第0层开始递增
if (Hf[index].leftchild != -1 || Hf[index].rightchild != -1)
{ //这个if判断当前节点是否有子节点
PrintfHuff(Hf, Hf[index].leftchild,level + 1); //遍历左子树
if (level != 0)
{
for(int i = 0; i < 4 * (level - 1); i++)
{
printf("%s", " ");
}
printf("%s", " ----");
}
printf("o \n");
PrintfHuff(Hf, Hf[index].rightchild, level+1);
}
else
{
if (level != 0)
{
for (int i = 0; i < 4 * (level - 1); i++)
{
printf("%s", " ");
}
printf("%s", " ---");
}
printf("%c \n", Hf[index].data);
}
}
哈夫曼编码
编码结构体
void Encoding(HuffNode ht[], HuffCode hcd[], int n) {
HuffCode d;
int i;
int k;
int ft; //叶子结点的父亲
int bg; //从叶子结点开始
for (i = 1; i <= n; i++)
{
d.start = n + 1;//即叶子结点合起来的结点
bg = i;
ft = ht[i].parent;
while (ft != -1)
{
if (ht[ft].leftchild == bg)
{
d.code[--d.start] = '0';
}
else
{
d.code[--d.start] = '1';
}
bg = ft;
ft = ht[ft].parent;
}
hcd[i] = d;
}
printf("打印哈夫曼树:\n");
for (i = 1; i <= n; i++)
{
printf("%c:", ht[i].data);
for (k = hcd[i].start; k <= n; k++)
{
printf("%c", hcd[i].code[k]);
}
printf("\n");
}
}
全部代码和主函数测试
#include<stdio.h>
#include<malloc.h>
#define MAXSIZE 30
typedef char ELMETYPE;
typedef struct {
ELMETYPE data;
int weight;
int parent;
int leftchild;
int rightchild;
}HuffNode;
typedef struct {
ELMETYPE code[MAXSIZE];
int start;//编码的起始位置
}HuffCode;
int HuffTreeCreate(HuffNode* ht) {
int i, k, n, min1, min2, lnode, rnode;
// i, k -->后面for循环需要用到的变量
// n-->保存元素的个数
// min1, min2 -->记录树中权值最小的值
// lnode, rnode -->记录左右子树的编码
printf("请输入元素个数\n");
scanf("%d", &n);
printf("元素的个数为:%d\n", n);
for (i = 1; i <= n; i++) { //输入叶子结点的权值
getchar();
printf("第%d个元素的 =>\n\t结点值:",i);
scanf("%c", &ht[i].data);
getchar();
printf("\t权 重:");
scanf("%d", &ht[i].weight);
}
for (i = 1; i <= 2 * n - 1; i++) { //初始化双亲,孩子数组
ht[i].parent = -1;
ht[i].leftchild = -1;
ht[i].rightchild = -1;
}
for (i = n + 1; i <= 2 * n - 1; i++) {
min1 = min2 = 32767; //先将变量赋为最大值
lnode = rnode = 1; //表示都从1下标开始
for (k = 1; k <= i - 1; k++) {
if (ht[k].parent == -1) { //没有父母的结点
if (ht[k].weight < min1) {//小于min1,作为左子树
min2 = min1; //原先的左子树变成右子树
rnode = lnode; //记录该结点的下标
min1 = ht[k].weight;
lnode = k;
}
else if (ht[k].weight < min2) {
min2 = ht[k].weight;
rnode = k;
}
}
}
ht[i].weight = min1 + min2; //将叶子结点的权值相加
ht[i].leftchild = lnode;//记录左右孩子的下标
ht[i].rightchild = rnode;
ht[lnode].parent = i;//孩子结点记录母亲下标
ht[rnode].parent = i;
}
printf("哈夫曼树已成功建立\n");
return n;
}
void PrintfHuff(HuffNode* Hf, int index, int level)
{ //index:初始值为 2*n - 1 ; level层级, 一般从第0层开始
if (Hf[index].leftchild != -1 || Hf[index].rightchild != -1)
{
PrintfHuff(Hf, Hf[index].leftchild, level + 1);
if (level != 0)
{
for(int i = 0; i < 4 * (level - 1); i++)
{
printf("%s", " ");
}
printf("%s", " ----");
}
printf("o \n");
PrintfHuff(Hf, Hf[index].rightchild, level+1);
}
else
{
if (level != 0)
{
for (int i = 0; i < 4 * (level - 1); i++)
{
printf("%s", " ");
}
printf("%s", " ---");
}
printf("%c \n", Hf[index].data);
}
}
void Encoding(HuffNode ht[], HuffCode hcd[], int n) {
HuffCode d;
int i;
int k;
int ft; //叶子结点的父亲
int bg; //从叶子结点开始
for (i = 1; i <= n; i++)
{
d.start = n + 1;//即叶子结点合起来的结点
bg = i;
ft = ht[i].parent;
while (ft != -1)
{
if (ht[ft].leftchild == bg)
{
d.code[--d.start] = '0';
}
else
{
d.code[--d.start] = '1';
}
bg = ft;
ft = ht[ft].parent;
}
hcd[i] = d;
}
printf("打印哈夫曼树:\n");
for (i = 1; i <= n; i++)
{
printf("%c:", ht[i].data);
for (k = hcd[i].start; k <= n; k++)
{
printf("%c", hcd[i].code[k]);
}
printf("\n");
}
}
int main()
{
HuffNode ht[MAXSIZE];
HuffCode hcd[MAXSIZE];
int n = HuffTreeCreate(ht);
PrintfHuff(ht, 2*n-1, 0);
Encoding(ht, hcd, n);
}