【Dev-c++】C语言数据结构实验——赫夫曼树的建立和应用

一、实验目的

   1、掌握赫夫曼树的构造。

   2、掌握赫夫曼编码原理

二、实验要求

    1、认真阅读程序,将未完成的代码补全(红色部分)。

2、上机调试,并运行程序。

3、保存和截图程序的运行结果,并结合程序进行分析。

三、实验内容

    1、从键盘输入一串电文字符,统计字符种类及出现的频率建立赫夫曼树。

参考程序5.1

#include <dos.h>

#include <conio.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

typedef struct

{unsigned int weight;  //结点权值

 unsigned int parent,lchild,rchild; //结点的父指针,左//右孩子指针

}HTNode,*HuffmanTree;       //动态分配数组存储赫夫曼树

typedef char **HuffmanCode;  //动态分配数组存储赫夫曼编码表

void CreateHuffmanTree(HuffmanTree &,unsigned int*,int ); //生成一棵赫夫曼树

void HuffmanCoding(HuffmanTree,HuffmanCode &,int );       //对赫夫曼树进行编码

void PrintHuffmanCode(HuffmanCode,unsigned int*,int);     //显示赫夫曼编码

void Select(HuffmanTree,int,int&,int&); //在数组中寻找权值最小的两个结点

void main()

{HuffmanTree HT;  //赫夫曼树HT

 HuffmanCode HC;  //赫夫曼编码表HC

 int n,i;         //n是赫夫曼树叶子结点数

 unsigned int *w; //w存放叶子结点权值  

 char j='y';

//程序解说

 printf("本程序将演示构造赫夫曼树.\n");

 printf("首先输入叶子结点数目.\n例如:8\n");

 printf("然后输入每个叶子结点的权值.\n");

 printf("例如:5 29 7 8 14 23 3 11\n");

 printf("程序会构造一棵哈夫曼树并显示赫夫曼编码.\n");

 printf("  5---0110\n 29---10\n  7---1110\n  8---1111\n 14---110\n");

 printf(" 23---00\n  3---0111\n 11---010\n");

 while(j!='N'&&j!='n')

      {printf("请输入叶子结点数目:");

       scanf("%d",&n);   //输入叶子结点数

       if(n<=1) {printf("该数不合理!\n");continue;}

       w=(unsigned int*)malloc(n*sizeof(unsigned int)); //开辟空间存放权值

       printf("请输入各叶子结点的权值:\n");

       for(i=0;i<n;i++) scanf("%d",&w[i]);       //输入各叶子结点权值

       CreateHuffmanTree(HT,w,n);             //生成赫夫曼树

       HuffmanCoding(HT,HC,n);              //进行赫夫曼编码

       PrintHuffmanCode(HC,w,n);             //显示赫夫曼编码

       printf("赫夫曼树构造完毕,还要继续吗?(Y/N)");

       scanf(" %c",&j);

     }

}



void CreateHuffmanTree(HuffmanTree &HT,unsigned int *w,int n)

{//w存放n个结点的权值,构造一棵赫夫曼树HT

 int i,m;

 int s1,s2;

 HuffmanTree p;

 if(n<=1) return;

 m=2*n-1;  //n个叶子结点的赫夫曼树,有2*n-1  //个结点

 HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode)); //开辟2*n各结点空间,0号单元不用

 for(p=HT+1,i=1;i<=n;++i,++p,++w) //进行初始化

       {p->weight=*w;

       p->parent=0;

       p->lchild=0;

       p->rchild=0;

       }

 for(;i<=m;++i,++p)

       {p->weight=0;

       p->parent=0;

       p->lchild=0;

       p->rchild=0;

       }

 for(i=n+1;i<=m;++i)  //建赫夫曼树

    {Select(HT,i-1,s1,s2); 

       //从HT[1...i-1]中选择parent为0且weight  //最小的两个结点,其序号分别为s1和s2

     HT[s1].parent=i; HT[s2].parent=i; //修改s1和//s2结点的父指针parent

  HT[i].lchild=s1;/*将未完成的代码补全,提示:此处添加一条语句,修改i结点的左孩子指针*/

  HT[i].rchild=s2;/*将未完成的代码补全,提示:此处添加一条语句,修改i结点的右孩子指针*/

     HT[i].weight=HT[s1].weight+HT[s2].weight;  //修改权值

    }

}

void HuffmanCoding(HuffmanTree HT,HuffmanCode &HC,int n)

{//将有n个叶子结点的赫夫曼树HT进行编码, 所//编的码存放在HC中

 //方法是从叶子到根逆向求每个叶子结点的赫夫曼编码

 int i,c,f,start;

 char *cd;

 HC=(HuffmanCode)malloc((n+1)*sizeof(char *));  //分配n个编码的头指针向量

 cd=(char *)malloc(n*sizeof(char));  //开辟一个求 //编码的工作空间

 cd[n-1]='\0';           //编码结束符

 for(i=1;i<=n;++i)       //逐个地求赫夫曼编码

    {start=n-1;          //编码结束位置

     for(c=i,f=HT[i].parent;f!=0;c=f,f=HT[f].parent) //从叶子到根逆向求编码

       if(HT[f].lchild==c)  cd[--start]='0';          //若是左孩子编为'0'

       else cd[--start]='1';                        //若是右孩子编为'1'

     HC[i]=(char *)malloc((n-start)*sizeof(char));   //为第i个编码分配空间

     strcpy(HC[i],&cd[start]);                  //将编码从cd复制到HC中

    }

 free(cd); //释放工作空间

}

void PrintHuffmanCode(HuffmanCode HC,unsigned int *w,int n)

{//显示有n个叶子结点的赫夫曼树的编码表

 int i;

 printf("HuffmanCode is :\n");

 for(i=1;i<=n;i++)

   {printf(" %3d---",w[i-1]);

    puts(HC[i]);

   }

 printf("\n");

}

void Select(HuffmanTree HT,int t,int&s1,int&s2)

{//在HT[1...t]中选择parent不为0且权值最小的两//个结点,其序号分别为s1和s2

 int i,m,n;

 m=n=10000; 

 for(i=1;i<=t;i++)

   {if((HT[i].parent==0)&&((HT[i].weight<m)||(HT[i].weight<n)))

       if(m<n)

           {n=HT[i].weight;s2=i;}

       else {m=HT[i].weight;s1=i;}



   }

 if(s1>s2)  //s1放较小的序号

      {i=s1;s1=s2;s2=i;}

}

 参考程序5.1运行的界面,如图1所示。

 

图 1运行界面

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Karry D

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

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

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

打赏作者

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

抵扣说明:

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

余额充值