目标

给定一组权值,根据权值求其一个哈夫曼树,并通过中序遍历的顺序输出叶子节点的哈夫曼编码。

分析

首先回顾哈夫曼树的求解过程:

  1. 在权值中取最小的两个x,y,以这两个权值为叶子节点,生成一个权值为x+y的父亲节点;
  2. 从权值组中删除x,y,添加x+y进入权值组;
  3. 循环直到权值组仅剩一个元素,该元素为根节点的权值。

一个重要的点是我们希望输入的权值有序,并且时刻保持有序,因此选用链表来存储权重,并每次插入时都按序排序,接下来只要用代码实现上述步骤便可完成哈夫曼树的构建;

那么如何得到叶子节点的哈夫曼编码呢?

考虑使用递归为每个节点都分配一个编码,储存在树节点中。

代码实现

树节点和链表节点的定义与初始化

struct node
{int weight, idx;struct node *parent, *lchild, *rchild;char *code;
};struct linknode
{int info;struct linknode *next;struct node *tree;
};
typedef struct linknode *Plink;
typedef struct node *Ptree;Ptree createNULLtree()
{Ptree head = (Ptree)malloc(sizeof(struct node));if (head == NULL)printf("fail to create tree node!\n");head->parent = NULL;head->lchild = NULL;head->rchild = NULL;head->idx = 0;head->code = (char *)malloc(sizeof(char) * 10);return head;
}Plink createNULLlink()
{Plink head = (Plink)malloc(sizeof(struct linknode));if (head == NULL)printf("fail to create link node!\n");head->next = NULL;head->tree = NULL;return head;
}

树节点中包含指向父亲节点和孩子节点的指针、权值、以及储存着编码的code和编码长度索引idx;

链表节点中包含权值大小info、指向下个节点的next指针以及指向权值对应树节点的tree指针。

一些工具函数

void insertwithorder(Plink head, int x, Ptree tree)
{Plink cur = head->next, last = head;if (tree == NULL)tree = createNULLtree();tree->weight = x;while (cur != NULL){if (x <= cur->info){last->next = createNULLlink();last->next->info = x;last->next->tree = tree;last->next->next = cur;return;}last = cur;cur = cur->next;}last->next = createNULLlink();last->next->info = x;last->next->tree = tree;last->next->next = cur;
}

将数据有序插入链表,小数据在前,插入和删除都比较方便

int is_over(Plink head)
{if (head->next->next == NULL)return 1;return 0;
}

判断是否应该结束程序,当链表中仅剩一个数据时结束

void LDR(Ptree head)
{if (head == NULL)return;LDR(head->lchild);visitleaf(head);LDR(head->rchild);
}

中序遍历

void visitleaf(Ptree head)
{if (head->lchild == NULL && head->rchild == NULL)printf("%d %s\n", head->weight, head->code);
}

只打印叶子节点的信息

生成二叉树

使用两个权值来创建一个二叉树,根节点权值为两权值之和;

实现过程中由于不仅仅需要链表节点的权值信息,所以没有单独使用函数实现这个这个功能;

大致流程如下:

  1. 获得两个权值及它们的树节点;
  2. 生成一个权值为其之和的树节点;
  3. 以新的树节点为父亲节点,连接这三个节点;
  4. 将求和之后的权值再按照顺序插入链表中;
  5. 使用递归,直到链表中仅剩一个元素;
  6. 至此,获得了哈夫曼树的根节点;
void createBiTree(Plink Link)
{if (is_over(Link))return;int nums[2]; //储存两个权值Plink temp = Link->next;Ptree p = createNULLtree(), lch, rch;nums[0] = temp->info;lch = temp->tree;Link->next = temp->next;free(temp);temp = Link->next;nums[1] = temp->info;rch = temp->tree;Link->next = temp->next;free(temp);p->weight = nums[0] + nums[1];p->lchild = lch;p->rchild = rch;lch->weight = nums[0];rch->weight = nums[1];lch->parent = p;rch->parent = p;insertwithorder(Link, p->weight, p);createBiTree(Link);
}

哈夫曼编码

void encode(Ptree head, char info)
{if (head == NULL)return;if (head->parent != NULL){strcpy(head->code, head->parent->code);head->idx = strlen(head->code);}head->code[head->idx++] = info;head->code[head->idx] = '\0';encode(head->lchild, '0');encode(head->rchild, '1');
}

encode函数接收树节点和一个字符变量,左子树接收’0’,右子树接收‘1’,并且每个树节点会copy父亲节点的code信息,如此递归,便完成了编码。

主函数

int main()
{int num, temp;Plink linkhead = createNULLlink();scanf("%d", &num);for (int i = 0; i < num; i++){scanf("%d", &temp);insertwithorder(linkhead, temp, NULL);}createBiTree(linkhead);Ptree treehead = linkhead->next->tree;if (treehead == NULL)printf("wrong!");encode(treehead, '\0');LDR(treehead);return 0;
}

至此便完成了题目要求。

全部代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct node
{int weight, idx;struct node *parent, *lchild, *rchild;char *code;
};struct linknode
{int info;struct linknode *next;struct node *tree;
};
typedef struct linknode *Plink;
typedef struct node *Ptree;Ptree createNULLtree()
{Ptree head = (Ptree)malloc(sizeof(struct node));if (head == NULL)printf("create tree wrongly!\n");head->parent = NULL;head->lchild = NULL;head->rchild = NULL;head->idx = 0;head->code = (char *)malloc(sizeof(char) * 10);return head;
}Plink createNULLlink()
{Plink head = (Plink)malloc(sizeof(struct linknode));if (head == NULL)printf("create link wrongly!\n");head->next = NULL;return head;
}void insertwithorder(Plink head, int x, Ptree tree)
{Plink cur = head->next, last = head;if (tree == NULL)tree = createNULLtree();tree->weight = x;while (cur != NULL){if (x <= cur->info){last->next = createNULLlink();last->next->info = x;last->next->tree = tree;last->next->next = cur;return;}last = cur;cur = cur->next;}last->next = createNULLlink();last->next->info = x;last->next->tree = tree;last->next->next = cur;
}int is_over(Plink head)
{if (head->next->next == NULL)return 1;return 0;
}void createBiTree(Plink Link)
{if (is_over(Link))return;int nums[2];Plink temp = Link->next;Ptree p = createNULLtree(), lch, rch;nums[0] = temp->info;lch = temp->tree;Link->next = temp->next;free(temp);temp = Link->next;nums[1] = temp->info;rch = temp->tree;Link->next = temp->next;free(temp);p->weight = nums[0] + nums[1];p->lchild = lch;p->rchild = rch;lch->weight = nums[0];rch->weight = nums[1];lch->parent = p;rch->parent = p;insertwithorder(Link, p->weight, p);createBiTree(Link);
}void encode(Ptree head, char info)
{if (head == NULL)return;if (head->parent != NULL){strcpy(head->code, head->parent->code);head->idx = strlen(head->code);}head->code[head->idx++] = info;head->code[head->idx] = '\0';encode(head->lchild, '0');encode(head->rchild, '1');
}void visitleaf(Ptree head)
{if (head->lchild == NULL && head->rchild == NULL)printf("%d %s\n", head->weight, head->code);
}void LDR(Ptree head)
{if (head == NULL)return;LDR(head->lchild);visitleaf(head);LDR(head->rchild);
}int main()
{int num, temp;Plink linkhead = createNULLlink();scanf("%d", &num);for (int i = 0; i < num; i++){scanf("%d", &temp);insertwithorder(linkhead, temp, NULL);}createBiTree(linkhead);Ptree treehead = linkhead->next->tree;if (treehead == NULL)printf("wrong!");encode(treehead, '\0');LDR(treehead);return 0;
}

C语言实现哈夫曼树求解及其编码输出相关推荐

  1. C语言:哈夫曼树构造及编码(核心代码每一行都有注释)

    一.[实验目的及要求] 理解Huffman树的概念及其存储结构: 熟悉Huffman树的构造: 掌握Huffman树的编码方法. 二.[实验内容] 1.代码实现Huffman编码 2.请统计每个字符出 ...

  2. huffman树_笃学不倦|c语言构造哈夫曼树哈夫曼编码

    艾薇巴蒂!许久不见甚是想念,想必这"涨姿势"的时刻大家已经期待许久了!今天我们要共同学习的是c语言构造哈夫曼树-哈夫曼编码 构造哈夫曼树 首先,我们需要了解哈夫曼树是什么: 相关知 ...

  3. 赫夫曼编码c语言 排序部分,c语言构造哈夫曼树输出哈夫曼编码出错 ,跪求大神帮我找错...

    c语言构造哈夫曼树输出哈夫曼编码出错 ,跪求大神帮我找错0 youxun0952016.09.07浏览120次分享举报 #include #include #include typedef struc ...

  4. c语言哈夫曼树统计字母频率,C语言实现哈夫曼树

    本文实例为大家分享了C语言实现哈夫曼树的具体代码,供大家参考,具体内容如下 //哈夫曼树C语言实现 #include #include typedef struct HuffmanNode { cha ...

  5. 字符串哈夫曼树C语言,C语言实现哈夫曼树的方法

    本文实例为大家分享了C语言实现哈夫曼树的具体代码,供大家参考,具体内容如下 准备工作: 1.定义一个结构体,表示一个节点.其中,这个结构体有4个成员变量,分别表示是这个节点的权值,父节点及左右子节点的 ...

  6. 霍夫曼树及霍夫曼编码的C语言实现,霍夫曼树及霍夫曼编码的C语言实现

    从周五开始学习霍夫曼树,一直到今天终于完成,期间遇到了各类各样的棘手的问题,经过一遍遍在纸上分析每一步的具体状态得以解决.如今对学习霍夫曼树的过程加以记录web 首先介绍霍夫曼树数组 霍夫曼树(Huf ...

  7. 哈夫曼树带权路径长度c语言,【哈夫曼树】求结点的哈夫曼的带权路径长度

    本文用C++采用顺序存储实现求哈夫曼树(即最小生成树)的带权路径长度 努力 下面来了解一下哈夫曼树的构造以及如何求带权路径长度: 哈夫曼树为带权路径长度最小的树 哈夫曼树 哈夫曼树的顺序存储 [问题描 ...

  8. c语言实现哈夫曼树构造

    c语言实现构造哈夫曼树 输入字符和权值,实现哈夫曼树的构造 #include<stdio.h> #include<string.h> #include<stdlib.h& ...

  9. 赫夫曼树建立c语言源程序编译结果详细解释,c语言构建哈夫曼树(附运行结果图)[本站推荐]...

    #include#include#include int m,s1,s2; typedef struct { unsigned int weight; unsigned int parent,lchi ...

  10. 哈夫曼树编码和译码c语言,C++哈夫曼树编码和译码的实现

    78 /*-----------创建工作---------------------------*/ 79     int s1,s2; 80     for (int i = n + 1; i < ...

最新文章

  1. 混合装置实现了24/7的能量收集和储存
  2. c# 关闭软件 进程 杀死进程
  3. python基础知识填空-Python基础知识(1)
  4. 算法提高课-搜索-最小步数模型-AcWing 1107. 魔板:bfs、复杂、八数码类似的题目
  5. Outlook Express设置方法
  6. 10.31模拟:总结
  7. php面向对象编程代码怎么写,php面向对象编程(一)
  8. [matlab]使用struct创建结构体
  9. 1486mysql,mysql_error.md
  10. java vuehello wotld,Vue Hello World
  11. 告诉你三个实用的换性别特效软件
  12. 计算机vb题库程序代码编写,计算机二级考试.题库-vb程序题
  13. 刘汝佳 《竞赛入门》5.2.2
  14. Canonical 和 DFI 发布第一款 Ubuntu 认证的基于 AMD 的“工业 Pi”
  15. commit节点号 git_Git调整commit之间顺序
  16. RT-Thread Smart上手指南~
  17. 最长公共子序列问题-----题目
  18. 怎么让俩张图片在一行_壁纸文案 | 我们俩不会道别
  19. 团体程序设计天梯赛-练习集 L2-015 互评成绩 (25分)
  20. C4D模型工具—线性切割

热门文章

  1. Nature:分离到一种位于原核生物-真核生物“交界”的古菌
  2. ForkJoinPool api 详解
  3. 微信小程序 表单控件【族谱聚微信小程序表单控件】
  4. Winner-Take-All Autoencoders ( 赢者通吃自编码器)
  5. Neuronink是医学奇迹的噩梦
  6. 红米怎么打开USB调试(Android4.2.2),系统中隐藏开发者选项(红米,MTK6589,三星i9500 /S4打开开发者选项)
  7. 组织的目的是使平凡的人做出不平凡的事 --- 彼得.德鲁克 《卓有成效的管理者》
  8. win10桌面的计算机图标怎么删除,win10电脑桌面图标如何去掉快捷箭头。
  9. 回炉重造之JAVA---枚举
  10. Gephi简单导入数据