实验1 对指令操作码进行霍夫曼编码

简介: 了解和掌握指令编码的基本要求和基本原理

一、实验目的


  了解和掌握指令编码的基本要求和基本原理


二、实验内容


  使用编程工具编写一个程序,对一组指令进行霍夫曼编码,并输出最后的编码结果以及对指令码的长度进行评价,与扩展操作码和等长编码进行比较。


例如: 有一组指令的操作码共分七类,它们出现概率如下表所示。


image.png对此组指令进行 huffman 编码如下图所示:



最后得到的 huffman 编码如下表所示:


image.png


huffman 编码长度为: 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 树所要做的工作:


  1. 先对各指令操作码的出现概率进行排序,构造一个有序链表。
  2. 再取出两个最小的概率节点相加,生成一个生的节点加入到链表中,同时从两表中删除此两个节点。
  3. 在对链表进行排序,链表是否只有一个节点,是则 huffman 树构造完毕,否则继续做步骤 2 的操作。
  4. 为此设计一个工作链表、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;
    }
}


相关文章
|
3月前
|
存储 程序员
【汇编】“转移”综述、操作符offset、jmp指令
【汇编】“转移”综述、操作符offset、jmp指令
|
8月前
|
存储 JavaScript
5.2 汇编语言:标志位测试指令
汇编语言是一种面向机器的低级语言,用于编写计算机程序。汇编语言与计算机机器语言非常接近,汇编语言程序可以使用符号、助记符等来代替机器语言的二进制码,但最终会被汇编器编译成计算机可执行的机器码。标志位测试指令是汇编语言中用于测试处理器标志位状态的指令。标志位是位于处理器状态寄存器中的一组特殊标志,用于指示上一个运算的结果是否为零、是否进位/借位、是否溢出等等。可以使用标志位测试指令来检查标志位的状态,并在需要时根据标志位状态进行操作。
139 0
|
8月前
|
存储 缓存
当执行汇编指令MOV [0001H] 01H时,计算机都做了什么?
今天和几位单位大佬聊天时,讨论到一个非常有趣的问题-当程序执行MOV [0001H], 01H计算机实际上都做了哪些工作?乍一看这个问题平平无奇,CPU只是把立即数01H放在了地址为0001的内存里,但仔细想想这个问题远没有那么简单,由于现代计算机体系中CPU速度比内存要快2到3个个数量级,因此从CPU执行MOV指令,到实际把01H写入内存之间,还有非常漫长而复杂的过程。
|
11月前
|
存储 JavaScript
x86汇编基础指令
x86汇编基础指令
x86汇编基础指令
|
JavaScript 前端开发
3、指令(v-if与v-for的区别、各种指令的使用)
3、指令(v-if与v-for的区别、各种指令的使用)
117 0
3、指令(v-if与v-for的区别、各种指令的使用)
数据指令
增删改查 插入数据,如果已有主键值则插入数据失败
101 0
|
编译器
|
Ruby
汇编实验2 寻址方式练习
实验目的: 1.理解存储器分段及寻址方式的意义 2.熟练掌握立即寻址、寄存器寻址、直接寻址、寄存器间接寻址、寄存器相对寻址、基址变址寻址、相对基址变址寻址等几种寻址方式。 3.复习巩固DEBUG中的R、D、E命令。 4.掌握用A命令编制程序,U命令进行反汇编,用G、T命令执行程序。
206 0
汇编实验2 寻址方式练习