哈夫曼树-中序遍历输出编码

任务描述

本关任务:编写能对给定n个叶子结点,构建哈夫曼树,给出每个叶子结点对应编码的程序。

相关知识
哈夫曼编码和译码的基本原理
  1. 首先要构造一棵哈夫曼树。哈夫曼树的结点结构包括权值,双亲,左右孩子;假如由n个字符来构造一棵哈夫曼树,则共有结点2n-1个;在构造前,先初始化,初始化操作是把双亲,左右孩子的下标值都赋为0;然后依次输入每个结点的权值。

  1. 第二步是通过n-1次循环,每次先找输入的权值中最小的两个结点,把这两个结点的权值相加赋给一个新结点,并且这个新结点的左孩子是权值最小的结点,右孩子是权值第二小的结点;鉴于上述找到的结点都是双亲为0的结点,为了下次能正确寻找到剩下结点中权值最小的两个结点,每次循环要把找的权值最小的两个结点的双亲赋值不为0i)。就这样通过n-1循环下、操作,创建了一棵哈夫曼树,其中,前n个结点是叶子(输入的字符结点)后n-1个是度为2的结点。

  1. 编码的思想是逆序编码,从叶子结点出发,向上回溯,如果该结点是回溯到上一个结点的左孩子,则在记录编码的数组里存“0”,否则存“1”,注意是倒着存;直到遇到根结点(结点双亲为0),每一次循环编码到根结点,把编码存在编码表中,然后开始编码下一个字符(叶子)。

  1. 译码的思想是循环读入一串哈夫曼序列,读到“0”从根结点的左孩子继续读,读到“1”从右孩子继续,如果读到一个结点的左孩子和右孩子是否都为0,如果是说明已经读到了一个叶子(字符),翻译一个字符成功,把该叶子结点代表的字符存在一个存储翻译字符的数组中,然后继续从根结点开始读,直到读完这串哈夫曼序列,遇到结束符便退出翻译循环。(译码内容为选做内容)

任务描述

在右侧编辑器中补充代码,编写能对给定n个叶子结点,构建哈夫曼树,给出每个叶子结点对应编码的程序。

测试说明

平台会对你编写的代码进行测试:

测试输入:5 2 7 4 5 19

预期输出:(对哈夫曼树按中序遍历输出对应叶子的哈夫曼编码)

7 00
5 010
2 0110
4 0111
19 1

测试输入数据说明:5代表共5个结点,后面的5个数字代表权值,不一定按顺序输入


开始你的任务吧,祝你成功!

/*请在此处编写代码,完成哈夫曼编码,并按中序遍历顺序输出每个叶子结点的编码*/
/**********  Begin  *********/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//编码结构体
struct code{
    int w;//权值
    int cnum;//编码个数
    char c[10];//编码的倒序 
    int flag;//记录有没有输出 
};
//哈夫曼树结点结构体
struct huffTree{
    int weight;
    int parent;
    int lchild,rchild;
};
typedef struct huffTree* PhuffTree;
typedef struct code* Pcode;

PhuffTree creatHuffTree();
void print_huff(PhuffTree t);
int compare(char a[],char b[],int x1,int x2);
Pcode huff_code (PhuffTree t);
void print(Pcode cd);

int n;//叶子节点个数,全局变量

//创建哈夫曼树
PhuffTree creatHuffTree()
{
    int i,j,min1,min2,x1,x2;//min1最小,min2第二小,x1最小的下标
    scanf("%d",&n);
    PhuffTree t = (PhuffTree)malloc((2*n-1)*sizeof(struct huffTree));//创建结点空间
    //输入权值并初始化 
    for(i=0; i<n; i++)
    {
        scanf("%d",&t[i].weight);
        t[i].lchild = -1;
        t[i].rchild = -1;
        t[i].parent = -1;
    }
    //查找两个最小的
    for(i=n; i<2*n-1; i++)
    {
        x1 = 0;
        x2 = 0;
        min1 = 65535;
        min2 = 65535;
        for(j=0; j<i; j++)
        {
            if(t[j].parent == -1)
            {//该节点是叶子节点 
                if(t[j].weight < min1)
                {//比最小的还要小 
                    min2 = min1;//原来的最小变成了第二小
                    x2 = x1;
                    min1 = t[j].weight;//变化之后的最小就是它了
                    x1 = j;
                }
                else if(t[j].weight <min2 && t[j].weight > min1)
                {//比最小的大,比第二小的小 
                    min2 = t[j].weight;//变化之后的第二小就是它了
                    x2 = j;
                }
            }
        }
        //更新找出来的两个结点的父节点的值
        t[x1].parent = i;
        t[x2].parent = i;
        //给新建立的结点赋值
        t[i].lchild = x1;//左节点小
        t[i].rchild = x2;//右结点大
        t[i].weight = min1 + min2;//权值等于二者相加
        t[i].parent = -1;//没有父节点
    } 
    return t;
}

//输出查看哈夫曼树(用来测试)
void print_huff(PhuffTree t)
{
    for(int i=0; i<2*n-1; i++)
    printf("第%d个的权值:%d\t,父节点:%d\t,左节点:%d\t,右节点:%d\t\n",i,t[i].weight,t[i].parent,t[i].lchild,t[i].rchild);
} 

 
//哈夫曼树编码
Pcode huff_code (PhuffTree t)
{
    Pcode cd = (Pcode)malloc(n*sizeof(struct code));
    int parent;//父节点
    int child;//子节点 
    for(int i=0; i<n; i++)//只有n位数需要编码
    {
        cd[i].flag = 0;//为后面的比较和输出做准备
        cd[i].cnum = 0;//开始编码之前位数清零
        child = i;
        parent = t[i].parent;
        while(parent != -1)
        {//还没到根节点时,循环继续
            if(t[parent].lchild == child)
            {//等于左孩子时,编码0
                cd[i].c[cd[i].cnum] = '0';//编码
            }
            else//等于右孩子时编码1
            {
                cd[i].c[cd[i].cnum] = '1';//编码 
            } 
            cd[i].cnum++;//编码数加一 
            cd[i].w = t[i].weight;//记录权值 
            child = parent;//以当前父节点为子节点 
            parent = t[child].parent; //继续找子节点的父节点  
        }    
    } 
    return cd;
}

//编码值比较 
int compare(char a[],char b[],int x1,int x2)
{//a比b小输出1,大输出0 
    int i,j;
    for(i=x1-1,j=x2-1; i>=0 && j>=0; i--,j--)
    {//从后往前比,有其中一个等于-1时循环结束
        if(a[i] < b[j]) return 1;
        else if(a[i] > b[j]) return 0;
        else continue;
    }
    if(i == -1) return 1;
    else return 0;
}    

//输出结果
void print(Pcode cd)
{
    for(int k=0; k<n; k++)
    {//一共有n个编码数需要输出
        struct code tc;//用来记录一轮比较中最小的编码值
        int x;//记录该编码值的下标 
        strcpy(tc.c,"111111");
        tc.cnum = 6; 
        for(int i=0; i<n; i++)
        {
            if(cd[i].flag == 0)//未被标记,即未输出 
            {
                if(compare(cd[i].c,tc.c,cd[i].cnum,tc.cnum) == 1)
                {//前比后小
                    tc = cd[i];
                    x = i;
                }
            }
        } 
        cd[x].flag=1; 
        //输出的部分 
        printf("%d ",tc.w);
        for(int j=tc.cnum-1; j>=0; j--)
            printf("%c",tc.c[j]);
        printf("\n");
    }
}
//输出编码(用来测试)
void print_code(Pcode tc)
{
    for(int i=0;i<n; i++)
    {
        printf("%d ",tc[i].w);
        for(int j=tc[i].cnum-1; j>=0; j--)
            printf("%c",tc[i].c[j]);
        printf("\n");
    }
}

//主函数 
int main()
{
     PhuffTree t = creatHuffTree();
//     print_huff(t);
     Pcode c = huff_code(t);
//     print_code(c);
     print(c);
    return 0;
}
/**********  End  *********/
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倒霉蛋要写检讨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值