实验三(必做,基本实验,4学时)实验题目:Huffman树及Huffman编码的算法实现

实验目的

1、 了解该树的应用实例,熟悉掌握Huffman树的构造方法及Huffman编码的应用,

2、 了解Huffman树在通信、编码领域的应用过程。

实验要求

1、输入一段100200字的英文短文,存入一文件a中。

2、写函数统计短文出现的字母个数n及每个字母的出现次数

3、写函数以字母出现次数作权值,建Haffman树(n个叶子),给出每个字母的Haffman编码。

4、用每个字母编码对原短文进行编码,码文存入文件b中。

5、用Haffman树对b中码文进行译码,结果存入文件c中,比较a,c是否一致,以检验编码、译码的正确性。

实验内容和实验步骤:

1.先编辑基本的存储单元struct twshu 用来存储节点;

2,在主函数中完成文件读写到数组中并且编码;编码中调用了quanzhi();来辅助;

3.在编写用来创建单链的twshu* creatnode(int q, char a, int type) //创建节点

与twshu* creatlink(int num, char word) {  //创建第一条链表,这个链表是后面创建二叉树的基础,并且赋予权值和对应的字母,按权值大小排序。

4.编写创建二叉树的编码 twshu* creatwshu(twshu* link, int quan[52], char A[52]) {  //创建二叉树,创建的思想为根据之前创建的有序link,最开始的两个最小,最小的两个形成新的节点并且接入到链表中

5.编写为每个字母编码的函数int bianma(twshu* head, char  hfm[52][52], char A[52], char b[1], int i, int j) {//对每一个叶子对应的字母进行编码,编码方式为进行一遍先根遍历,每遍历一次左子树加是对应的哈夫曼编码加0,每遍历一遍右子树加一,如果遍历的节点是叶子的话使标记hfm编码数组的值加一并返回,

6.以哈夫曼码为基础,编写char *bianmafile(char  hfm[52][52], char A[52], twshu* head, char str[N + 1]) {//根据哈夫曼码及其对应的字母对整个文件进行编码

7. 编写译码函数译码char* yima(char bstr[N * 52], twshu* head) {//根据编码文件,遍历译码树,当访问到叶子的时候返回相应的数值并且从头开始继续遍历

8.在主函数中依次进行权值计算,单链的创建,哈夫曼树的建立,为哈夫曼树编码,为文件编码,为文件译码这些过程,并且将文件存储到根目录下。

代码如下:

#include<stdio.h>

#include <string>

#include <math.h>

#define N 1000

struct twshu {

    int number;

    int type;//0是根,1是节点,2是叶子

    char elem;

    twshu* lchild, * rchild, * next = NULL;

};

void compare(twshu* link, int quan);

twshu* creatlink(int num, char word);

twshu* creatwshu(twshu* link, int quan[52], char A[52]);

int bianma(twshu* head, char hfm[52][52], char A[52], char b[1], int i, int j);

char* bianmafile(char hfm[52][52], char A[52], twshu* head, char str[N + 1]);

char yimashu(twshu* head, char bstr[N * 52], int& i);

char* yima(char bstr[N * 52], twshu* head);

int quanzhi(char str[N + 1], char elem) {//为每一个字母返回权值

    int quan = 0;

    int i = 0;

    while (str[i] != NULL)

    {

        if (elem == str[i]) quan++;

        i++;

    }

    return quan;

}

twshu* creatnode(int q, char a, int type) {   //创建节点

    twshu* node = ((twshu*)malloc(sizeof(twshu)));

    node->type = type;

    node->number = q;

    node->elem = a;

    node->rchild = NULL;

    node->lchild = NULL;

    node->next = NULL;

    return node;

}

void compare(twshu* link, int quan) {              //为运算一次之后的权值排序,截止条件是数值大于运算后的权值

    twshu* p = link;

    while (p != NULL && p->number <= quan) {

        twshu* q = p;

        while (q != NULL && q->number <= quan) {

            if (p->number > q->number) {

                twshu* lchild = p->lchild;

                int number = p->number;

                twshu* rchild = p->rchild;

                char elem = p->elem;

                int type = p->type;

                p->lchild = q->lchild;

                p->number = q->number;

                p->rchild = q->rchild;

                p->elem = q->elem;

                p->type = q->type;

                q->lchild = lchild;

                q->number = number;

                q->rchild = rchild;

                q->elem = elem;

                q->type = type;

            }

            q = q->next;

        }

        p = p->next;

    }

}

twshu* creatlink(int num, char word) {  //创建第一条链表,这个链表是后面创建二叉树的基础

    twshu* node = (twshu*)malloc(sizeof(twshu));

    node->lchild = NULL;

    node->number = num;

    node->rchild = NULL;

    node->type = 2;

    node->elem = word;

    node->next = NULL;

    return node;

}

twshu* creatwshu(twshu* link, int quan[52], char A[52]) {  //创建二叉树,创建的思想为根据之前创建的有序link,最开始的两个最小,最小的两个形成新的节点并且接入到链表中

    if (link->next != NULL)

    {

        twshu* temp = NULL;

        twshu* q = link->next;

        while (q->next != NULL) {

            temp = (twshu*)malloc(sizeof(twshu));

            temp->next = q->next->next;

            temp->lchild = q;

            temp->rchild = q->next;

            q = temp;

            q->number = quan[0] + quan[1];

            q->type = 1;

            q->elem = 0;

            compare(q, q->number);

        }

        return q;

    }

    else {

        return NULL;

    }

}

int bianma(twshu* head, char  hfm[52][52], char A[52], char b[1], int i, int j) {//对每一个叶子对应的字母进行编码,编码方式为进行一遍先根遍历,每遍历一次左子树加是对应的哈夫曼编码加0,每遍历一遍右子树加一,如果遍历的节点是叶子的话使标记hfm编码数组的值加一并返回,

    twshu* p = head;

    j++;

    if (b [0] != '2') {

        hfm[i][j] = b[0];

    }

    if (head->lchild == NULL && head->rchild == NULL)

    {

        A[i] = head->elem;

        int t = 0;

        for (int t = 0; t < j; t++)

        {

            if (i != 0 && hfm[i][t] == NULL)

            {

                hfm[i][t] = hfm[i - 1][t];

            }

        }

        i++;

        return i;

    }

    int t = j;

    char b0[1] = { '0' };

    char b1[1] = { '1' };

    i = bianma(head->lchild, hfm, A, b0, i, j);

    j = t;

    i = bianma(head->rchild, hfm, A, b1, i, j);

    return i;

}

char *bianmafile(char  hfm[52][52], char A[52], twshu* head, char str[N + 1]) {//根据哈夫曼码及其对应的字母对整个文件进行编码

    char bstr[52 * N]={};

    int i = 0, j = 0, t = 0, n = 0;

    while (str[i] != NULL) {

        t = 0;

        while (A[t] != str[i] && t < 52) { t++; }

        if (t < 52) {

                while (hfm[t][n] != NULL) {

                    bstr[j] = hfm[t][n];

                    n++;

                    j++;

                }

        }

        n = 0;

        i++;

    }

    return bstr;

}

char yimashu(twshu* head, char bstr[N * 52], int& i) {

    if (head->lchild == NULL && head->rchild == NULL) return head->elem;

    if (bstr[i] == '0') {

        i++;

        return yimashu(head->lchild, bstr, i);

    }

    else {

        i++;

        return yimashu(head->rchild, bstr, i);

    }

}

char* yima(char bstr[N * 52], twshu* head) {//根据编码文件,遍历译码树,当访问到叶子的时候返回相应的数值并且从头开始继续遍历

    char xstr[N+1]={};

    int i = 0, j = 0;

    while (bstr[i] != NULL) {

        xstr[j] = yimashu(head, bstr, i);

        j++;

    }

    return xstr;

}

int main()

{

    FILE* f;

    char str[N + 1] = {};

    char astr[N + 1] = {};

    char fstr[N + 1] = {};

    int quan[52], i = 0, sum = 0, j = 0;

    char hfm[52][52] = {};

    char A[52]={};

    int one = 1;

    char* bstr;

    char  cstr[52 * N]={};

    char* xstr;

    errno_t err = fopen_s(&f, "data.txt", "r");

    for (i = 0; i < 52; i++)

    {

        quan[i] = 0;

    }

    i = 0;

    if (f != NULL)

    {

        printf("fopen ok\n");

    }

    char c;

    while ((c = fgetc(f)) != EOF && i < 999) { // 逐个读取字符并存储到数组中

        fstr[i] = c;

        i++;

    }

    printf("文件中的原内容为\n");

    printf("%s\n", fstr);

    i = 0;

    while (fstr[i] != '/0'&&i<N) {//计算每个字母的权值

        one = 1;

        int j = 0;

        while (A[j] != NULL) {

            if (fstr[i] == A[j]) one = 0;

            j++;

        }

        if (one) {

            if ((fstr[i] >= 'a' && fstr[i] <= 'z') || (fstr[i] >= 'A' && fstr[i] < ='Z'))

            {

                A[sum] = fstr[i];

                quan[sum] = quanzhi(fstr, fstr[i]);

                sum++;

            }

        }

        i++;

    }

    sum = 0;

    for (i = 0; A[i] != NULL && quan[i] != NULL; i++) {//按权值大小排序

        for (int j = i + 1; A[j] != NULL && quan[j] != NULL; j++) {

            if (quan[i] > quan[j]) {

                int temp = quan[i];

                char TEMP = A[i];

                A[i] = A[j];

                quan[i] = quan[j];

                A[j] = TEMP;

                quan[j] = temp;

            }

        }

    }

    twshu* link = creatlink(0, 0);

    twshu* p = link;

    i = 0;

    while (A[i] != NULL) {   //将权值连成链表

        p->next = creatlink(quan[i], A[i]);

        p = p->next;

        i++;

    }

    twshu* head = creatwshu(link, quan, A);//返回哈夫曼树

    if (head != NULL) {

        head->elem = 0;

        head->type = 0;

    }

    else {

        printf("创建树失败");

    }

    char b[1] = { '2' };

    bianma(head, hfm, A, b, 0, -2);

    printf("bianma操作:输出每个字母对应的编码\n");//输出每个字母对应的编码

    i = 0;

    while (A[i] != NULL) {

        printf("%c=%s\n", A[i], hfm[i]);

        i++;

    }

    i = 0; j = 0;

    if (f != 0)

        fclose(f);

    bstr = bianmafile(hfm, A, head, fstr);

    err=fopen_s(&f,"databianma.txt", "w");

    if (f != NULL) {

        printf("\n写入bianma文件打开成功\n");

        fwrite(bstr, sizeof(char), sizeof(cstr), f);

        fclose(f);

    }

    err = fopen_s(&f,"databianma.txt", "r");

    i = 0;

    while ((c = fgetc(f)) != EOF && i < 5000) { // 逐个读取字符并存储到数组中

        cstr[i] = c;

        i++;

    }

    bstr = cstr;

    fclose(f);

    printf("\n\n编码结果:\n%s", bstr);

    i = 0;

    xstr = yima(bstr, head);

    int size = 0;

    while (xstr[size] != NULL)

    {

        astr[size] = xstr[size];

        size++;

    }

    err = fopen_s(&f,"datayima.txt", "w");

    printf("\n译码的结果:\n%s", astr);

    if (f != NULL) {

        printf("\n写入文件已经打开\n");

        fprintf(f, " % s", astr);

        fclose(f);

    }

    printf("\nendend\n");

    return 0;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值