实验1 对指令操作码进行霍夫曼编码
一、实验目的
了解和掌握指令编码的基本要求和基本原理
二、实验内容
使用编程工具编写一个程序,对一组指令进行霍夫曼编码,并输出最后的编码结果以及对指令码的长度进行评价,与扩展操作码和等长编码进行比较。
例如: 有一组指令的操作码共分七类,它们出现概率如下表所示。
指令 | P1 | P2 | P3 | P4 | P5 | P6 | P7 |
---|---|---|---|---|---|---|---|
出现概率 | 0.45 | 0.30 | 0.15 | 0.05 | 0.03 | 0.01 | 0.01 |
对此组指令进行 huffman 编码如下图所示:
最后得到的 huffman 编码如下表所示:
指令 | P1 | P2 | P3 | P4 | P5 | P6 | P7 |
---|---|---|---|---|---|---|---|
出现概率 | 0.45 | 0.30 | 0.15 | 0.05 | 0.03 | 0.01 | 0.01 |
huffman编码 | 0 | 10 | 110 | 1110 | 11110 | 111110 | 111111 |
编码长度 | 1 | 2 | 3 | 4 | 5 | 6 | 6 |
huffman 编码长度为:
H = 0.45 x 1 + 0.30 x 2 + 0.15 x 3 + 0.05 x 4 + 0.03 x 5 + 0.01 x 6 + 0.01 x 6 = 1.97
要对指令的操作码进行 huffman 编码,只要根据指令的各类操作码的出现概率构造 huffman 树再进行 huffman 编码。此过程的难点在于构造 huffman 树,进行 huffman 编码只要对所生成的 huffman 树进行中序遍历即可完成编码工作。
三、实验步骤
观察上图,不难看出构造 huffman 树所要做的工作:
- 先对各指令操作码的出现概率进行排序,构造一个有序链表。
- 再取出两个最小的概率节点相加,生成一个生的节点加入到链表中,同时从两表中删除此两个节点。
- 在对链表进行排序,链表是否只有一个节点,是则 huffman 树构造完毕,否则继续做步骤 2 的操作。
- 为此设计一个工作链表、huffman 树节点、huffman 编码表节点。
四、实验结果
四、实验代码
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int N = 8; // huffman编码最大长度
class huff_p {
public:
huff_p* r_child; // 大概率的节点
huff_p* l_child; // 小概率的节点
char op_mask[3]; // 指令标号
float p; // 指令使用概率
};
class f_min_p{
public:
f_min_p* next;
char op_mask[3]; // 指令标号
float p; // 指令使用概率
huff_p* huf_p;
};
// huff_man code
class huff_code{
public:
huff_code* next;
float p;
char op_mask[3];
char code[N]; // huffman 编码
};
f_min_p* input_instruct_set(); // 输入指令集子模块;
huff_p* creat_huffman_tree(f_min_p* head); // 构造huffman树;
f_min_p* fin_min(f_min_p* h);
f_min_p* del_min(f_min_p* h,f_min_p* p);
void insert_n(f_min_p* h,f_min_p* p);
huff_p* creat_huffp(f_min_p* p);
void creat_huffman_code(huff_p* h1,huff_code* h);// 生成 huffman 编码;
void r_find(huff_p* p1,char code[],int i,huff_code* h);
void output_huffman(huff_code* head);// 输出huffman编码;
void cal_sort_length(huff_code* head);// 计算指令用huffman编码的平均编码字长
void print(huff_p* h1);
int main() {
f_min_p *h, *h1;
huff_p *root;
huff_code* head, *pl;
h = input_instruct_set();
h1 = h;
root = creat_huffman_tree(h1);
head = new huff_code;
head->next = NULL;
creat_huffman_code(root, head);
output_huffman(head);
cal_sort_length(head);
pl = head->next;
while (pl) {
delete head;
head = pl;
pl = pl->next;
}
}
f_min_p* input_instruct_set() {
f_min_p* head;
f_min_p* h;
h = new f_min_p;
h->next = NULL;
h->huf_p = NULL;
head = h;
int n;
cout << "请输入指令数:";
cin >> n;
cout << "请输入指令标号:";
cin >> h->op_mask;
cout << "请输入指令的使用概率:";
cin >> h->p;
f_min_p* point;
f_min_p* p1 = head;
for (int i = 0; i < n-1; i++) {
point = new f_min_p;
cout << "请输入指令标号:";
cin >> point->op_mask;
point->op_mask[2] = '\0';
cout << "请输入指令的使用概率:";
cin >> point->p;
point->huf_p = NULL;
point->next = p1->next;
p1->next = point;
p1 = point;
}
return head;
}
huff_p* creat_huffman_tree(f_min_p* h) {
f_min_p *h1, *min1, *min2, *comb;
huff_p* head, *rd, *ld, *parent;
h1 = h;
min1 = fin_min(h1);
ld = creat_huffp(min1);
h1 = del_min(h1, min1);
if (h1->next) {
min2 = fin_min(h1);
} else {
min2 = h1;
}
rd = creat_huffp(min2);
comb = new f_min_p;
comb->next = NULL;
comb->p = rd->p + ld->p;
comb->op_mask[0] = '\0';
comb->op_mask[1] = '\0';
parent = creat_huffp(comb);
insert_n(h1, comb);
if (h1->next != NULL) {
h1 = del_min(h1, min2);
}
parent->l_child = ld;
parent->r_child = rd;
comb->huf_p = parent;
head = parent;
while (h1->next != NULL) {
min1 = fin_min(h1);
if (min1->huf_p == NULL) {
ld = creat_huffp(min1);
} else {
ld = min1->huf_p;
}
h1 = del_min(h1, min1);
if (h1->next) {
min2=fin_min(h1);
} else {
min2=h1;
}
if (min2->huf_p == NULL) {
rd = creat_huffp(min2);
} else {
rd = min2->huf_p;
}
comb = new f_min_p;
comb->next = NULL;
comb->p = rd->p + ld->p;
comb->op_mask[0] = '\0';
comb->op_mask[1] = '\0';
parent = creat_huffp(comb);
if (h1 != NULL) {
insert_n(h1, comb);
}
if (h1->next != NULL) {
h1 = del_min(h1, min2);
}
if (h1->next == NULL && ld->p < rd->p) {
huff_p* tmp = ld;
ld = rd;
rd = tmp;
}
parent->l_child = ld;
parent->r_child = rd;
comb->huf_p = parent;
head = parent;
if (h1->next == NULL) {
break;
}
}
delete comb;
return head;
}
f_min_p* fin_min(f_min_p* h) {
f_min_p *h1, *p1;
h1 = h;
p1 = h1;
float min = h1->p;
h1 = h1->next;
while (h1) {
if (min > (h1->p)) {
min = h1->p;
p1 = h1;
}
h1 = h1->next;
}
return p1;
}
f_min_p* del_min(f_min_p *h,f_min_p *p) {
f_min_p *p1, *p2;
p1 = h;
p2 = h;
if (h == p) {
h = h->next;
delete p;
} else {
while (p1->next != NULL) {
p1 = p1->next;
if (p1 == p) {
p2->next = p1->next;
delete p;
break;
}
p2 = p1;
}
}
return h;
}
void insert_n(f_min_p *h, f_min_p *p1) {
p1->next = h->next;
h->next = p1;
}
huff_p* creat_huffp(f_min_p* d) {
huff_p* p1;
p1 = new huff_p;
p1->l_child = NULL;
p1->r_child = NULL;
p1->p = d->p;
p1->op_mask[0] = d->op_mask[0];
p1->op_mask[1] = d->op_mask[1];
return p1;
}
void r_find(huff_p* p1, char code[], int i, huff_code* h) {
if (p1->l_child) {
code[i] = '1';
r_find(p1->l_child, code, i+1, h);
}
if (p1->op_mask[0] != '\0') {
huff_code* p2 = new huff_code;
p2->op_mask[0] = p1->op_mask[0];
p2->op_mask[1] = p1->op_mask[1];
p1->op_mask[2] = '\0';
p2->p = p1->p;
int j = 0;
for (; j < i; j++) {
p2->code[j] = code[j];
}
p2->code[j] = '\0';
p2->next = h->next;
h->next = p2;
}
if (p1->r_child) {
code[i] = '0';
r_find(p1->r_child, code, i+1, h);
}
delete p1;
}
void creat_huffman_code(huff_p* h1, huff_code* h) {
int i = 0;
char code[N] = {'\0'};
r_find(h1, code, i, h);
}
void output_huffman(huff_code* head) {
huff_code* h = head->next;
cout << "指令\t" << "概率\t" << "编码" << endl;
cout<<"---------------------------------"<<endl;
while (h) {
h->op_mask[2] = '\0';
cout << h->op_mask << ":\t" << h->p << "\t" << h->code << endl;
h = h->next;
}
cout << "---------------------------------" << endl;
cout << endl;
}
void cal_sort_length(huff_code* head) {
huff_code *h = head->next;
double j = 0;
float one_length = 0;
float per_length = 0;
float ext_length = 0;//按1-2-3-5扩展编码的最小长度为。
while (h) {
float length = 0;
int i = 0;
while (h->code[i] != '\0') {
length++;
i++;
}
one_length = h->p*length;
per_length = per_length + one_length;
h = h->next;
j++;
}
int i1 = int(j);
huff_code *p2 = head->next;
float* p_a = new float[i1];
//sort指令概率
int i0 = 0;
while (p2) {
p_a[i0++] = p2->p;
p2 = p2->next;
}
float max, temp;
int l;
for (int s = 0; s < i1; s++) {
max = p_a[s];
l = s;
for (int k = s+1; k < i1; k++) {
if (max<p_a[k]) {
max = p_a[k];
l = k;
}
}
temp = p_a[s];
p_a[s] = max;
p_a[l] = temp;
}
//计算1-2-3-5扩展编码的最短平均长度
float* code_len = new float[i1];
code_len[0] = 1;
code_len[1] = 2;
code_len[2] = 3;
code_len[3] = 5;
for (int i = 4; i < j; i++) {
code_len[i]=5;
}
l = 0;
while (l<i1) {
ext_length = ext_length + code_len[l]*p_a[l];
l++;
}
//计算等长编码平均长度;
int q_length = ceil(log10(j)/log10(2));
cout << "此指令集操作码 huffman 编码的平均长度为:" << per_length<<endl;
cout << "等长编码的平均长度为:" << q_length << endl;
cout << "按1-2-3-5的扩展编码的最短平均编码长度为:" << ext_length;
cout << endl;
cout << endl;
if (q_length > per_length) {
cout << "可见 huffman 编码的平均长度要比等长编码的平均长度短" << endl;
} else {
cout << "huffman 编码有问题请仔细查看算法,以及输入的指令集的概率之和是否大于1。" << endl;
}
if (ext_length>per_length) {
cout << "可见 huffman 编码的平均长度要比1-2-3-5扩展编码的最短平均长度短" << endl;
} else {
cout << "huffman 编码有问题请仔细查看算法,以及输入的指令集的概率之和是否大于1。" << endl;
}
}
分类:
大学实验
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!