二叉树的应用

1. 实验目的:掌握二叉树的链式存储结构和常用算法。利用哈夫曼树设计最优压缩编码

2. 实验内容

1) 编写函数,实现建立哈夫曼树和显示哈夫曼树的功能。

2) 编写函数,实现生成哈夫曼编码的功能

3) 编写主函数,从终端输入一段英文文本;统计各个字符出现的频率,然后构建哈夫曼树并求出对应的哈夫曼编码;显示哈夫曼树和哈夫曼编码。

选做内容:修改程序,选择实现以下功能:

4) 编码:用哈夫曼编码对一段英文文本进行压缩编码,显示编码后的文本编码序列

5) 统计:计算并显示文本的压缩比例

6) 解码:将采用哈夫曼编码压缩的文本还原为英文文本。

3. 说明:

1) 二叉树和哈夫曼树的相关算法见讲义。

2) 编码的方法是:从头开始逐个读取文本字符串中的每个字符,查编码表得到它的编码并输出。重复处理直至文本结束。

3) 解码的方法是:将指针指向哈夫曼树的树根,从头开始逐个读取编码序列中的每位,若该位为1则向右子树走,为0则向左子树走。当走到叶子节点时,取出节点中的字符并输出。重新将指针放到树根,继续以上过程直至编码序列处理完毕。

4) 压缩比例的计算:编码后的文本长度为编码序列中的01的个数,原文本长度为字符数*8。两者之比即为压缩比。

4.函数说明

1编写函数,实现建立哈夫曼树和显示哈夫曼树的功能 

huffnode CreateHufftree(  建立Huffman

2.编写函数,实现生成哈夫曼编码的功能

void CreateHuffcode( 

已知tree[i]节点的编码序列为s,求该节点下所有叶子节点的编码序列

3编写主函数,从终端输入一段英文文本;统计各个字符出现的频率,然后构建哈夫曼树并求出对应的哈夫曼编码;显示哈夫曼树和哈夫曼

(4) 编码:用哈夫曼编码对一段英文文本进行压缩编码,显示编码后的文本编码序列。

void DeCoding( 

 根据tree数组中的huffman,逐个对hfmstr字符串中的字符进行译码,结果放在decodestr字符串中

(5)压缩比例的计算

float CompressRatio(  

6将采用哈夫曼编码压缩的文本还原为英文文本

*函数内容详见程序清单*

 

 

 

 

5.程序清单&代码说明

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <limits.h>

#define 96 //ASCII字符集包含至多N个可见字符

typedef struct    //Huffman树节点定义

{ char data; //字符值

int weight; //权重

int lchild; //左子结点

int rchild; //右子结点

huffnode; //huffman节点类型

struct charcode

{ int count; //字符出现的次数(频率)

char code[N]; //字符的Huffman编码

codeset[N]; //编码表,长为N,每项对应一个ascii码字符,下标i的项对应ascii编码为i+32的字符

huffnode CreateHufftree(char data[], int weight[], int n)   //建立Huffman树的算法

{

int i,k;

int min1,min2,min_i1,min_i2;

huffnode *tree;

tree=(huffnode *)malloc((2*n-1)*sizeof(huffnode));  //Huffman树分配2n-1个节点空间

for (i=0;i<2*n-1;i++)  //初始化,将各字符和其频率填入Huffman,作为叶子结点

 {

tree[i].lchild=tree[i].rchild=-1;

if (i<n) {

tree[i].data=data[i];

tree[i].weight=weight[i];

}

else tree[i].data=' ';

for (i=n;i<2*n-1;i++)   合并两棵树,n-1

{

min1=min2=INT_MAX; //INT_MAX为最大值

min_i1=min_i2=-1;

for (k=0;k<i;k++)  查找定位两个最小权重节点

if (tree[k].weight>=0)  //仅在根节点中找

if (tree[k].weight<min1)

{

min2=min1;

min_i2=min_i1;

min1=tree[k].weight;

min_i1=k;

}

else 

if (tree[k].weight<min2) {

min2=tree[k].weight;

min_i2=k;

}

tree[i].weight=min1+min2;  // 合并

tree[min_i1].weight *= -1;

 

tree[min_i2].weight *= -1;

tree[i].lchild=min_i1;

tree[i].rchild=min_i2;

}

return tree;

}

void CreateHuffcode(huffnode tree[], int i, char s[])

//已知tree[i]节点的编码序列为s,求该节点下所有叶子节点的编码序列。

{ char s1[N],c;

if(i!=-1) 

if (tree[i].lchild==-1 && tree[i].rchild==-1) 

c=tree[i].data; 

strcpy(codeset[c-32].code, s);

}

else {

strcpy(s1, s);  strcat(s1, "0");

CreateHuffcode(tree, tree[i].lchild, s1);

strcpy(s1, s);  strcat(s1, "1");

CreateHuffcode(tree, tree[i].rchild, s1);

}

return;

 

void PrintHufftree(huffnode tree[], int n)      //输出tree中的Huffman

  

{

   int i;

   printf("Huffman tree :\n");

   printf("i\tValue\tLchild\tRchild\tWeight\n");

   for(i=2*n-2;i>=0;i--)

  

 

 {

      printf("%d\t",i);

      printf("%c\t",tree[i].data);

      printf("%d\t",tree[i].lchild);

      printf("%d\t",tree[i].rchild);

      printf("%d\t",tree[i].weight);

      printf("\n");

   }

}

 

 

 

 

 

void EnCoding(char str[], char hfmstr[])

{

//根据codeset编码表,逐个将str字符串中的字符转化为它的huffman编码,结果编码串放在hfmstr字符串中

int i, j;

hfmstr[0]='\0';

i=0;

while(str[i]!='\0')   

    {

j=str[i]-32;

strcat(hfmstr, codeset[j].code);

i++;

}

}

void DeCoding(huffnode tree[], int n, char hfmstr[], char decodestr[])

//根据tree数组中的huffman,逐个对hfmstr字符串中的字符进行译码,结果放在decodestr字符串中

{

int i=0,j=0;

huffnode p;

p=tree[2*n-2];

while(hfmstr[i]!='\0')

{while(p.lchild!=-1&&p.rchild!=-1)

{

if(hfmstr[i]=='0')

{

p=tree[p.lchild];

}

 

else if(hfmstr[i]=='1')

{

p=tree[p.rchild];

}

i++;

}

decodestr[j]=p.data;j++;

p=tree[2*n-2];

}

 

}

float CompressRatio(char str[], char hfmstr[])  //计算并返回压缩比

{

float w,a=1,b=1;

int i;

 

 

for(i=0;str[i]!='\n';i++)

a++;

a=a*8;

for(i=0;hfmstr[i]!='\n';i++)

b++;

w=a/b;

return w;

}

void main()

{  

int i,j;

float ratio;  //压缩比

huffnode ht; //Huffman

char data[N]; //要编码的字符集合

int  weight[N]; //字符集合中各字符的权重(频率)

int n=0; //字符集合中字符的个数

char str[1000];         //需输入的原始字符串  

char hfm_str[1000]=""; //编码后的字符串

char decode_str[1000]="";//解码后的字符串

printf("输入要转换的字符串\n");

gets(str);

for(i=0;i<N;i++) { //初始化编码表,频率为0,编码串为空串

codeset[i].count=0;

codeset[i].code[0]='\0';

}

 

i=0; 

while(str[i]!='\0') { //统计原始字符串中各字符出现的频率,存入编码表

j=str[i]-32;

codeset[j].count++; //codeset[0]~[95]对应ascii32~127的字符

i++;

}

for(i=0;i<N;i++) //统计原始字符串中出现的字符个数

if(codeset[i].count!=0) n++;

printf("字符频率统计:\n"); //显示统计结果

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

if(codeset[i].count!=0) printf("%c:%d, ", i+32, codeset[i].count);

printf("\n");

j=0;

for(i=0;i<N;i++) //生成要编码的字符集合,以及权重

if (codeset[i].count!=0) {

data[j]=i+32;

weight[j]=codeset[i].count;

 

   j++;

}

ht=CreateHufftree(data,weight,n);  //建立Huffman,根节点是ht[2*n-2]

    PrintHufftree(ht,n); //显示Huffman树的存储结果

CreateHuffcode(ht, 2*n-2, "");  //ht[2*n-2]为根,以空字符串为起始编码字符串,求出各叶子节点的编码字符串

//显示codeset中的Huffman编码,参见"显示频率统计结果"的代码.

    printf("haffman编码为:\n");

    for(i=0;i<N;i++){

if(codeset[i].count!=0)

    printf("%c:%s\n",i+32,codeset[i].code );

 

}

EnCoding(str, hfm_str);  //str字符串进行编码,放在hfm_str字符串中

printf("编码序列%s\n",hfm_str);

ratio=CompressRatio(str, hfm_str); //计算压缩比

printf("压缩比%3.2f\n",ratio);

DeCoding(ht, n, hfm_str, decode_str); //hfm_str字符串进行译码,放在decode_str字符串中

printf("解码后的字符串%s\n",decode_str);

free(ht);  //释放Huffman

}

 

 

 

6、实验截图

二叉树的应用

 

 

7、实验体会:、

实验前有老师给的已经编好的一部分程序,大大减少了工作来量。通过上机实验,我进一步掌握指针变量和动态变量的含义你,掌握二叉树的结构特性,以及各种存储结构的特点及适用范围,掌握用指针类型描述、访问和处理二叉树的运算。二叉树也是递归定义的,其结点有左右子树之分,逻辑上二叉树有多种形态为了扩展知识,我从网上查阅了一些关于树的知识。尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形树是由一个或多个结点组成的有限集合,其中: 

⒈必有一个特定的称为根(ROOT)的结点;  

⒉剩下的结点被分成n>=0个互不相交的集合T1、T2、......Tn,而且, 这些集合的每一个又都是树。树T1、T2、......Tn被称作根的子树(Subtree)。
树结构的特点是:它的每一个结点都可以有不止一个直接后继,除根结点外的所有结点都有且只有一个直接前驱。二叉树很象一株倒悬着的树,从树根到大分枝、小分枝、直到叶子把数据联系起来,这种数据结构就叫做树结构,简称树。树中每个分叉点称为结点,起始结点称为树根,任意两个结点间的连接关系称为树枝,结点下面不再有分枝称为树叶 普通树转二叉树,一般采用左“子女”右“兄弟”的方式来转化。  

希望自己在这门课中可以学到更多的知识,多点知识总是好的。1. 实验目的:掌握二叉树的链式存储结构和常用算法。利用哈夫曼树设计最优压缩编码

2. 实验内容

1) 编写函数,实现建立哈夫曼树和显示哈夫曼树的功能。

2) 编写函数,实现生成哈夫曼编码的功能

3) 编写主函数,从终端输入一段英文文本;统计各个字符出现的频率,然后构建哈夫曼树并求出对应的哈夫曼编码;显示哈夫曼树和哈夫曼编码。

选做内容:修改程序,选择实现以下功能:

4) 编码:用哈夫曼编码对一段英文文本进行压缩编码,显示编码后的文本编码序列

5) 统计:计算并显示文本的压缩比例

6) 解码:将采用哈夫曼编码压缩的文本还原为英文文本。

3. 说明:

1) 二叉树和哈夫曼树的相关算法见讲义。

2) 编码的方法是:从头开始逐个读取文本字符串中的每个字符,查编码表得到它的编码并输出。重复处理直至文本结束。

3) 解码的方法是:将指针指向哈夫曼树的树根,从头开始逐个读取编码序列中的每位,若该位为1则向右子树走,为0则向左子树走。当走到叶子节点时,取出节点中的字符并输出。重新将指针放到树根,继续以上过程直至编码序列处理完毕。

4) 压缩比例的计算:编码后的文本长度为编码序列中的01的个数,原文本长度为字符数*8。两者之比即为压缩比。

4.函数说明

1编写函数,实现建立哈夫曼树和显示哈夫曼树的功能 

huffnode CreateHufftree(  建立Huffman

2.编写函数,实现生成哈夫曼编码的功能

void CreateHuffcode( 

已知tree[i]节点的编码序列为s,求该节点下所有叶子节点的编码序列

3编写主函数,从终端输入一段英文文本;统计各个字符出现的频率,然后构建哈夫曼树并求出对应的哈夫曼编码;显示哈夫曼树和哈夫曼

(4) 编码:用哈夫曼编码对一段英文文本进行压缩编码,显示编码后的文本编码序列。

void DeCoding( 

 根据tree数组中的huffman,逐个对hfmstr字符串中的字符进行译码,结果放在decodestr字符串中

(5)压缩比例的计算

float CompressRatio(  

6将采用哈夫曼编码压缩的文本还原为英文文本

*函数内容详见程序清单*

 

 

 

 

5.程序清单&代码说明

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <limits.h>

#define 96 //ASCII字符集包含至多N个可见字符

typedef struct    //Huffman树节点定义

{ char data; //字符值

int weight; //权重

int lchild; //左子结点

int rchild; //右子结点

huffnode; //huffman节点类型

struct charcode

{ int count; //字符出现的次数(频率)

char code[N]; //字符的Huffman编码

codeset[N]; //编码表,长为N,每项对应一个ascii码字符,下标i的项对应ascii编码为i+32的字符

huffnode CreateHufftree(char data[], int weight[], int n)   //建立Huffman树的算法

{

int i,k;

int min1,min2,min_i1,min_i2;

huffnode *tree;

tree=(huffnode *)malloc((2*n-1)*sizeof(huffnode));  //Huffman树分配2n-1个节点空间

for (i=0;i<2*n-1;i++)  //初始化,将各字符和其频率填入Huffman,作为叶子结点

 {

tree[i].lchild=tree[i].rchild=-1;

if (i<n) {

tree[i].data=data[i];

tree[i].weight=weight[i];

}

else tree[i].data=' ';

for (i=n;i<2*n-1;i++)   合并两棵树,n-1

{

min1=min2=INT_MAX; //INT_MAX为最大值

min_i1=min_i2=-1;

for (k=0;k<i;k++)  查找定位两个最小权重节点

if (tree[k].weight>=0)  //仅在根节点中找

if (tree[k].weight<min1)

{

min2=min1;

min_i2=min_i1;

min1=tree[k].weight;

min_i1=k;

}

else 

if (tree[k].weight<min2) {

min2=tree[k].weight;

min_i2=k;

}

tree[i].weight=min1+min2;  // 合并

tree[min_i1].weight *= -1;

 

tree[min_i2].weight *= -1;

tree[i].lchild=min_i1;

tree[i].rchild=min_i2;

}

return tree;

}

void CreateHuffcode(huffnode tree[], int i, char s[])

//已知tree[i]节点的编码序列为s,求该节点下所有叶子节点的编码序列。

{ char s1[N],c;

if(i!=-1) 

if (tree[i].lchild==-1 && tree[i].rchild==-1) 

c=tree[i].data; 

strcpy(codeset[c-32].code, s);

}

else {

strcpy(s1, s);  strcat(s1, "0");

CreateHuffcode(tree, tree[i].lchild, s1);

strcpy(s1, s);  strcat(s1, "1");

CreateHuffcode(tree, tree[i].rchild, s1);

}

return;

 

void PrintHufftree(huffnode tree[], int n)      //输出tree中的Huffman

  

{

   int i;

   printf("Huffman tree :\n");

   printf("i\tValue\tLchild\tRchild\tWeight\n");

   for(i=2*n-2;i>=0;i--)

  

 

 {

      printf("%d\t",i);

      printf("%c\t",tree[i].data);

      printf("%d\t",tree[i].lchild);

      printf("%d\t",tree[i].rchild);

      printf("%d\t",tree[i].weight);

      printf("\n");

   }

}

 

 

 

 

 

void EnCoding(char str[], char hfmstr[])

{

//根据codeset编码表,逐个将str字符串中的字符转化为它的huffman编码,结果编码串放在hfmstr字符串中

int i, j;

hfmstr[0]='\0';

i=0;

while(str[i]!='\0')   

    {

j=str[i]-32;

strcat(hfmstr, codeset[j].code);

i++;

}

}

void DeCoding(huffnode tree[], int n, char hfmstr[], char decodestr[])

//根据tree数组中的huffman,逐个对hfmstr字符串中的字符进行译码,结果放在decodestr字符串中

{

int i=0,j=0;

huffnode p;

p=tree[2*n-2];

while(hfmstr[i]!='\0')

{while(p.lchild!=-1&&p.rchild!=-1)

{

if(hfmstr[i]=='0')

{

p=tree[p.lchild];

}

 

else if(hfmstr[i]=='1')

{

p=tree[p.rchild];

}

i++;

}

decodestr[j]=p.data;j++;

p=tree[2*n-2];

}

 

}

float CompressRatio(char str[], char hfmstr[])  //计算并返回压缩比

{

float w,a=1,b=1;

int i;

 

 

for(i=0;str[i]!='\n';i++)

a++;

a=a*8;

for(i=0;hfmstr[i]!='\n';i++)

b++;

w=a/b;

return w;

}

void main()

{  

int i,j;

float ratio;  //压缩比

huffnode ht; //Huffman

char data[N]; //要编码的字符集合

int  weight[N]; //字符集合中各字符的权重(频率)

int n=0; //字符集合中字符的个数

char str[1000];         //需输入的原始字符串  

char hfm_str[1000]=""; //编码后的字符串

char decode_str[1000]="";//解码后的字符串

printf("输入要转换的字符串\n");

gets(str);

for(i=0;i<N;i++) { //初始化编码表,频率为0,编码串为空串

codeset[i].count=0;

codeset[i].code[0]='\0';

}

 

i=0; 

while(str[i]!='\0') { //统计原始字符串中各字符出现的频率,存入编码表

j=str[i]-32;

codeset[j].count++; //codeset[0]~[95]对应ascii32~127的字符

i++;

}

for(i=0;i<N;i++) //统计原始字符串中出现的字符个数

if(codeset[i].count!=0) n++;

printf("字符频率统计:\n"); //显示统计结果

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

if(codeset[i].count!=0) printf("%c:%d, ", i+32, codeset[i].count);

printf("\n");

j=0;

for(i=0;i<N;i++) //生成要编码的字符集合,以及权重

if (codeset[i].count!=0) {

data[j]=i+32;

weight[j]=codeset[i].count;

 

   j++;

}

ht=CreateHufftree(data,weight,n);  //建立Huffman,根节点是ht[2*n-2]

    PrintHufftree(ht,n); //显示Huffman树的存储结果

CreateHuffcode(ht, 2*n-2, "");  //ht[2*n-2]为根,以空字符串为起始编码字符串,求出各叶子节点的编码字符串

//显示codeset中的Huffman编码,参见"显示频率统计结果"的代码.

    printf("haffman编码为:\n");

    for(i=0;i<N;i++){

if(codeset[i].count!=0)

    printf("%c:%s\n",i+32,codeset[i].code );

 

}

EnCoding(str, hfm_str);  //str字符串进行编码,放在hfm_str字符串中

printf("编码序列%s\n",hfm_str);

ratio=CompressRatio(str, hfm_str); //计算压缩比

printf("压缩比%3.2f\n",ratio);

DeCoding(ht, n, hfm_str, decode_str); //hfm_str字符串进行译码,放在decode_str字符串中

printf("解码后的字符串%s\n",decode_str);

free(ht);  //释放Huffman

}

 

 

 

6、实验截图二叉树的应用


二叉树的应用

 

 

7、实验体会:、

实验前有老师给的已经编好的一部分程序,大大减少了工作来量。通过上机实验,我进一步掌握指针变量和动态变量的含义你,掌握二叉树的结构特性,以及各种存储结构的特点及适用范围,掌握用指针类型描述、访问和处理二叉树的运算。二叉树也是递归定义的,其结点有左右子树之分,逻辑上二叉树有多种形态为了扩展知识,我从网上查阅了一些关于树的知识。尽管二叉树与树有许多相似之处,但二叉树不是树的特殊情形树是由一个或多个结点组成的有限集合,其中: 

⒈必有一个特定的称为根(ROOT)的结点;  

⒉剩下的结点被分成n>=0个互不相交的集合T1、T2、......Tn,而且, 这些集合的每一个又都是树。树T1、T2、......Tn被称作根的子树(Subtree)。
树结构的特点是:它的每一个结点都可以有不止一个直接后继,除根结点外的所有结点都有且只有一个直接前驱。二叉树很象一株倒悬着的树,从树根到大分枝、小分枝、直到叶子把数据联系起来,这种数据结构就叫做树结构,简称树。树中每个分叉点称为结点,起始结点称为树根,任意两个结点间的连接关系称为树枝,结点下面不再有分枝称为树叶 普通树转二叉树,一般采用左“子女”右“兄弟”的方式来转化。  

希望自己在这门课中可以学到更多的知识,多点知识总是好的。


原文地址:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值