题目描述

给定n个权值,根据这些权值构造huffman树,并进行huffman编码

参考课本P147算法6.12 HuffmanCoding代码,注意数组访问是从位置1开始

要求:赫夫曼的构建中,默认左孩子权值不大于右孩子权值

输入

第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
依此类推

输出

逐行输出每个权值对应的编码,格式如下:权值-编码
即每行先输出1个权值,再输出一个短划线,再输出对应编码,接着下一行输入下一个权值和编码。
以此类推

输入样例1

1
5 15 4 4 3 2
输出样例1

15-1
4-010
4-011
3-001
2-000

以下是思路

这题分两步想,先是建立赫夫曼树,再对其节点进行编码。

首先是构建节点,没啥特殊的。

class Node
{
public:int left, right;int weight;int parent;
};

其次是树的构建。这里先判断需要哪些成员。这里选择用huftree来存放各个节点;max为最大权(为了后面与其他权值相比较);len为节点个数;lnum为叶子个数;code来存放各个节点的对应编码。

class HufTree
{
public:Node* huftree;int max = 10000;int len;int lnum;string *code;void Init();void Init(int n, int* wei);void SelectMin(int pos, int* s0, int* s1);void Coding();
};

然后开始初始化这些成员,。这里我主函数里用的是一个动态数组*wei来存放各个节点的权值。所以先传进来节点数n和数组wei。同时初始化lnum和len分别为n与2*n-1。再初始化对应的动态数组。

这里可能有人不理解为什么lnum和len的值是这个,其实你自己画个赫夫曼树就明白了。假设有n个节点,就会有n个叶子节点。同时每次都要从这n个节点中选出两个权值最小的来建树,再把这两个节点的权值相加构成一个新的节点再塞回去(即每建一次n都要减1)。那么直到最后只剩下一个根节点和另一个叶子节点时,建树后形成的新节点就是赫夫曼树的根节点(这个节点不用塞回去,所以新生成的节点总数为n-1)。那么总节点的个数就是n+(n-1)即2n-1。

同时还要注意这题要求数组从1开始访问,所以huftree[i].weight = wei[i - 1]而不是huftree[i].weight = wei[i]。

void HufTree::Init(int n, int* wei)
{int i;lnum = n;len = 2 * n - 1;huftree = new Node[2 * n];code = new string[lnum + 1];for (i = 1;i <= n;i++){huftree[i].weight = wei[i - 1];}for (i = 1;i <= len;i++){if (i > n){huftree[i].weight = 0;}huftree[i].parent = 0;huftree[i].left = 0;huftree[i].right = 0;}Init();
}

现在开始建树。为了选出两个权值最小的节点还得写一个 SelectMin。当一个节点权最小且没有父亲节点时,记录该节点的权值与位置。这样下来从1-lnum存放的为叶子节点的权,从lnum+1-len为新生成节点的权,那最后编码也只用对0-lnum这段的节点进行编码。

void HufTree::Init()
{for (int i = lnum + 1;i <= len;i++){int s0, s1;SelectMin(i - 1, &s0, &s1);huftree[s0].parent = huftree[s1].parent = i;huftree[i].left = s0;huftree[i].right = s1;huftree[i].weight = huftree[s0].weight + huftree[s1].weight;}
}
void HufTree::SelectMin(int pos, int* s0, int* s1)
{int w0, w1, i;w0 = w1 = max;*s0 = *s1 = 0;for (i=1;i <= pos;i++){if (w0 > huftree[i].weight && !huftree[i].parent){w1 = w0;*s1 = *s0;w0 = huftree[i].weight;*s0 = i;}else if (w1 > huftree[i].weight && !huftree[i].parent){w1 = huftree[i].weight;*s1 = i;}}
}

树已经构建完了,接下来对各叶子节点进行编码。编码原理为从根节点开始,各个节点的左子树为0,右子树为1。

void HufTree::Coding()
{char* tmp = new char[lnum];;int i, c, f, start;tmp[lnum - 1] = '\0';for (i = 1;i <= lnum;i++){start = lnum - 1;for (c = i, f = huftree[i].parent;f != 0;c = f, f = huftree[f].parent){if (huftree[f].left == c){tmp[--start] = '0';}else{tmp[--start] = '1';}code[i] = tmp[start] + code[i];}}delete[]tmp;
}

code[i] = tmp[start] + code[i]也可以用str.assign(new_str)函数来实现,该函数为用new_str去替换str的值。这里可以理解为从tmp[start]的地址开始一直到tmp结束的所有单个字符拼接并转换为了string类型的字符串再赋给了code[i]。

code[i].assign(&tmp[start]);

以下是代码

#include <iostream>
#include <cstring>
using namespace std;class Node
{
public:int left, right;int weight;int parent;
};class HufTree
{
public:Node* huftree;int max = 10000;int len;int lnum;string *code;void Init();void Init(int n, int* wei);void SelectMin(int pos, int* s0, int* s1);void Coding();
};
void HufTree::Init()
{for (int i = lnum + 1;i <= len;i++){int s0, s1;SelectMin(i - 1, &s0, &s1);huftree[s0].parent = huftree[s1].parent = i;huftree[i].left = s0;huftree[i].right = s1;huftree[i].weight = huftree[s0].weight + huftree[s1].weight;}
}
void HufTree::Init(int n, int* wei)
{int i;lnum = n;len = 2 * n - 1;huftree = new Node[2 * n];code = new string[lnum + 1];for (i = 1;i <= n;i++){huftree[i].weight = wei[i - 1];}for (i = 1;i <= len;i++){if (i > n){huftree[i].weight = 0;}huftree[i].parent = 0;huftree[i].left = 0;huftree[i].right = 0;}Init();
}
void HufTree::SelectMin(int pos, int* s0, int* s1)
{int w0, w1, i;w0 = w1 = max;*s0 = *s1 = 0;for (i=1;i <= pos;i++){if (w0 > huftree[i].weight && !huftree[i].parent){w1 = w0;*s1 = *s0;w0 = huftree[i].weight;*s0 = i;}else if (w1 > huftree[i].weight && !huftree[i].parent){w1 = huftree[i].weight;*s1 = i;}}
}
void HufTree::Coding()
{char* tmp;int i, c, f, start;tmp = new char[lnum];tmp[lnum - 1] = '\0';for (i = 1;i <= lnum;i++){start = lnum - 1;for (c = i, f = huftree[i].parent;f != 0;c = f, f = huftree[f].parent){if (huftree[f].left == c){tmp[--start] = '0';}else{tmp[--start] = '1';}code[i].assign(&tmp[start]);}}delete[]tmp;
}
int main()
{int t;cin >> t;while (t--){int n;cin >> n;int* weight = new int[n];for (int i = 0;i < n;i++){cin >> weight[i];}HufTree tree;tree.Init(n, weight);tree.Coding();for (int i = 1;i <= n;i++){cout << tree.huftree[i].weight << "-";cout << tree.code[i] << endl;}delete[]weight;}
}

【id:179】【20分】C. DS二叉树--赫夫曼树的构建与编码(不含代码框架)相关推荐

  1. 【id:180】【20分】D. DS二叉树--赫夫曼树解码(不含代码框架)

    题目描述 已知赫夫曼编码算法和程序,在此基础上进行赫夫曼解码 在赫夫曼树的类定义中增加了一个公有方法: int  Decode(const string codestr, char txtstr[]) ...

  2. 算法学习之最优二叉树(赫夫曼树)

    概念 给定n个权值作为n个叶子节点,构造一颗二叉树,若该数的代全路径长度(wpl)达到最小,称这样的的二叉树为最优二叉树,也成霍夫曼树 霍夫曼树是带权路径长度最短的树,权值较大的节点离根较近 路径和路 ...

  3. 6.6.1最优二叉树(赫夫曼树)

    首先我们来看一个伪代码.这个是代表成绩的等级. 然后我们知道,每一次高考,学生的成绩分布应该接近某个比例,现在我们假如分别规律如下: 为此可以作出下面的这个树. 我们发现,概率分布主要是在70-79, ...

  4. 最优二叉树(赫夫曼树)

    赫夫曼树的介绍(写的不好地方大佬请指教) 最优二叉树又称哈夫曼树,是带权路径最短的二叉树.根据节点的个数,权值的不同,最优二叉树的形状也不同. 图 6-34 是 3 棵最优二叉树的例子,它们共同的特点 ...

  5. 【数据结构】赫夫曼树与赫夫曼编码(可执行完整代码)

    赫夫曼编码对文件进行压缩与解密 理论 赫夫曼树 赫夫曼编码 应用 应用源码 运行结果截图 理论 赫夫曼树 先有赫夫曼树,才有赫夫曼编码.所以,首先简单介绍一下什么是赫夫曼树. 假设一共五个叶子节点,分 ...

  6. 一文了解赫夫曼树的构建与赫夫曼编码

    文章目录 一.赫夫曼树 基本介绍 赫夫曼树几个重要概念和举例说明 赫夫曼树创建步骤图解 代码构建赫夫曼树 二.赫夫曼编码 1基本介绍 通信领域中的信息的处理方式1-定长编码 通信领域中的信息的处理方式 ...

  7. 数据结构Java06【赫夫曼树、概述、原理分析、代码实现(数据压缩、创建编码表、解码、压缩文件、解压文件)】

    学习地址:[数据结构与算法基础-java版]                  

  8. 赫夫曼树 和 赫夫曼树编码

    赫夫曼树 代码在:github.com 赫夫曼(Huffman)树,又称最优树,是一类带权路径长度最短的树. 树的路径和路径长度:从树中一个节点到另一个节点之间的分支构成这两个节点之间的路径,路径上的 ...

  9. 算法系列之赫夫曼树的精解【构造流程及原理分析】

    赫夫曼树又称为最优树.最优二叉树 赫夫曼树百度百科 https://baike.baidu.com/item/%E5%93%88%E5%A4%AB%E6%9B%BC%E6%A0%91/2305769? ...

最新文章

  1. autorelease什么时候释放_乌龟的天性是什么,饲养中要释放龟的天性吗?
  2. 2D图片3秒变立体,变换视角流畅自然:Adobe实习生的智能景深算法,登上顶级期刊...
  3. struts2中result的type跳转类型总结
  4. pat乙级相当于什么水平_林书豪在CBA相当于什么水平的外援?
  5. PHP建立和删除目录
  6. LeetCode算法入门- Compare Version Numbers -day14
  7. ModuleNotFoundError No module named urllib2
  8. CentOS设置网卡成DHCP动态获取IP
  9. 压缩包安装_SPSS 21 下载(内附压缩包及安装过程)
  10. Linux网络编程--socket
  11. 优化器,sgd,adam等
  12. 天龙八部linux 换win,Linux从菜鸟到大师之天龙八部 第三部文本编辑处理.doc
  13. 传感器融合sensor fusion
  14. et99php,加密锁/加密狗ET199(包含网络锁功能)
  15. 删除bootcamp后扩充Mac分区
  16. 务器性能变慢 c盘temp文件夹存在大量sess开头文件的问题原因
  17. 深度图+灰度图 可视化判断灰度图区域是否有深度
  18. JDOM解析xml文件
  19. Switch中的参数
  20. MacBook Air M1硬盘写入量查询

热门文章

  1. PIX学习路径-1-选择PIXHAWK作为飞控学习的起点
  2. 架构:常用的三种架构模式
  3. 必读论文 | 云机器人必读论文10篇
  4. Xilinx vivado 常用IP核使用
  5. 天秤座 的个人分析,真的很准,这段时间一直在关注星座。
  6. 港湾公园 Haven Park for Mac(好玩的探索建造冒险游戏)
  7. Rebus渲染农场分析
  8. linux如何编写crontab定时脚本,linux下编写定时任务crontab
  9. 怎么搜索到最新最全的热点新闻资讯呢?有这四个工具就够了
  10. 烧录flash_烧录固件完成后,配置JFLASH让程序自动运行