一、【实验目的及要求】

  1. 理解Huffman树的概念及其存储结构;
  2. 熟悉Huffman树的构造;
  3. 掌握Huffman树的编码方法。

二、实验内容】

1、代码实现Huffman编码

2、请统计每个字符出现的频率,构造Huffman树的逻辑结构图(即结点-连线图)。

3、列出每个字符的Huffman编码。

三、主要问题和解决方案

问题:给出一行字符,判断出现次数并且用Huffman来得出每个字符的编码。

解决:先统计每个字符出现的次数,在进行次数大小的排序,从小到大依次排列,利用HuffmanTree的原理进行树的构造,在运用左0又1的方法进行编码,又次数最大的叶子开始遍历记录编码,直到遍历到根节点停止编码,然后倒序输出编码就是所需要的编码。


代码:

//-------HuffmanTree--------------HuffmanTree--------------HuffmanTree-------
#include<stdio.h>
#include<stdlib.h>//分别为权重 双亲 左孩子 右孩子
typedef struct {int weight;int parent, left, right;
}Node,*HuffmanTree;//记录结点名字和权重
typedef struct code{//用于元素记录权重char id;int time;
}code,*Zcode;//数据排序(冒泡):小→大
//用于给结点排序构造
void Sorting(HuffmanTree& HT, int sum) {//传入数组 和 数据个数int temp;int i = 0;for (int m = 0; m < sum; m++) {for (int j = 0; j < (sum - 1) - m; j++) {if ((HT[i].weight) > (HT[i + 1].weight)) {temp = HT[i].weight;HT[i].weight = HT[i+1].weight;HT[i+1].weight = temp;i++;}else {i++;}}i = 0;}
}//构造HuffmanTree
void structure(HuffmanTree &HT,int sum) {if (sum <= 1) return;//结点需要大于1才能执行下面操作 int s1 = 0, s2 = 1;//用于记录结点集中最小的两个结点 int m = 2 * sum - 1;//哈夫曼树的总结点个数:2n-1,用于限制循环的次数,sum为数据种类个数 HT = (HuffmanTree)malloc((4*m)*sizeof(int));//给每个结点分配内存:权重、双亲、左右孩子 for (int i = 0; i < m; i++) {//所有结点双亲、左右孩子全部初始化为0 HT[i].left = 0;HT[i].right = 0;HT[i].parent = 0;}printf("参考数据随意顺序输入权值:");for (int i = 0; i < sum; i++) {scanf("%d",&HT[i].weight);}for (int i = sum ; i <m; i++) {//>sum用于存储结点,>sum用于存储双亲  Sorting(HT, sum);//排序HT[s1].parent = i;//给第一小的结点的双亲数组赋值下标数据 i HT[s2].parent = i;//第二小的结点双亲跟第一小的一样 HT[i].left = s1;// 记录孩子的下标 HT[i].right = s2;HT[i].weight = HT[s1].weight + HT[s2].weight;//双亲结点的权重为 左孩子权重 + 右孩子权重 HT[s2].weight = HT[i].weight;//将双亲结点的权重加入到排序的集里 s1 += 2;//因为最小的两个结点已经构造完成,所以移动下标,前两个结点作废 s2 += 2;}printf("------------------------------------\n");printf("树构造完成!\n");
}//Huffman编码
void coding(HuffmanTree HT,int sum,char code[100][100]) {//使用二维数组code[][]存储编码 int n = 0;int son, father;//子结点,父结点;for (int i = sum-1; i>=0; i--) {//从最后一个孩子结点开始向上遍历 int start = -1;//二维数组列下标初始化为 -1 son = i;//son记录当前孩子的位置 father = HT[i].parent;//father记录当前孩子的双亲的位置 while (father != 0) {//如果father等于0的话  证明 已经遍历到了根结点 因为根节点的双亲已经初始化为0 所以,当双亲回溯成孩子的时候向上找双亲就会找到 0  start++;//每次循环一次 列下标就会 +1 if (HT[father].left == son)code[n][start] = '0';//如果双亲结点的左孩子坐标等于当前孩子的坐标 那么记录为 0 else code[n][start] = '1';                //否则记录为 1 son = father;        //双亲结点变为孩子结点 继续向上编码 father = HT[father].parent;   //双亲结点的双亲变为双亲结点  继续向上编码 }code[n][start + 1] = '\0';       //每次编码完一个结点都在后面加 \0 作为结束 n++;       //每次编码完一个结点 二维数组就切换到第二行 }code[n][0]='\0';//全部编码完毕后 在二维数组的下一行加入 \0 标记结束 printf("编码完成!\n");
}//将字符数组逆序并且输出全部字符的编码
void coding_print(Zcode A,char code[100][100]) {int line = 0, column = 0;int N = 0, j = 0;int elem=0;for (int i = 0;1;i++) {//找到行数if (code[i][0] == '\0')break;line++;}printf("-----------------------编码如下-----------------------\n");printf("\t\t**********************\n");printf("\t\t** 注意:'!'代表空格 **\n");printf("\t\t**********************\n");while (N<line) {while (1) {if (code[N][j] == '\0')break;//找到列数column++;j++;}printf("%c 的编码为: ", A[elem++].id);for (int n = column-1; n>=0; n--) {printf("%c",code[N][n]);}printf("\n");N++;}
}//统计每个字符出现的频率
int statistical(Zcode &A) {int q=-1;int sum = 0;int count = 0;char elem[100];int change;int total=0;printf("------------------------------------------------------\n");printf("输入一行字符: ");gets(elem);for (int i = 0; elem[i] != '\0'; i++){sum = i + 1;}A = (Zcode)malloc((2*sum)*sizeof(code));for (change = 0; change < 26; change++) {for (int j = 0; j < sum; j++) {if (elem[j] == 'A' + change)count++;}if (count != 0) {printf("%c 有 %d 个,频率:%.2f\n", 'A' + change, count, ((float)count / (float)sum));A[++q].id = ('A' + change);A[q].time = count;total++;}count = 0;}for (change = 0; change < 26; change++) {for (int j = 0; j < sum; j++) {if (elem[j] == 'a' + change)count++;}if (count != 0) { printf("%c 有 %d 个,频率:%.2f\n", 'a' + change, count , ((float)count / (float)sum));A[++q].id = ('a' + change);A[q].time = count;total++;}count = 0;}for (int j = 0; j < sum; j++) {if (elem[j] == ' ')count++;}if (count != 0) { printf("空格有 %d 个,频率:%.2f\n", count, ((float)count / (float)sum));A[++q].id ='!';A[q].time = count;total++;}count = 0;printf("------------------------------------------------------\n");printf("一共有 %d 种字符\n", total);printf("---------------------贪心算法运行---------------------\n");return total;
}//排序:大→小
void bigGOsmall(Zcode &A,int sum) {int temp_id;int temp_time;int i = 0;for (int m = 0; m < sum; m++) {for (int j = 0; j < (sum - 1) - m; j++) {if ((A[i].time) < (A[i + 1].time)) {temp_time = A[i].time;temp_id = A[i].id;A[i].time = A[i + 1].time;A[i].id = A[i + 1].id;A[i + 1].time = temp_time;A[i + 1].id = temp_id;i++;}else {i++;}}i = 0;}
}int main() {HuffmanTree HT;Zcode A;char code[100][100];int total;total=statistical(A);//输入一行字符,得到频率,总字符种类数structure(HT, total);//输入权值,构造哈夫曼树coding(HT, total,code);//得出哈夫曼编码(倒序)bigGOsmall(A, total);coding_print(A, code);//输出哈夫曼编码(正序)return 0;
}
//-------HuffmanTree--------------HuffmanTree--------------HuffmanTree-------

运行结果:


由于不熟练指针数组的运用,所有在程序上定义了char code[100][100]的数组来存储字符编码,浪费了多余的内存,以及运行更大的数据会导致内存分配不足,发生错误的情况,程序不够灵活。

由于定义了单单定义了char code[100][100]的字符数组,存入编码后还需要进行倒序输出,需要在写多一个倒叙程序,延长了运行时间!

因为是课堂布置的作业,对该知识的运用还不够熟练。

如代码有误,请各位老师指出,谢谢各位老师啦!

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

  1. 哈夫曼树 构造,编码 完整代码

    Haffman Tree 构造方法: 1.初始化每个叶子结点都是一棵树. 2.找最小权值的两棵树. 3.合并两树,生成新结点. 编码: 1.往左为1,右为0. 2.不等长编码. #include< ...

  2. c语言哈夫曼树构造代码

    c语言哈夫曼树构造代码 博主就很掘的一个人,最近学哈夫曼树,想着用指针去实现,觉得用指针实现,内存消耗会更少,写到后面发现越来与麻烦,且内存开销并没有减少,于是还是使用结构体数组中规中矩的去实现哈夫曼 ...

  3. 【数据结构】基于c++的哈夫曼树构造、编码、译码算法实现

    创建哈夫曼树的描述: 数据结构: 数据的逻辑结构是树状结构:采用静态的三叉链表存放. 算法思想: 1.先把三叉链表中N个元素进行初始化,存放叶子节点,他们都没有孩子和双亲. 2.再初始化后n-1个非叶 ...

  4. 哈夫曼树构造算法的实现

    先考虑如何存储:既可以链式也可以顺序,但顺序存储结构(数组)简单点 这里用一维结构数组,结构数组是因为我们要保存的结点的值比较多,先看结点的类型定义 那几个值?每一个都要知道他的权值weight是多少 ...

  5. C语言哈夫曼树压缩/解压器

    C语言哈夫曼树压缩/解压器 小编是大一的菜鸡,这个题目是数据结构的一个实验题,为了完成这个作业,查找了各种资料,借鉴了很多人的代码,前后折腾了三天左右.代码可能跟网上的不一样,大佬路过请不要踩我. 温 ...

  6. 哈夫曼树构造以及代码实现

    哈夫曼树构造以及代码实现 什么是哈夫曼树 理解哈夫曼树 哈夫曼树的构造 哈夫曼树构造-代码实现 什么是哈夫曼树 构造一颗二叉树,该树的带权路径长度达到最小,称为最优二叉树,也称为哈夫曼树(Huffma ...

  7. 哈夫曼树构造哈夫曼编码

    在传输文字时,经常要将文字转换成二进制字符串.所以我们希望编码最短,但是又想保证它的唯一性.哈夫曼树具有最小带权路径长度,用来实现编码就可以编码最短,所以用哈夫曼树来构造编码.而前缀编码就可以保证在解 ...

  8. 算法学习笔记10——应用哈夫曼树构造最短的不等长编码方案

    内容: (1)设需要编码的字符集为{d1, d2, -, dn},它们出现的频率为{w1, w2, -, wn},应用哈夫曼树构造最短的不等长编码方案. 提示: 哈夫曼树(Huffman Tree), ...

  9. 哈夫曼树构造算法的正确性证明

    哈夫曼树构造 1.哈夫曼树的定义 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman tree). 2.哈夫曼树的构造 假 ...

最新文章

  1. Webhook与Jenkins自动构建(上)
  2. Android 系统镜像: boot.img kernel.img ramdisk.img system.img userdata.img cache.img recovery.img
  3. android入门学习-天气预报app(一)
  4. leetcode 371. 两整数之和(不用算术运算符实现两个数的加法:按位异或原理)
  5. 缺少using namespace std;
  6. iOS开发之UITableView中计时器的几种实现方式(NSTimer、DispatchSource、CADisplayLink)
  7. 获取场景中指定类的实例
  8. 这么做科研你也能成功!
  9. (转):GOF设计模式趣解(23种设计模式)
  10. 解决Hadoop时no namenode to stop异常或则 是 jps中没有namenode
  11. matlab的otdr仿真,OTDR仿真分析软件
  12. 计算机专业术语大全(中~英文版)
  13. 基于matlab的黑体辐射特性分析,MATLAB 黑体辐射规律的研究
  14. raid5换硬盘显示ready_服务器RAID磁盘坏道修复实战
  15. leet198.打家劫舍
  16. 如何在虚拟机上安装苹果系统(Mac OS)
  17. python的爬虫攻击
  18. Raspberry pi 通过iphone手机访问
  19. ArcPY实现分图斑批量制图
  20. web服务器创建站点,服务器:如何使用IIS建立网站

热门文章

  1. 第三方支付“千万元罚单”与“紧箍咒”齐飞
  2. java里utils写什么_工具篇-Java中一些utils
  3. 【前端】同步异步区别
  4. java模拟电脑体育彩票的随机选号_利用JS来模拟体育彩票选号器
  5. 心看来已不在霆锋身上
  6. Android Cannot execute task: the task has already been executed (a task can be executed only once)
  7. java项目 建文件夹_在Java工程下,用java代码创建文件夹
  8. 实现TDD测试驱动开发
  9. layui 数据表格+分页
  10. scss 是什么?在 Vue.cli 中的安装使用步骤是?有哪几大特性?(gxcw)