《数据结构与算法》C语言 实验报告 哈夫曼树实现

简介: 《数据结构与算法》C语言 实验报告 哈夫曼树实现

image.png


《数据结构与算法》

实验报告

实验名称      哈夫曼树实现      

     信息与通信工程学院      

年级专业 20级智能科学与技术      

      孙成                  

      20203101694            

指导教师   冯思玲                

   2020 2021 学年第    学期



实验报告正文



实验目的

使用C语言实现哈夫曼树


实验内容及要求

1、问题描述


利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。构造哈夫曼树时,首先将由n个字符形成的n个叶子结点存放到数组HuffNode的前n个分量中,然后根据哈夫曼方法的基本思想,不断将两个较小的子树合并为一个较大的子树,每次构成的新子树的根结点顺序放到HuffNode数组中的前n个分量的后面。通俗的来讲,哈弗曼树就是一种广泛应用的二叉树,哈弗曼树可以用来构造最优编码,用于信息的传输,压缩等方面哈弗曼树也可以理解为,最小二叉树,最优二叉树。


2、主要数据类型与变量


struct BTreeNode  

{  

   ElemType data;  

   struct BTreeNode* left;  

   struct BTreeNode* right;  

};  

3、算法或程序模块


3、求哈夫曼树的带权路径长度  

ElemType WeightPathLength(struct BTreeNode* FBT, int len)//len初始为0  

{  

   if (FBT == NULL) //空树返回0  

       return 0;  

   else  

   {  

       if (FBT->left == NULL && FBT->right == NULL)//访问到叶子结点  

           return FBT->data * len;  

       else //访问到非叶子结点,进行递归调用,返回左右子树的带权路径长度之和,len递增  

           return WeightPathLength(FBT->left,len+1)+WeightPathLength(FBT->right,len+1);  

   }  

}  

 

//4、哈夫曼编码(可以根据哈夫曼树带权路径长度的算法基础上进行修改)  

void HuffManCoding(struct BTreeNode* FBT, int len)//len初始值为0  

{  

   static int a[10];//定义静态数组a,保存每个叶子的编码,数组长度至少是树深度减一  

   if (FBT != NULL)//访问到叶子结点时输出其保存在数组a中的0和1序列编码  

   {  

       if (FBT->left == NULL && FBT->right == NULL)  

       {  

           int i;  

           printf("结点权值为%d的编码:", FBT->data);  

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

               printf("%d", a[i]);  

           printf("\n");  

       }  

       else//访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组a  

       {   //的对应元素中,向下深入一层时len值增1  

           a[len] = 0;  

           HuffManCoding(FBT->left, len + 1);  

           a[len] = 1;  

           HuffManCoding(FBT->right, len + 1);  

       }  

   }  

}  

测试

方案

从键盘输入待构造的哈夫曼树中带权叶子结点数n:6


从键盘输入6个整数作为权值:3 9 5 12 6 15


结果

总结与讨论



image.png


通过不断地调试,实现了最终的稳定运行结果


附:程序源代码


  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3. typedef int ElemType;  
  4. struct BTreeNode  
  5. {  
  6.    ElemType data;  
  7.    struct BTreeNode* left;  
  8.    struct BTreeNode* right;  
  9. };  
  10.  
  11. //1、输出二叉树,可在前序遍历的基础上修改。采用广义表格式,元素类型为int  
  12. void PrintBTree_int(struct BTreeNode* BT)  
  13. {  
  14.    if (BT != NULL)  
  15.    {  
  16.        printf("%d", BT->data); //输出根结点的值  
  17.        if (BT->left != NULL || BT->right != NULL)  
  18.        {  
  19.            printf("(");  
  20.            PrintBTree_int(BT->left); //输出左子树  
  21.            if (BT->right != NULL)  
  22.                printf(",");  
  23.            PrintBTree_int(BT->right); //输出右子树  
  24.            printf(")");  
  25.        }  
  26.    }  
  27. }  
  28.  
  29. //2、根据数组 a 中 n 个权值建立一棵哈夫曼树,返回树根指针  
  30. struct BTreeNode* CreateHuffman(ElemType a[], int n)  
  31. {  
  32.    int i, j;  
  33.    struct BTreeNode **b, *q;  
  34.    b = malloc(n*sizeof(struct BTreeNode));  
  35.    for (i = 0; i < n; i++) //初始化b指针数组,使每个指针元素指向a数组中对应的元素结点  
  36.    {  
  37.        b[i] = malloc(sizeof(struct BTreeNode));  
  38.        b[i]->data = a[i];  
  39.        b[i]->left = b[i]->right = NULL;  
  40.    }  
  41.    for (i = 1; i < n; i++)//进行 n-1 次循环建立哈夫曼树  
  42.    {  
  43.        //k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标  
  44.        int k1 = -1, k2;  
  45.        for (j = 0; j < n; j++)//让k1初始指向森林中第一棵树,k2指向第二棵  
  46.        {  
  47.            if (b[j] != NULL && k1 == -1)  
  48.            {  
  49.                k1 = j;  
  50.                continue;  
  51.            }  
  52.            if (b[j] != NULL)  
  53.            {  
  54.                k2 = j;  
  55.                break;  
  56.            }  
  57.        }  
  58.        for (j = k2; j < n; j++)//从当前森林中求出最小权值树和次最小  
  59.        {  
  60.            if (b[j] != NULL)  
  61.            {  
  62.                if (b[j]->data < b[k1]->data)  
  63.                {  
  64.                    k2 = k1;  
  65.                    k1 = j;  
  66.                }  
  67.                else if (b[j]->data < b[k2]->data)  
  68.                    k2 = j;  
  69.            }  
  70.        }  
  71.        //由最小权值树和次最小权值树建立一棵新树,q指向树根结点  
  72.        q = malloc(sizeof(struct BTreeNode));  
  73.        q->data = b[k1]->data + b[k2]->data;  
  74.        q->left = b[k1];  
  75.        q->right = b[k2];  
  76.  
  77.        b[k1] = q;//将指向新树的指针赋给b指针数组中k1位置  
  78.        b[k2] = NULL;//k2位置为空  
  79.    }  
  80.    free(b); //删除动态建立的数组b  
  81.    return q; //返回整个哈夫曼树的树根指针  
  82. }  
  83.  
  84. //3、求哈夫曼树的带权路径长度  
  85. ElemType WeightPathLength(struct BTreeNode* FBT, int len)//len初始为0  
  86. {  
  87.    if (FBT == NULL) //空树返回0  
  88.        return 0;  
  89.    else  
  90.    {  
  91.        if (FBT->left == NULL && FBT->right == NULL)//访问到叶子结点  
  92.            return FBT->data * len;  
  93.        else //访问到非叶子结点,进行递归调用,返回左右子树的带权路径长度之和,len递增  
  94.            return WeightPathLength(FBT->left,len+1)+WeightPathLength(FBT->right,len+1);  
  95.    }  
  96. }  
  97.  
  98. //4、哈夫曼编码(可以根据哈夫曼树带权路径长度的算法基础上进行修改)  
  99. void HuffManCoding(struct BTreeNode* FBT, int len)//len初始值为0  
  100. {  
  101.    static int a[10];//定义静态数组a,保存每个叶子的编码,数组长度至少是树深度减一  
  102.    if (FBT != NULL)//访问到叶子结点时输出其保存在数组a中的0和1序列编码  
  103.    {  
  104.        if (FBT->left == NULL && FBT->right == NULL)  
  105.        {  
  106.            int i;  
  107.            printf("结点权值为%d的编码:", FBT->data);  
  108.            for (i = 0; i < len; i++)  
  109.                printf("%d", a[i]);  
  110.            printf("\n");  
  111.        }  
  112.        else//访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组a  
  113.        {   //的对应元素中,向下深入一层时len值增1  
  114.            a[len] = 0;  
  115.            HuffManCoding(FBT->left, len + 1);  
  116.            a[len] = 1;  
  117.            HuffManCoding(FBT->right, len + 1);  
  118.        }  
  119.    }  
  120. }  
  121.  
  122. //主函数  
  123. void main()  
  124. {  
  125.    int n, i;  
  126.    ElemType* a;  
  127.    struct BTreeNode* fbt;  
  128.    printf("从键盘输入待构造的哈夫曼树中带权叶子结点数n:");  
  129.    while(1)  
  130.    {  
  131.        scanf("%d", &n);  
  132.        if (n > 1)  
  133.            break;  
  134.        else  
  135.            printf("重输n值:");  
  136.    }  
  137.    a = malloc(n*sizeof(ElemType));  
  138.    printf("从键盘输入%d个整数作为权值:", n);  
  139.    for (i = 0; i < n; i++)  
  140.        scanf(" %d", &a[i]);  
  141.    fbt = CreateHuffman(a, n);  
  142.    printf("广义表形式的哈夫曼树:");  
  143.    PrintBTree_int(fbt);  
  144.    printf("\n");  
  145.    printf("哈夫曼树的带权路径长度:");  
  146.    printf("%d\n", WeightPathLength(fbt, 0));  
  147.    printf("树中每个叶子结点的哈夫曼编码:\n");  
  148.    HuffManCoding(fbt, 0);  
  149. }  

相关文章
|
2月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
68 1
|
24天前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
|
24天前
|
C语言
数据结构基础详解(C语言):图的基本概念_无向图_有向图_子图_生成树_生成森林_完全图
本文介绍了图的基本概念,包括图的定义、无向图与有向图、简单图与多重图等,并解释了顶点度、路径、连通性等相关术语。此外还讨论了子图、生成树、带权图及几种特殊形态的图,如完全图和树等。通过这些概念,读者可以更好地理解图论的基础知识。
|
26天前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
26天前
|
存储 算法 C语言
数据结构基础详解(C语言):单链表_定义_初始化_插入_删除_查找_建立操作_纯c语言代码注释讲解
本文详细介绍了单链表的理论知识,涵盖单链表的定义、优点与缺点,并通过示例代码讲解了单链表的初始化、插入、删除、查找等核心操作。文中还具体分析了按位序插入、指定节点前后插入、按位序删除及按值查找等算法实现,并提供了尾插法和头插法建立单链表的方法,帮助读者深入理解单链表的基本原理与应用技巧。
|
26天前
|
存储 C语言 C++
数据结构基础详解(C语言) 顺序表:顺序表静态分配和动态分配增删改查基本操作的基本介绍及c语言代码实现
本文介绍了顺序表的定义及其在C/C++中的实现方法。顺序表通过连续存储空间实现线性表,使逻辑上相邻的元素在物理位置上也相邻。文章详细描述了静态分配与动态分配两种方式下的顺序表定义、初始化、插入、删除、查找等基本操作,并提供了具体代码示例。静态分配方式下顺序表的长度固定,而动态分配则可根据需求调整大小。此外,还总结了顺序表的优点,如随机访问效率高、存储密度大,以及缺点,如扩展不便和插入删除操作成本高等特点。
|
26天前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
26天前
|
存储 C语言
数据结构基础详解(C语言): 栈与队列的详解附完整代码
栈是一种仅允许在一端进行插入和删除操作的线性表,常用于解决括号匹配、函数调用等问题。栈分为顺序栈和链栈,顺序栈使用数组存储,链栈基于单链表实现。栈的主要操作包括初始化、销毁、入栈、出栈等。栈的应用广泛,如表达式求值、递归等场景。栈的顺序存储结构由数组和栈顶指针构成,链栈则基于单链表的头插法实现。
151 3
|
26天前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
2月前
|
算法 Java 测试技术
算法分析(蛮力法与减治算法应用实验报告)
这篇文章是关于算法分析的实验报告,介绍了如何使用蛮力法解决背包问题,并通过伪代码和Java代码实现,同时分析了其时间效率;还介绍了基于减治法思想实现的二叉查找树的插入与查找,同样提供了伪代码、Java源代码实现和时间效率分析,最后展示了测试结果截图。
算法分析(蛮力法与减治算法应用实验报告)
下一篇
无影云桌面