数据结构实验-哈夫曼编/译码器-NOJ7

写一个哈夫曼码的编/译码系统,要求能对要传输的报文进行编码和解码。构造哈夫曼树时,权值小的放左子树,权值大的放右子树,编码时右子树编码为 1,左子树编码为0。

输入表示字符集大小为 n(n <= 100)的正整数,以及 n 个字符和 n 个权值(正整数,值越大表示该字符出现的概率越大);输入串长小于或等于 100 的目标报文。

输出:经过编码后的二进制码,占一行;
以及对应解码后的报文,占一行;
最后输出一个回车符。

这一题要实现哈夫曼树的各种操作,对我而言还是有一定难度的。完整代码如下,关键部分有注释:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100
#define M 2 * N - 1

typedef struct
{
    char data;
    int weight;
    int parent;
    int lchild;
    int rchild;
} HTNode, HuffmanTree[M + 1];//HuffmanTree是一个结构数组类型,0号单元不用

HuffmanTree ht;//哈夫曼树
char hc[M + 1][M];
int n;//n个数据
char s[N];//目标报文
char key[N];//加密报文

void input();
void select(int k, int *min1, int *min2);
void CreateHuffmanTree();
void HuffmanTreeCode();//生成n个字符的哈夫曼编码
void PrintHuffmanTree();//打印哈夫曼编码
void PrintHuffmanTreeDeCoder();//解码

int main()
{
    input();
    CreateHuffmanTree();
    HuffmanTreeCode();
    PrintHuffmanTree();
    PrintHuffmanTreeDeCoder();

    return 0;
}

void input()
{
    int i;
    ht[0].weight = 10000;//由于后面要寻找最小值和次小值,将ht[0].weight设为无穷大
    scanf("%d", &n);
    for(i = 1; i <= n; i++)
    {
        scanf(" %c", &ht[i].data);//读入数据
    }
    for(i = 1; i <= n; i++)
    {
        scanf("%d", &ht[i].weight);//读入权值
    }
    scanf("%s", s);//读入报文
}

void CreateHuffmanTree()//创建哈夫曼树
{
    int i;
    int m;
    int min1, min2;
    ///1.初始化
    for(i = 1; i <= n; i++)
    {
        ht[i].lchild = ht[i].rchild = ht[i].parent = 0;//1到n号存叶子结点,初始化
    }

    m = 2 * n - 1;
    for(i = n + 1; i <= m; i++)
    {
        ht[i] = {0, 0, 0, 0, 0};//n + 1到m号存非叶子结点,初始化
    }
    ///2.创建非叶子结点,建立哈夫曼树
    for(i = n + 1; i <= m; i++)//n - 1次合并
    {
        select(i - 1, &min1, &min2);//在ht[1]到ht[i - 1]里找出最小值和次小值,将其编号赋予min1和min2
        //合并
        ht[i].weight = ht[min1].weight + ht[min2].weight;
        ht[i].lchild = min1;
        ht[i].rchild = min2;
        ht[min1].parent = ht[min2].parent = i;
    }
}


void select(int k, int *min1, int *min2)//在ht[1]到ht[k]里找出最小值和次小值,将其编号赋予min1和min2
{
    int i;

    *min1 = 0;
    for(i = 1; i <= k; i++)
    {
        if(ht[i].parent == 0 && ht[i].weight < ht[*min1].weight)
        {
            *min1 = i;
        }
    }
    *min2 = 0;
    for(i = 1; i <= k; i++)
    {
        if(ht[i].parent == 0 && ht[i].weight < ht[*min2].weight && i != *min1)
        {
            *min2 = i;
        }
    }
}

void HuffmanTreeCode()
{
    int i, k;
    int start;
    int p;
    char cd[M];
    cd[n - 1] = '\0';
    for(i = 1; i <= n; i++)//求n个叶子节点的哈夫曼编码,并将其存储于hc[i]
    {
        start = n - 1;
        k = i;
        p = ht[i].parent;
        while(p != 0)
        {
            start--;
            if(ht[p].lchild == k)
            {
                cd[start] = '0';
            }
            else
            {
                cd[start] = '1';
            }
            k = p;
            p = ht[k].parent;
        }
        strcpy(hc[i], &cd[start]);
    }
}

void PrintHuffmanTree()
{
    int i, j, len;
    len = 0;
    for(i = 0; s[i] != '\0'; i++)//依次转码打印
    {
        for(j = 1; ht[j].data != s[i]; j++);//寻找数据
        strcpy(key + len, hc[j]);
        len = len + strlen(hc[j]);
    }
    key[len + 1] = '\0';
    printf("%s\n", key);
}

void PrintHuffmanTreeDeCoder()//将加密报文key解码
{
    int i;
    int p;
    i = 0;
    p = 2 * n - 1;//p为根节点
    while(key[i] != '\0')
    {
        while(ht[p].lchild != 0 || ht[p].rchild != 0)//当p不为叶子节点时,继续读取编码
        {
            if(key[i] == '0')
            {
                p = ht[p].lchild;
            }
            else
            {
                p = ht[p].rchild;
            }
            i++;
        }
        printf("%c", ht[p].data);
        p = 2 * n - 1;//p重置为根节点
    }
}

以上就是我的实现,其中,为了代码简明,cd并没有使用动态分配,而是直接使用数组。

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,数据结构/译码器的课程设计小结可以包括以下几个方面: 1. 引言:介绍课程设计的背景和目的,说明选择哈/译码器作为课程设计的原因。 2. 设计思路:描述你在设计哈/译码器时的思路和方法。可以包括以下内容: -树的构建:说明如何构建哈树,包括使用线性表保存树的结点。 - 码与解码算法:介绍哈码和解码的算法原理,以及你在设计过程中采用的具体实现方法。 - 数据结构选择:说明你选择的数据结构,以及选择该数据结构的原因。 3. 实现过程:描述你在实现哈/译码器的过程中遇到的问题和解决方法。可以包括以下内容: - 困难与挑战:说明你在实现过程中遇到的困难和挑战,以及你是如何克服它们的。 - 参考资料和学习方法:介绍你在解决问题过程中查阅的参考资料和学习方法,包括课本、网上搜索和相关视频等。 4. 实验结果与分析:展示你的哈/译码器实验结果,并对结果进行分析和讨论。可以包括以下内容: - 功能测试:说明你对哈/译码器进行的功能测试,包括码和解码的正确性验证。 - 性能评估:对你的哈/译码器的性能进行评估,例如码和解码的速度和内存占用等。 5. 总结与反思:总结你在课程设计中的收获和体会,以及对哈/译码器的进一步改进和优化的思考。 6. 参考文献:列出你在课程设计中参考的相关文献和资料。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值