树的企业应用-哈夫曼编码树-有趣的数据压缩算法

哈夫曼编码 描述

张三去李四家里,但 李四是一个女生,所以张三找李四去上海迪尼斯玩 …

亚历山大.张三去伊丽莎白.李四家里,但 伊丽莎白.李四是一个女生,所以亚历山大.张三找伊丽莎白.李四去美国迪尼斯玩 …

我们发现 一个关键点 有些重复的也不多 无非就高亮的地方 所以简化一下

声明一下 在上方的引言里 凡是出现高亮的 统统替换为 “张三” and “李四”

张三去李四家里,但 李四是一个女生,所以张三找李四去上海迪尼斯玩 ………

张三去李四家里,但 李四是一个女生,所以张三找李四去美国迪尼斯玩 ………

哈夫曼编码:把字符出现的次数压缩成只有一个

这就是哈夫曼编码 基本描述

哈夫曼编码树原理

字符串为 **"yyds ndd yygq bbq jjz xdxl jj qq wx dy wb bz ww " **

进行压缩变成如下表格:

字符 该字符出现的次数
‘y’ 5
‘d’ 5
‘b’ 4
‘g’ 1
‘q’ 4
‘z’ 2
‘x’ 3
‘j’ 4
‘w’ 4
’ ’ 13

我们使用文本的方式储存这些 字符和出现的频率(注意:此博主比较懒输入,干脆整成一个文件)

input.txt:

y 5 d 5 g 1 q 4 z 2 x 3 j 4 w 4   13

那问题来了 哈夫曼编码树? 这些只是从文件读取到内存里整成了一个顺序表, 而已

我们使用C I/O的函数 来读取 文件 .

回过神来!

能看得出来这些是一体的 所以ndd(你懂的),我们应该定义 全新的数据类型 : Huffman_Code

哈夫曼编码树数据域定义

 struct HuffmanCode{char Val;//数据int weight;//频率}

定义完 先实现读取字符和频率

既然是顺序表 那还得用 统计 input.txt 文件的数据和频率多少个元素


const char* FileName = "input.txt";
const char* OpenMode = "r";
//读取的格式: 数据 空格 权值 空格
const  char* readFormat = "%c %d ";//统计文件中的数据和频率的个数并且通过参数修改
bool  getSize(int& size) {FILE* ReadStream = nullptr;const errno_t  openState = fopen_s(&ReadStream, FileName, OpenMode);bool ret = openState == 0;if (ret) {int i = 0;char ch = getc(ReadStream);ret = ch != EOF;if (ret) {ungetc(ch, ReadStream);HuffmanCodeValue value{};int ReadNum = 0;while (!feof(ReadStream)) {ReadNum = fscanf_s(ReadStream, readFormat, &value.value, sizeof(value.value), &value.weight, sizeof(value.weight));++i;}size = i;}else {cerr << "错误:" << FileName << "里文件为空" << endl;}fclose(ReadStream);ReadStream = nullptr;}else {char error[1024]{};strerror_s(error, errno);cerr << "错误:" << error << endl;}return ret;
}

分配好内存 之后 读取文件中的数据


//获取文件 哈夫曼编码 以及编码的权值
void loadValue(HuffmanCodeValue* value, const int &size) {if (size!=0){FILE* ReadStream = nullptr;const errno_t  openState = fopen_s(&ReadStream, FileName, OpenMode);bool ret = openState == 0;if (ret) {auto First = 0;int ReadNum = 0;char read[alignof(HuffmanCodeValue)+ 1];while (First != size && !feof(ReadStream)) {ReadNum = fscanf_s(ReadStream, readFormat, &value[First].value, sizeof(value[First].value), &value[First].weight, sizeof(value[First].weight));++First;}fclose(ReadStream);//free(ReadStream);ReadStream = nullptr;}}
}

读取完毕后 ,是时候 该设计一些数据结构了(也是,最骚脑的时刻)

哈夫曼编码树的定义

//哈夫曼编码树节点
struct HuffmanCodeTreeNode{HuffmanCode value;//数据HuffmanCodeTreeNode* Parent;//父节点HuffmanCodeTreeNode* LeftChild;//左子节点HuffmanCodeTreeNode* RightChild;//右子节点
};
//哈夫曼编码树
struct HuffmanCodeTree {HuffmanCodeTreeNode* root;//根节点
};

你以为到这里就结束了吗 …

那你就有点小瞧了哈夫曼编码树 还得按照优先级的频率来的

所以 还得吧写好的优先级队列搬出来

#ifndef __PriorityQueue_H__
#define __PriorityQueue_H__
#include"HuffmanTree.h"using Element = HuffmanCodeTreeNode*;
using  PriorityQueueNode = struct _PriorityQueueNode;using  PriorityCompare = bool (*)(const int &, const int &);using PriorityQueueAuxiliary = struct _PriorityQueueAuxiliary;using  PriorityQueue = struct _PriorityQueue;struct _PriorityQueueNode {int Priority;Element value;PriorityQueueNode* next;
};struct  _PriorityQueueAuxiliary {PriorityQueueNode* froot;PriorityQueueNode* back;
};struct _PriorityQueue {PriorityCompare Compare;size_t size;PriorityQueueAuxiliary Auxiliary;
};const size_t MaxSize = 1024;void initPriorityQueue(PriorityQueue& priorityQueue, PriorityCompare c);
void PushPriorityQueue(PriorityQueue& priorityQueue,const Element& value);
bool fullPriorityQueue(const PriorityQueue& priorityQueue);
bool emptyPriorityQueue(const PriorityQueue& priorityQueue);
Element& PriorityQueueFroot(PriorityQueue& priorityQueue);// 禁止
//删除优先级队列 Element& value 设置到 value 里
void PopPriorityQueue(PriorityQueue& priorityQueue, Element& value);
void setCompare(PriorityQueue& priorityQueue, PriorityCompare Compare);
const size_t& PriorityQueueSize(PriorityQueue& priorityQueue);
void destroyPriorityQueue(PriorityQueue& priorityQueue);#endif

PriorityQueue.cpp

#include"PriorityQueue.h"
#include<stdexcept>
using namespace std;using Node = PriorityQueueNode;
const size_t zero = 0;//创建优先级队列元素
Node* CreatePriorityQueueNode(const Element& value, Node* nullPtr = nullptr) {Node* node = new Node{ value->value.weight,value,nullPtr };return node;
}void initPriorityQueue(PriorityQueue& priorityQueue, PriorityCompare c) {priorityQueue.Auxiliary = { nullptr,nullptr };priorityQueue.size = zero;priorityQueue.Compare = c;
}bool fullPriorityQueue(const PriorityQueue& priorityQueue) {return priorityQueue.size == MaxSize;
}bool emptyPriorityQueue(const PriorityQueue& priorityQueue) {return priorityQueue.size == zero;
}void GetPriorityNode(Node*&, PriorityCompare&);Element& PriorityQueueFroot(PriorityQueue& priorityQueue)
{if (emptyPriorityQueue(priorityQueue)) {destroyPriorityQueue(priorityQueue);terminate();}return priorityQueue.Auxiliary.froot->value;
}void Link(Node*& node, Node* NewNode) {if (node) {node->next = NewNode;}node = NewNode;
}const size_t& PriorityQueueSize(PriorityQueue& priorityQueue) {return priorityQueue.size;
}void PushPriorityQueue(PriorityQueue& priorityQueue, const Element& value) {const bool iSfront = priorityQueue.size == zero;if (fullPriorityQueue(priorityQueue)) {destroyPriorityQueue(priorityQueue);terminate();}auto&& newNode = CreatePriorityQueueNode(value);auto& Froot = priorityQueue.Auxiliary.froot;auto& back = priorityQueue.Auxiliary.back;if (!iSfront) {Link(newNode->next ,Froot);//小的 调整Froot = newNode;}else{Link(back, newNode);Froot = back;  }++priorityQueue.size;
}void setCompare(PriorityQueue& priorityQueue, PriorityCompare Compare) {priorityQueue.Compare = Compare;
}void PopPriorityQueue(PriorityQueue& priorityQueue, Element& value) {if (emptyPriorityQueue(priorityQueue)) {destroyPriorityQueue(priorityQueue);terminate();}size_t& size = priorityQueue.size;Node** prev = NULL, * prev_node = NULL;Node* last = NULL, * tmp = NULL;prev = &(priorityQueue.Auxiliary.froot);last = priorityQueue.Auxiliary.froot;if (!last){--size;}else {tmp = last->next;while (tmp) {if (priorityQueue.Compare(tmp->Priority, (*prev)->Priority)) {prev = &(last->next);prev_node = last;}last = tmp;tmp = tmp->next;}value = (*prev)->value;auto DeleteNode = *prev;*prev = (*prev)->next;delete DeleteNode;DeleteNode = nullptr;--size;}if (size == zero) {(priorityQueue.Auxiliary.back) = nullptr;}if (prev_node && prev_node->next == NULL) {(priorityQueue.Auxiliary.back = prev_node);}
}void destroyPriorityQueue(PriorityQueue& priorityQueue) {PriorityQueueAuxiliary& Auxiliary = priorityQueue.Auxiliary;Node*& Firsh = Auxiliary.froot;Node*& deleteNode = Firsh;size_t& size = priorityQueue.size;while (Firsh) {Node* next = Firsh->next;delete deleteNode;deleteNode = next;}priorityQueue = {};}

插入小调整

按照比较函数 经过比较函数来达到出队的目的

HuffmanTree.cpp

#include "HuffmanTree.h"
#include"PriorityQueue.h"
#include<iostream>
using std::cout;
using std::endl;bool  priorityCompare(const int& Left, const int& Right){return Left < Right;
}

构建哈夫曼编码树

void build_HuffmanCodeTree(HuffmanCodeTree& tree, HuffmanCodeValue* value, size_t Size) {PriorityQueue priorityQueue;initPriorityQueue(priorityQueue, priorityCompare);HuffmanCodeTreeNode* newNode = nullptr;for (size_t i = 0; i < Size; i++) {newNode = new HuffmanCodeTreeNode{};newNode->value = value[i];PushPriorityQueue(priorityQueue, newNode);}HuffmanCodeTreeNode* Node1 = nullptr;HuffmanCodeTreeNode* Node2 = nullptr;int    i = 0;do {if (!emptyPriorityQueue(priorityQueue)) {PopPriorityQueue(priorityQueue, Node1);if (OutputISspace(Node1->value.value) == "空格")    {cout << "第"<<++i<<"次优先级队列 出队数据为:" << OutputISspace(Node1->value.value) << " 权值:" << Node1->value.weight << endl << endl;}else {cout << "第" << ++i << "次优先级队列 出队数据为:" << (Node1->value.value) << " 权值:" << Node1->value.weight << endl << endl;}}else {break;}if (!emptyPriorityQueue(priorityQueue)) {newNode = new HuffmanCodeTreeNode();PopPriorityQueue(priorityQueue, Node2);if (OutputISspace(Node2->value.value) == "空格") {cout << "第" << ++i << "次优先级队列 出队数据为:"<<OutputISspace(Node2->value.value) << " 权值:" << Node2->value.weight << endl << endl;}else {cout << "第" << ++i << "次优先级队列 出队数据为:"<<(Node2->value.value) << " 权值:" << Node2->value.weight << endl << endl;}newNode->LeftChild = Node1;Node1->Parent = newNode;newNode->RightChild = Node2;Node2->Parent = newNode;newNode->value.value = Space;newNode->value.weight = Node1->value.weight + Node2->value.weight;cout << "合并新结点 优先级队列 入队数据为:" << OutputISspace(newNode->value.value) << " 权值:" << newNode->value.weight << endl << endl;PushPriorityQueue(priorityQueue, newNode);}else {tree.root = Node1;break;}} while (true);destroyPriorityQueue(priorityQueue);
}

合并成新的树节点





合并的结果

哈夫曼编码树算法实现

算法声明

bool  priorityCompare(const int& Left, const int& Right);
//构建哈夫曼编码树
void build_HuffmanCodeTree(HuffmanCodeTree& tree, HuffmanCodeValue* value, size_t Size);
//前序遍历
void FirstOrderRecursiveTraversal(HuffmanCodeTreeNode*& Root);
//销毁哈夫曼编码树
void DestroyHuffmanCodeTree(HuffmanCodeTreeNode*& root);

算法实现

#include "HuffmanTree.h"
#include"PriorityQueue.h"
#include<iostream>
using std::cout;
using std::endl;bool  priorityCompare(const int& Left, const int& Right){return Left < Right;
}void build_HuffmanCodeTree(HuffmanCodeTree& tree, HuffmanCodeValue* value, size_t Size) {PriorityQueue priorityQueue;initPriorityQueue(priorityQueue, priorityCompare);HuffmanCodeTreeNode* newNode = nullptr;for (size_t i = 0; i < Size; i++) {newNode = new HuffmanCodeTreeNode{};newNode->value = value[i];PushPriorityQueue(priorityQueue, newNode);}HuffmanCodeTreeNode* Node1 = nullptr;HuffmanCodeTreeNode* Node2 = nullptr;int  i = 0;do {if (!emptyPriorityQueue(priorityQueue)) {PopPriorityQueue(priorityQueue, Node1);if (OutputISspace(Node1->value.value) == "空格")    {cout << "第"<<++i<<"次优先级队列 出队数据为:" << OutputISspace(Node1->value.value) << " 权值:" << Node1->value.weight << endl << endl;}else {cout << "第" << ++i << "次优先级队列 出队数据为:" << (Node1->value.value) << " 权值:" << Node1->value.weight << endl << endl;}}else {break;}if (!emptyPriorityQueue(priorityQueue)) {newNode = new HuffmanCodeTreeNode();PopPriorityQueue(priorityQueue, Node2);if (OutputISspace(Node2->value.value) == "空格") {cout << "第" << ++i << "次优先级队列 出队数据为:"<<OutputISspace(Node2->value.value) << " 权值:" << Node2->value.weight << endl << endl;}else {cout << "第" << ++i << "次优先级队列 出队数据为:"<<(Node2->value.value) << " 权值:" << Node2->value.weight << endl << endl;}newNode->LeftChild = Node1;Node1->Parent = newNode;newNode->RightChild = Node2;Node2->Parent = newNode;newNode->value.value = Space;newNode->value.weight = Node1->value.weight + Node2->value.weight;cout << "合并新结点 优先级队列 入队数据为:" << OutputISspace(newNode->value.value) << " 权值:" << newNode->value.weight << endl << endl;PushPriorityQueue(priorityQueue, newNode);}else {tree.root = Node1;break;}} while (true);destroyPriorityQueue(priorityQueue);
}void FirstOrderRecursiveTraversal(HuffmanCodeTreeNode*& Root) {if (Root) {cout << "- :" << (Root->value.value) << " -" << endl;//cout << "压缩数据为:" << (Root->value.value) << endl;FirstOrderRecursiveTraversal(Root->LeftChild);FirstOrderRecursiveTraversal(Root->RightChild);}
}void DestroyHuffmanCodeTree(HuffmanCodeTreeNode*& root) {if (root) {DestroyHuffmanCodeTree(root->LeftChild);DestroyHuffmanCodeTree(root->RightChild);delete root;root = {};}
}

main函数

#include<iostream>
#include"HuffmanTree.h"
#include"PriorityQueue.h"using namespace std;const char* FileName = "input.txt";
const char* OpenMode = "r";
//读取的格式: 数据 空格 权值 空格
const  char* readFormat = "%c %d ";//统计文件中的数据和频率的个数并且通过参数修改
bool  getSize(int& size) {FILE* ReadStream = nullptr;const errno_t  openState = fopen_s(&ReadStream, FileName, OpenMode);bool ret = openState == 0;if (ret) {int i = 0;char ch = getc(ReadStream);ret = ch != EOF;if (ret) {ungetc(ch, ReadStream);HuffmanCodeValue value{};int ReadNum = 0;char read[alignof(HuffmanCodeValue) +2];//&value.value, sizeof(value.value), &space, sizeof(space), &value.weight, sizeof(value.weight)while (!feof(ReadStream)) {ReadNum = fscanf_s(ReadStream, readFormat, &value.value, sizeof(value.value), &value.weight, sizeof(value.weight));++i;}size = i;}else {cerr << "错误:" << FileName << "里文件为空" << endl;}fclose(ReadStream);ReadStream = nullptr;}else {char error[1024]{};strerror_s(error, errno);cerr << "错误:" << error << endl;}return ret;
}//获取文件 哈夫曼编码 以及编码的权值
void loadValue(HuffmanCodeValue* value, const int &size) {if (size!=0){FILE* ReadStream = nullptr;const errno_t  openState = fopen_s(&ReadStream, FileName, OpenMode);bool ret = openState == 0;if (ret) {auto First = 0;int ReadNum = 0;char read[alignof(HuffmanCodeValue)+ 1];while (First != size && !feof(ReadStream)) {ReadNum = fscanf_s(ReadStream, readFormat, &value[First].value, sizeof(value[First].value), &value[First].weight, sizeof(value[First].weight));++First;}fclose(ReadStream);//free(ReadStream);ReadStream = nullptr;}}
}int main(void) {HuffmanCodeValue* value;HuffmanCodeTree tree{};int size;if (getSize(size)){value = new  HuffmanCodeValue[size];loadValue(value, size);build_HuffmanCodeTree(tree, value, size);FirstOrderRecursiveTraversal(tree.root);delete [] value;DestroyHuffmanCodeTree(tree.root);}return 0;
}

output:

第1次优先级队列 出队数据为:g 权值:1第2次优先级队列 出队数据为:z 权值:2合并新结点 优先级队列 入队数据为:空格 权值:3第3次优先级队列 出队数据为:空格 权值:3第4次优先级队列 出队数据为:1 权值:3合并新结点 优先级队列 入队数据为:空格 权值:6第5次优先级队列 出队数据为:x 权值:3第6次优先级队列 出队数据为:w 权值:4合并新结点 优先级队列 入队数据为:空格 权值:7第7次优先级队列 出队数据为:j 权值:4第8次优先级队列 出队数据为:q 权值:4合并新结点 优先级队列 入队数据为:空格 权值:8第9次优先级队列 出队数据为:d 权值:5第10次优先级队列 出队数据为:y 权值:5合并新结点 优先级队列 入队数据为:空格 权值:10第11次优先级队列 出队数据为:空格 权值:6第12次优先级队列 出队数据为:空格 权值:7合并新结点 优先级队列 入队数据为:空格 权值:13第13次优先级队列 出队数据为:空格 权值:8第14次优先级队列 出队数据为:空格 权值:10合并新结点 优先级队列 入队数据为:空格 权值:18第15次优先级队列 出队数据为:空格 权值:13第16次优先级队列 出队数据为:空格 权值:18合并新结点 优先级队列 入队数据为:空格 权值:31第17次优先级队列 出队数据为:空格 权值:31- :  -
- :  -
- :  -
- :  -
- :g -
- :z -
- :1 -
- :  -
- :x -
- :w -
- :  -
- :  -
- :j -
- :q -
- :  -
- :d -
- :y -

树的企业应用-哈夫曼编码树-有趣的数据压缩算法相关推荐

  1. 【数据结构与算法】-哈夫曼树(Huffman Tree)与哈夫曼编码

    超详细讲解哈夫曼树(Huffman Tree)以及哈夫曼编码的构造原理.方法,并用代码实现. 1哈夫曼树基本概念 路径:从树中一个结点到另一个结点之间的分支构成这两个结点间的路径. 结点的路径长度:两 ...

  2. 哈夫曼树的生成及哈夫曼编码

    首先构造哈夫曼树结构体,初始化哈夫曼树的四个无符号整型域,输入文本,统计各个字符的权值,然后构建哈夫曼树,从根到叶子逆向求哈夫曼树的编码. #include"stdio.h" #i ...

  3. 【算法学习笔记】哈夫曼树的构建和哈夫曼编码的实现代码

    介绍 哈夫曼(Haffman)这种方法的基本思想如下: ①由给定的n个权值{W1,W2,-,Wn}构造n棵只有一个叶子结点的二叉树,从而得到一个二叉树的集合F={T1,T2,-,Tn}. ②在F中选取 ...

  4. 数据结构C#版笔记--啥夫曼树(Huffman Tree)与啥夫曼编码(Huffman Encoding)

    哈夫曼树Huffman tree 又称最优完全二叉树,切入正题之前,先看几个定义 1.路径 Path 简单点讲,路径就是从一个指定节点走到另一个指定节点所经过的分支,比如下图中的红色分支(A-> ...

  5. 数据结构学习记录——哈夫曼树(什么是哈夫曼树、哈夫曼树的定义、哈夫曼树的构造、哈夫曼树的特点、哈夫曼编码)

    目录 什么是哈夫曼树 哈夫曼树的定义 哈夫曼树的构造 图解操作 代码实现 代码解析 哈夫曼树的特点 哈夫曼编码 不等长编码 二叉树用于编码 哈夫曼编码实例 什么是哈夫曼树 我们先举个例子: 要将百分制 ...

  6. 哈夫曼树的创建和哈夫曼编码

    #include<stdio.h> #include<stdlib.h> #include<string.h> #include<limits.h> # ...

  7. 哈夫曼编码树的经典题目

                                                          点击打开题目链接   poj3253 Fence Repair Time Limit: 20 ...

  8. 理论基础 —— 二叉树 —— 哈夫曼树与哈夫曼编码

    [哈夫曼树] 1.相关概念 1)叶结点的权值:对叶结点赋予的一个有意义的数值量 2)二叉树的带权路径长度(WPL):设二叉树具有 n 个带权叶结点,从根结点到各叶结点的路径长度与相应叶节点权值的乘积之 ...

  9. 哈夫曼编码c语言论文,哈夫曼编码的实现及应用论文.doc

    哈夫曼编码的实现及应用论文 毕 业 设 计(论文) 题目 哈夫曼编码的实现 及应用 二级学院 数学与统计学院 专 业 信息与计算科学 班 级 学生姓名 张泽欣 学号 指导教师 职称 时 间 目录 摘要 ...

最新文章

  1. 正确导入svn拉取的工程
  2. 全面剖析Redis Cluster原理和应用 (good)
  3. 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南(六) MiniGUI 提供的非 GUI/GDI 接口...
  4. Tomcat下server.xml怎样处理图片多路径映射问题
  5. homepage php,HomePage.php
  6. 2012暑假最后两次组队赛总结
  7. 如何实现线程间的通讯(转载)
  8. Linux修改hostname的几种方式,及遇到的问题
  9. java 反射调用set方法_java反射调用set方法时如果让参数做自动类型转换
  10. mysql完全备份 二进制日志_MySQL完全备份脚本:数据+二进制日志+备份日志
  11. linux表示虚拟字符终端,终端,控制台,虚拟终端分别指什么
  12. qq语音聊天对方听不到我说话怎么办?
  13. 黑镜成真!3分钟看懂马斯克直播脑机接口,芯片植入猪脑,活猪演示
  14. 为文字添加下划线和中划线
  15. golang float转string后去除末尾的0
  16. 一分钟带你了解新版系统集成资质——信息系统建设和服务能力评估(CS)
  17. 用Selenium库获取网页源代码:新浪财经股票信息
  18. 【年度榜单】2020大数据产业创新服务产品丨数据猿·金猿榜
  19. win11照片一打开就是打印怎么办?
  20. 网络购物有风险,某东PINKO自营也有假

热门文章

  1. 什么是PV、UV、PR
  2. lombok插件失效解决
  3. 研究生选择统计学还是计算机,985学校的数学系的想考好一点的学校的金融经济方面的研究生容易么?专业应该选择统计学还是应用数学?...
  4. js实现石头剪刀布效果
  5. Database | DBeaver | 完美解决驱动下载/连接失败报错问题
  6. 鹅厂也对元宇宙下手了
  7. 【六一儿童节】用Java生成一个随机童话故事,哄bb睡觉
  8. 联想手机内存卡照片数据删除怎么免费恢复
  9. 安装RocketMQ,启动namesrv报错
  10. 怎样本地服务可以用外网访问