Huffman编码解码_霍夫曼编码的verilog实现(1)

Huffman编码

下面将解释为什么是这样编码,在解释之前先说明一个概念:

  • 前缀码:任何一个编码都不是另一个编码的前缀(prefix)。

如果Huffman编码符合前缀码的要求的话,那么绝不会出现编码二义性的问题。而且通过权值这一参考量,构成了最优编码。

原理图

原始节点


构建Huffman树的步骤


Huffman编码

Huffman编码解码算法实现

节点信息结构

// 节点信息结构
struct Node {
// 值
string value;
// 权值
float weight;
// 父节点
int parent;
// 左子节点
int lchild;
// 右子节点
int rchild;
};

编码信息结构

// 编码信息结构
struct Code {
// 编码字符
int bit[maxBit];
// 开始位置
int start;
// 值
string value;
};

全局常量和全局变量

const int INF = 1000000000;
const int maxBit = 1 << 5;
const int maxNode = 1 << 10;
const int maxCode = 1 << 10;

// 节点数组
Node huffman[maxNode];
// 编码数组
Code huffmanCode[maxCode];
// n个字符串
int n;

初始化Huffman树

// 初始化Huffman树
void initHuffmanTree() {
for(int i = 0; i < (2 * n) - 1; i++) {
huffman[i].weight = 0;
huffman[i].value = “”;
huffman[i].parent = -1;
huffman[i].lchild = -1;
huffman[i].rchild = -1;
}
}

构造Huffman树

// 贪心法
// 构造Huffman树
void huffmanTree() {
// 循环构建Huffman树
for(int i = 0; i < n - 1; i++) {
// m1,m2存放所有节点中权值最小的两个节点权值
int m1 = INF;
int m2 = INF;
// x1,x2存放所有节点中权值最小的两个节点下标
int x1 = 0;
int x2 = 0;
for(int j = 0; j < n + i; j++) {
if(huffman[j].weight < m1 && huffman[j].parent == -1) {
m2 = m1;
x2 = x1;
m1 = huffman[j].weight;
x1 = j;
} else if(huffman[j].weight < m2 && huffman[j].parent == -1) {
m2 = huffman[j].weight;
x2 = j;
}
}
// 设置找到的两个节点的x1,x2的父节点信息
huffman[x1].parent = n + i;
huffman[x2].parent = n + i;
huffman[n + i].weight = huffman[x1].weight + huffman[x2].weight;
huffman[n + i].lchild = x1;
huffman[n + i].rchild = x2;
}
}

Huffman编码

// huffman编码
void huffmanEncoding() {
// 临时结构
Code cd;
int child, parent;
for(int i = 0; i < n; i++) {
cd.value = huffman[i].value;
cd.start = n - 1;
child = i;
parent = huffman[child].parent;
// 未到根节点
while(parent != -1) {
// 左孩子
if(huffman[parent].lchild == child) {
cd.bit[cd.start] = 0;
} else {
// 右孩子
cd.bit[cd.start] = 1;
}
cd.start–;
// 设置下一循环条件
child = parent;
parent = huffman[child].parent;
}

// 保存求出的每个叶子节点的Huffman编码结构
for(int j = cd.start + 1; j < n; j++) {
huffmanCode[i].bit[j] = cd.bit[j];
}
huffmanCode[i].start = cd.start;
huffmanCode[i].value = cd.value;
}
}

打印Huffman编码信息

// 打印每个叶节点的Huffman编码和编码起始值
void printHuffmanCode() {
for(int i = 0; i < n; i++) {
cout << “第” << i + 1 << “个字符 " << huffmanCode[i].value << " 的Huffman编码为:”;
for(int j = huffmanCode[i].start + 1; j < n; j++) {
cout << huffmanCode[i].bit[j];
}
cout << " 编码起始值为:" << huffmanCode[i].start << endl;
}
cout << endl;
}

解码Huffman编码

// 解码Huffman编码
void HuffmanDecoding(string s) {
vector v;
// 标识位
int ok = 1;
for(int i = 0; i < s.length()😉 {
// 根节点
int x = (2 * n) - 1 - 1;
// 不为叶子节点
while(huffman[x].lchild != -1 && huffman[x].rchild != -1) {
// 左子树
if(s[i] == ‘0’) {
x = huffman[x].lchild;
} else {
// 右子树
x = huffman[x].rchild;
}
i++;
// 处理0,1序列有误
// 这种情况一般是结尾0,1序列少了,导致最后一个字符串解码失败
if(i == s.length() && huffman[x].lchild != -1) {
ok = 0;
break;
}
}

if(ok) {
v.push_back(huffman[x].value);
}
}
if(ok) {
for(int i = 0; i < v.size(); i++) {
cout << v[i];
}
cout << endl << endl;
} else {
cout << “解码有误。” << endl << endl;
}
}

主函数

int main() {
while(true) {
// 初始化

// 输入数据
cout << “请输入字符串个数(0退出):”;
cin >> n;
if(!n) {
break;
}

// 初始化Huffman树
initHuffmanTree();

for(int i = 0; i < n; i++) {
cout << “一共” << n << “个字符串,请输入第” << i + 1 << “个字符串及其权值:”;
cin >> huffman[i].value;
cin >> huffman[i].weight;
}

// 构造Huffman树
huffmanTree();

// huffman编码
huffmanEncoding();

// 打印每个叶节点的Huffman编码和编码起始值
printHuffmanCode();

while(true) {
cout << “请输入一段符合上述编码的0,1序列(q进入下一次编码解码):”;
string s;
cin >> s;
if(s[0] == ‘q’) {
cout << endl;
break;
}
cout << “原始0,1序列为:” << s << endl;
cout << “解码后为:”;
// 解码
HuffmanDecoding(s);
}
}
return 0;
}

测试主程序

#include
#include
#include

using namespace std;

const int INF = 1000000000;
const int maxBit = 1 << 5;
const int maxNode = 1 << 10;
const int maxCode = 1 << 10;

// 节点信息结构
struct Node {
// 值
string value;
// 权值
float weight;
// 父节点
int parent;
// 左子节点
int lchild;
// 右子节点
int rchild;
};

// 编码信息结构
struct Code {
// 编码字符
int bit[maxBit];
// 开始位置
int start;
// 值
string value;
};

// 节点数组
Node huffman[maxNode];
// 编码数组
Code huffmanCode[maxCode];

// n个字符串
int n;

// 初始化Huffman树
void initHuffmanTree() {
for(int i = 0; i < (2 * n) - 1; i++) {
huffman[i].weight = 0;
huffman[i].value = “”;
huffman[i].parent = -1;
huffman[i].lchild = -1;
huffman[i].rchild = -1;
}
}

// 贪心法
// 构造Huffman树
void huffmanTree() {
// 循环构建Huffman树
for(int i = 0; i < n - 1; i++) {
// m1,m2存放所有节点中权值最小的两个节点权值
int m1 = INF;
int m2 = INF;
// x1,x2存放所有节点中权值最小的两个节点下标
int x1 = 0;
int x2 = 0;
for(int j = 0; j < n + i; j++) {
if(huffman[j].weight < m1 && huffman[j].parent == -1) {
m2 = m1;
x2 = x1;
m1 = huffman[j].weight;
x1 = j;
} else if(huffman[j].weight < m2 && huffman[j].parent == -1) {
m2 = huffman[j].weight;
x2 = j;
}
}
// 设置找到的两个节点的x1,x2的父节点信息
huffman[x1].parent = n + i;
huffman[x2].parent = n + i;
huffman[n + i].weight = huffman[x1].weight + huffman[x2].weight;
huffman[n + i].lchild = x1;
huffman[n + i].rchild = x2;
}
}

// huffman编码
void huffmanEncoding() {
// 临时结构
Code cd;
int child, parent;
for(int i = 0; i < n; i++) {
cd.value = huffman[i].value;
cd.start = n - 1;
child = i;
parent = huffman[child].parent;
// 未到根节点
while(parent != -1) {
// 左孩子
if(huffman[parent].lchild == child) {
cd.bit[cd.start] = 0;
} else {
// 右孩子
cd.bit[cd.start] = 1;
}
cd.start–;
// 设置下一循环条件
child = parent;
parent = huffman[child].parent;
}

// 保存求出的每个叶子节点的Huffman编码结构
for(int j = cd.start + 1; j < n; j++) {
huffmanCode[i].bit[j] = cd.bit[j];
}
huffmanCode[i].start = cd.start;
huffmanCode[i].value = cd.value;
}
}

// 打印每个叶节点的Huffman编码和编码起始值
void printHuffmanCode() {
for(int i = 0; i < n; i++) {
cout << “第” << i + 1 << “个字符 " << huffmanCode[i].value << " 的Huffman编码为:”;
for(int j = huffmanCode[i].start + 1; j < n; j++) {
cout << huffmanCode[i].bit[j];
}
cout << " 编码起始值为:" << huffmanCode[i].start << endl;
}
cout << endl;
}

// 解码Huffman编码
void HuffmanDecoding(string s) {
vector v;
// 标识位

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Go语言工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Go语言全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

片转存中…(img-NJ1Zunec-1712877722488)]
[外链图片转存中…(img-HcSjYwws-1712877722489)]
[外链图片转存中…(img-2XxLWaR5-1712877722489)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Golang知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-G2vbMQp6-1712877722490)]

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 30
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值