采用C++实现哈夫曼树的创建并输出哈夫曼编码
一、问题源自一道信息论的作业题:
二、完整代码如下 1 #include <iostream>
#include <string>
#include <deque>
#include <algorithm>
using namespace std;
struct Node{
Node *parent, *lchild, *rchild;
pair<float, string> value;
};
class Tree{
public:
int max;
deque<pair<float, string>> leafs; //存放所有叶子
Node *root;
void hfTree(); //将所有叶子组合成哈夫曼树
Tree(deque<pair<float, string>>); //构造函数
bool findLeaf(const pair<float, string> &); //查找叶子
bool deleteLeaf(const pair<float, string> &); //删除叶子
void sortLeafs();
};
//重载pair的加法运算
pair<float, string> operator+(pair<float, string> pr1, pair<float, string> pr2){
return pair<float, string>(pr1.first + pr2.first, pr1.second + pr2.second);
}
//Tree的构造函数
Tree::Tree(deque<pair<float, string>> lf){
int count = ;
for (deque<pair<float, string>>::iterator it = lf.begin(); it != lf.end(); it++){
this->leafs.push_front(*it);
count++;
}
this->max = count;
this->root = NULL;
} //根据键值对判断是否存在该叶子
bool Tree::findLeaf(const pair<float, string> &pr){
for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++){
if ((*it) == pr){
return true;
}
}
return false;
}
//根据键值对删除一个叶子
bool Tree::deleteLeaf(const pair<float, string> &pr){
for (deque<pair<float, string>>::iterator it = this->leafs.begin(); it != this->leafs.end(); it++){
if ((*it) == pr){
pair<float, string> temp = this->leafs.back();
while (temp != (*it)){
this->leafs.pop_back();
this->leafs.push_front(temp);
temp = this->leafs.back();
}
this->leafs.pop_back();
return true;
}
}
return false;
}
//删除deque<Node*>中的一个元素
void deleteNode(deque<Node *> &temp, const pair<float, string> &pr){
for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++){
if ((*it)->value == pr){
Node *nd = temp.back();
while (nd->value != pr){
temp.pop_back();
temp.push_front(nd);
nd = temp.back();
}
temp.pop_back();
return;
}
}
}
//根据键值对找到节点并返回其地址
Node *findNode(deque<Node *> &temp, const pair<float, string> &pr){
for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++){
if ((*it)->value == pr){
return *it;
}
}
return NULL;
}
bool isIn(deque<Node *> &temp, const pair<float, string> &pr){
for (deque<Node *>::iterator it = temp.begin(); it != temp.end(); it++){
if ((*it)->value == pr){
return true;
}
}
return false;
}
//根据所存的叶子节点构造哈夫曼树
void Tree::hfTree(){
deque<Node *> temp;
temp.push_front(NULL);
while (this->leafs.begin() != this->leafs.end()){
//对所有叶子排序并取出概率最小的两个叶子节点
this->sortLeafs();
pair<float, string> pr1;
pair<float, string> pr2;
if (this->leafs.back() == this->leafs.front()){//只剩一个叶子了
pr1 = pr2 = this->leafs.front();
this->leafs.pop_front();
}else{
pr1 = this->leafs.front();
this->leafs.pop_front();
pr2 = this->leafs.front();
this->leafs.pop_front();
}
//首次合并,特殊处理
if (temp.front() == NULL){
temp.pop_front();
Node *node = new Node;
if (pr1 == pr2){
node->lchild = node->parent = node->rchild = NULL, node->value = pr1;
}else{
Node *node1 = new Node;
Node *node2 = new Node;
node1->value = pr1, node2->value = pr2, node->value = pr1 + pr2;
node1->lchild = node1->rchild = node2->rchild = node2->lchild = node->parent = NULL;
node1->parent = node2->parent = node, node->lchild = node1, node->rchild = node2;
}
this->leafs.push_front(node->value);
temp.push_front(node);
}else{
Node *node = new Node;
if (pr1 == pr2){//只剩一个节点了而且是被处理过的,表明所有节点处理完毕,直接退出
break;
}else{//新选出的两个节点都是已经处理后得到的根节点
if (isIn(temp, pr1) && isIn(temp, pr2)){
Node *node1 = findNode(temp, pr1);
Node *node2 = findNode(temp, pr2);
node->value = pr1 + pr2;
node->parent = NULL;
node1->parent = node2->parent = node, node->lchild = node1, node->rchild = node2;
this->deleteLeaf(pr1), this->deleteLeaf(pr2), deleteNode(temp, pr1), deleteNode(temp, pr2); //删除选出来的两个节点
this->leafs.push_front(node->value);
}else if (isIn(temp, pr1)){
Node *tp = findNode(temp, pr1);
Node *node2 = new Node;
node2->value = pr2, node->value = pr1 + pr2;
node2->rchild = node2->lchild = node->parent = NULL;
node2->parent = tp->parent = node, node->rchild = node2, node->lchild = tp;
this->deleteLeaf(pr1), this->deleteLeaf(pr2); //删除选出来的节点
this->leafs.push_front(node->value), deleteNode(temp, pr1); //将合并的节点放到生成树和原始集合中
}else if (isIn(temp, pr2)){
Node *tp = findNode(temp, pr2);
Node *node1 = new Node;
node1->value = pr1, node->value = pr1 + pr2;
node1->rchild = node1->lchild = node->parent = NULL;
node1->parent = tp->parent = node, node->lchild = node1, node->rchild = tp;
this->deleteLeaf(pr1), this->deleteLeaf(pr2); //删除选出来的节点
this->leafs.push_front(node->value), deleteNode(temp, pr2); //将合并的节点放到生成树和原始集合中
}else{
Node *node1 = new Node;
Node *node2 = new Node;
node->value = pr1 + pr2;
node->parent = NULL;
node1->value = pr1, node2->value = pr2;
node1->parent = node2->parent = node, node->lchild = node1, node->rchild = node2;
node1->lchild = node2->lchild = node1->rchild = node2->rchild = node->parent = NULL;
this->deleteLeaf(pr1), this->deleteLeaf(pr2); //删除选出来的两个节点
this->leafs.push_front(node->value);
}
}
temp.push_front(node);
}
}
this->root = temp.front();
} //前序遍历一棵树
void prelook(Node *root,string str){
if (root != NULL){
if (root->lchild == NULL && root->rchild == NULL){
cout << "weight:\t" << root->value.first << "\tcontent:\t" << root->value.second << "\tcode:\t"<<str<<endl;
}
if (root->lchild != NULL){
str+="";
prelook(root->lchild,str);
str.pop_back();
}
if (root->rchild != NULL){
str+="";
prelook(root->rchild,str);
str.pop_back();
}
}
}
//重载操作符,实现两个集合的笛卡儿积
Tree operator+(Tree tr1, Tree tr2){
deque<pair<float, string>> temp;
for (deque<pair<float, string>>::iterator it1 = tr1.leafs.begin(); it1 != tr1.leafs.end(); it1++){
for (deque<pair<float, string>>::iterator it2 = tr2.leafs.begin(); it2 != tr2.leafs.end(); it2++){
temp.push_back(pair<float, string>((*it1).first * (*it2).first, (*it1).second + (*it2).second));
}
}
return Tree(temp);
}
//对一棵树的叶子节点进行排序
void Tree::sortLeafs(){
sort(this->leafs.begin(), this->leafs.end());
}
int main(){
deque<pair<float, string>> temp;
temp.push_front(pair<float, string>(0.5, "a1"));
temp.push_front(pair<float, string>(0.3, "a2"));
temp.push_front(pair<float, string>(0.2, "a3"));
Tree tr = Tree(temp)+Tree(temp)+Tree(temp);
tr.hfTree();
prelook(tr.root,"");
system("pause");
return ;
}
三、修改源代码第276行可以实现对任意次方笛卡尔积结果的编码,第三问输出结果如下:
//表明只剩一个叶子了
采用C++实现哈夫曼树的创建并输出哈夫曼编码的更多相关文章
- [C++]哈夫曼树(最优满二叉树) / 哈夫曼编码(贪心算法)
一 哈夫曼树 1.1 基本概念 算法思想 贪心算法(以局部最优,谋求全局最优) 适用范围 1 [(约束)可行]:它必须满足问题的约束 2 [局部最优]它是当前步骤中所有可行选择中最佳的局部选择 3 [ ...
- 数据结构之C语言实现哈夫曼树
1.基本概念 a.路径和路径长度 若在一棵树中存在着一个结点序列 k1,k2,……,kj, 使得 ki是ki+1 的双亲(1<=i<j),则称此结点序列是从 k1 到 kj 的路径. 从 ...
- 【算法】赫夫曼树(Huffman)的构建和应用(编码、译码)
参考资料 <算法(java)> — — Robert Sedgewick, Kevin Wayne <数据结构> ...
- 20172332 2017-2018-2 《程序设计与数据结构》Java哈夫曼编码实验--哈夫曼树的建立,编码与解码
20172332 2017-2018-2 <程序设计与数据结构>Java哈夫曼编码实验--哈夫曼树的建立,编码与解码 哈夫曼树 1.路径和路径长度 在一棵树中,从一个结点往下可以达到的孩子 ...
- java实现哈弗曼树和哈夫曼树压缩
本篇博文将介绍什么是哈夫曼树,并且如何在java语言中构建一棵哈夫曼树,怎么利用哈夫曼树实现对文件的压缩和解压.首先,先来了解下什么哈夫曼树. 一.哈夫曼树 哈夫曼树属于二叉树,即树的结点最多拥有2个 ...
- C++哈夫曼树编码和译码的实现
一.背景介绍: 给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree).哈夫曼树是带权路径长度最短的树,权值较大的 ...
- 哈夫曼树(三)之 Java详解
前面分别通过C和C++实现了哈夫曼树,本章给出哈夫曼树的java版本. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载请注明出处:htt ...
- 哈夫曼树(二)之 C++详解
上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...
- 哈夫曼树(一)之 C语言详解
本章介绍哈夫曼树.和以往一样,本文会先对哈夫曼树的理论知识进行简单介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现:实现的语言虽不同,但是原理如出一辙,选择其中之一进行了解即可.若 ...
随机推荐
- MySQL5.7报错[ERROR] Unix socket lock file is empty /tmp/mysql.sock.lock的解决方法
发现MySQL服务器因系统磁盘写满导致服务停了,清理磁盘后启动服务时无法正常启动,查看localhost.err日志发现如下报错: [ERROR] Unix socket lock file is e ...
- Elasticsearch,Filebeat,Kibana部署,添加图表及elastalert报警
服务端安装 Elasticsearch和Kibana(需要安装openjdk1.8以上) 安装方法:https://www.elastic.co以Ubuntu为例: wget -qO - https: ...
- 论文笔记[Slalom: Fast, Verifiable and Private Execution of Neural Networks in Trusted Hardware]
作者:Florian Tramèr, Dan Boneh [Standford University] [ICLR 2019] Abstract 为保护机器学习中隐私性和数据完整性,通常可以利用可信 ...
- Animate.css动画库,简单的使用,以及源码剖析
animate.css是什么?能做些什么? animate.css是一个css动画库,使用它可以很方便的快捷的实现,我们想要的动画效果,而省去了操作js的麻烦.同时呢,它也是一个开源的库,在GitHu ...
- Nginx之常用基本配置(二)
上一篇我们把nginx的主配置文件结构大概介绍了下,全局配置段比较常用的指令说了一下,http配置段关于http服务器配置指令介绍了下,以及有几个调优的指令,server_name的匹配机制,错误页面 ...
- 设计模式-09装饰模式(Decorator Pattern)
1.模式动机 一般有两种方式可以实现给一个类或对象增加行为: 继承机制:使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法.但是这种方法是 ...
- alibaba开发手册
alibaba开发手册 11.19 强制: 方法参数在定义和传入时,多个参数逗号后边必须加空格. IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 ...
- python复制多层目录下的文件至其他盘符对应的目录中
一.需求 app打包需要打入一些H5进去,以便更快的加载页面.这些H5文件是散落在各个文件夹中的[如下列所示],偶尔各个文件夹还需新增文件,每次新增一个文件,需要改动jenkins上job脚本,比较麻 ...
- 记一次crontab执行和日志生成问题
一.crontab未执行 crontab里面设置定时任务如下: 1 19 * * * /usr/bin/python3 /home/nola/a.py > /home/nola/logs/a_l ...
- crypto-js aes加密解密
安装 npm install crypto-js --save unit.js import CryptoJS from "crypto-js"; //秘钥 const CRYPT ...