数据结构---哈夫曼树(C语言看了就懂教程)

哈夫曼树是一种用于数据压缩和编码的数据结构,由DavidA.Huffman提出。这种树的特性是所有叶子节点的度数为0,总共有2n-1个节点,且具有最小带权路径长度。构造哈夫曼树的过程包括构造森林、选择最小节点合并等步骤,通常通过排序和结构体表示节点。提供的代码示例展示了如何用C语言实现哈夫曼树的构建过程。
摘要由CSDN通过智能技术生成

1.概念:

    哈夫曼树(Huffman Tree)是一种常用的数据结构,用于实现数据压缩和编码。它是由美国计算机科学家David A. Huffman于1952年提出的,被广泛应用于通信、压缩算法和信息存储等领域。

2.性质:

    1.哈夫曼树的结点的度数为0或2,没有度数为1的结点。

    2.包含n个叶子结点的哈夫曼树中共有2n-1个结点。

    3.其带权路径长度WPL最小的二叉树,且称为最优二叉树或哈夫曼树。

        WPL = 权值 * 深度;

3.步骤

    口诀:

    ①构造森林全是根

    ②选用两小造新树

    ③删除两小添新人

    ④重复②③操作,直到只剩一棵树

4.图例分析

    以下图例能够简单且很直观得看出并推导出N个权值根的Huffmantree构造过程。

 

5.哈夫曼树算法分析

    像我们已知哈夫曼树框架就是类似于连连看,先是一个个的独立的点(根),然后将其中点数最小的两个点,连接在一个新的点上,这个新的点的点数就是两个小点的点数之和,然后循环往复,获得最后一个点,此时这些点之间的关系就是哈夫曼树逻辑联系。

    ①构造森林全是根

    第一步应该是先将一个个独立的点(根)创建出来,你得先知道这个点(根)它包含了哪些属性,作为一个程序开发者,你需要考虑的就是用什么变量来存放且描述这个点(根)

    最简单的哈夫曼树他就是一颗最基本的二叉树,他拥有权值域,指针域---(父结点,左孩子结点,右孩子结点)

    此时就可以考虑用结构体来存放这些点(根)   

 /*结构体*/

    typedef struct {

        int weight; //权值

        int parent,lchild,rchild;   //父节点和左右孩子节点

    }HTNode, *HuffmanTree;

    ②选用两小造新树

    如何选用两个权值最小的根去造新树,这是不用细说的吧,就是使用排序算法就可以了,找到最小的两个权值的下标,将其指针域中的父节点,指向新的结点,并使新的根左右孩子指向子节点!

    ③删除两小添新人

    找到森林中最小的两个根作为子节点去构造一颗树,然后将之前的结点删除(删除肯定是不需要删除的,只是得有个标志位)

    当其作为子节点去构造一颗树的时候,那它的指针域中的父结点,肯定不为空,这就是标志位!

    ②③步循环逻辑使用代码逻辑

        循环使用for循环,使用的次数就是,要新建结点的个数
       

 Select_min_tree(HT, i-1);                           //找到两个最小值的下标 s1,s2

        HT[s1].parent = i;

        HT[s2].parent = i;

        HT[i].lchild = s1;

        HT[i].rchild = s2;

        HT[i].weight = HT[s1].weight+HT[s2].weight;         //创造的森林根结点的权值为两个子节点的权值和

6.代码

    代码以该图去编写代码,能理解该图基本就能懂上述讲解的逻辑思路


 

 大家对于细节不懂的问题,第一可以试着去运行代码(调试运行)这样更能深刻,且贴切的理解代码的运行过程,以及地址空间的存取过程。

完整代码:

#include <stdio.h>
#include <stdlib.h>

/*口诀:
①构造森林全是根
②选用两小造新树
③删除两小添新人
④重复②③操作,直到只剩一棵树*/

//首先创建二叉树结构体
//创建函数---找出森林里最小的两颗树
//编写创建函数---两颗树变成一颗树,并删除两颗小树,添加合成之后的树到森林里面,直到只剩一棵树

/*结构体*/
typedef struct {
    int weight; //权值
    int parent,lchild,rchild;   //父节点和左右孩子节点
}HTNode, *HuffmanTree;
//二维数组字符

int s1 ,s2 = 0;                                             //创建两个全局变量存放下标值

/*init 初始化函数*/
HTNode *huffmantree_init(int n) 
{
    int i;
    HTNode *HT = (HTNode*)malloc(sizeof(HTNode));   //申请2n-1个节点空间
    //初始化哈夫曼树的各个节点,只需要2n-1个
    for(i = 1; i<=(2*n-1); i++)                             //创造没有子森林的森林
    {
        HT[i].parent = 0;
        HT[i].lchild = 0;
        HT[i].rchild = 0;
        if(i <= n)
        {
            printf("输入第%d颗树的权值:",i);
            scanf("%d",&(HT[i].weight));
        }  
    }
    return HT;
}
/*select函数*/
int Select_min_tree(HTNode *T, int n)                       //找出森林里最小的两棵树
{
    s1 = 0;
    s2 = 0;
    int min1,min2,i= 0;
    for(i = 1;i <= n;i++)                                   //初始化两个祖先变量
    {
        if(T[i].parent == 0 && s1 == 0)                     //前提是没有父节点,意思就是森林中的根结点
        {
            min1 = T[i].weight;
            s1 = i;
        }
        else if(T[i].parent == 0 && s2 == 0)                //前提是没有父节点,意思就是森林中的根结点
        {
            min2 = T[i].weight; 
            s2 = i;
            if(min2 < min1)
            {
                min2 = min1 ;
                min1 = T[i].weight;
                s2 = s1;
                s1 = i;
                
            }
            break;
        }
    }
    for(i = 2;i < n;i++)                                    //找出最小的两个值min1,min2
    {
        if((T[i].weight < min2) && T[i].parent == 0 && i != s1)
        {
            if(T[i].weight < min1)
            {
                min2 = min1;
                s2 = s1;
                min1 = T[i].weight;
                s1 = i;
            }
            else 
            {
                min2 = T[i].weight;
                s2 = i;
            }
        }  
    }
}

//构建哈夫曼树
int CreateHuffmanTree(HTNode *HT, int n, int m)
{
    //如果只有一棵树 那就直接跳出
    if(n <= 1)
    return 0;
    int i;
    for(i = n+1; i <= m; i++)
    {
        Select_min_tree(HT, i-1);                           //找到两个最小值的下标 s1,s2
        HT[s1].parent = i;
        HT[s2].parent = i;
        HT[i].lchild = s1;
        HT[i].rchild = s2;
        HT[i].weight = HT[s1].weight+HT[s2].weight;         //创造的森林根结点的权值为两个子节点的权值和
    }
}
//打印函数Huffmantree();
void Print_huffmantree_demo(HTNode *HT,int n,int m) 
{
    int i ;
    for(i = 0;i<=m; i++)
    {
        printf("权值:%d\n",HT[i].weight);
    }
}

int main()
{                                   
    int n;
    printf("请输入森林中子树的数量:");
    scanf("%d",&n);
    HTNode *HT;
    int m = 2*n-1;
    HT = huffmantree_init(n);                               //初始化huffmantree根结点
    CreateHuffmanTree(HT,n,m);                              //创建huffmantree实现逻辑
    Print_huffmantree_demo (HT,n,m);                         //打印huffmantree
    return 0;
}

   

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

底层电工人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值