赫夫曼树的建立

文章目录

赫夫曼树的建立

#define _CRT_SECURE_NO_WARNINGS  1
#pragma warning(disable:6031)
#include<stdio.h>
#include<stdlib.h>
#define N 15
#define M 2*N-1
typedef struct node
{
    char data;//存的数据
    int weight;//权重
    int parent;//双亲的数组下标
    int lchild;//左孩子的数组下标
    int rchild;//右孩子的数组下标
    int flag;//标志这个节点是否已经被查找到,并构造成树过
} Hffmantree;//

int select(Hffmantree* H, int n);//查找剩余未被构造成数的节点中权重最小的节点
void init_H(Hffmantree* H, int n);//初始化赫夫曼树
void create_H(Hffmantree* H, int n);//创建赫夫曼树
void traverse_H(Hffmantree* H, int n);//遍历输出赫夫曼树

int main()
{
    int n;
    printf("请输入该赫夫曼树的叶子节点个数:");
    scanf("%d", &n);//便于区分已有的叶子节点下标和新创建的“根节点”的数组下标
    Hffmantree H[M+1];
    int i;
    for (i = 1; i <= n; i++)
    {
        H[i].data = 64 + i;
        H[i].weight = i;
    }//存入赫夫曼树节点的数据'A','B','C','D'......
    for (i = n+1; i <= 2*n-1; i++)
    {
        H[i].data = ' ';
    }
    init_H(H, n);
    traverse_H(H, n);//输出一次初始化的赫夫曼树
    create_H(H, n);
    traverse_H(H, n);//输出一次构造好的赫夫曼树
}

void init_H(Hffmantree *H, int n)
{
    int i = 0;
    for (i = 1; i <= n; i++)
    {
        H[i].parent = 0;
        H[i].lchild = 0;
        H[i].rchild = 0;
        H[i].flag = 0;
    }//初始化原本的叶子节点
    for (i = n + 1; i <= 2 * n - 1; i++)
    {
        H[i].weight = 0;
        H[i].parent = 0;
        H[i].lchild = 0;
        H[i].rchild = 0;
        H[i].flag = 0;
    }//初始化将要构造的“根节点”
}

int select(Hffmantree* H, int n)
{
    int i = 0;
    int min=0;//存放权重最小节点的权重值
    int dex=0;//存放权重最小的节点的下标
    for (i = 0; i <= n; i++)
    {
        if (H[i].flag == 0)
        {
            min = H[i].weight;
            dex = i;
            break;
        }
    }//为避免min和dex值不合理,用一个for循环找到第一个为被查找到过的节点的下标和权重作为min和dex的初始化值
    for (i = 0; i <= n; i++)
    {
        if (H[i].flag == 0)
        {
            if (H[i].weight < min)
            {
                min = H[i].weight;
                dex = i;
            }
        }
    }//找到最小权重的节点的权重值和下标
    H[dex].flag = 1;//改写flag为1,标志该结点已被查找过
    return dex;//返回最小权重节点的下标
}

void create_H(Hffmantree* H, int n)
{
    int i = n + 1;
    for (i = n + 1; i <= 2 * n - 1; i++)//从结构体数组的第n-1位开始创建“根节点”
    {
        int a;
        a = select(H, i - 1);//查找当前最小权值的节点下标
        int b;
        b = select(H, i - 1);//查找第二小权值的节点下标(当然它也就是查找完最小权值节点之后最小的权值节点)
        H[i].weight = H[a].weight + H[b].weight;//存储“根节点”的权重
        H[i].lchild = a;//存储“根节点”的左孩子下标
        H[i].rchild = b;//存储“根节点”的右孩子下标
        H[a].parent = i;//将左孩子的双亲下标存入
        H[b].parent = i;//将右孩子的双亲下标存入
    }
}

void traverse_H(Hffmantree* H, int n)
{
    int i = 0;
    printf("当前的赫夫曼树:\n");
    for (i = 1; i <= 2 * n - 1; i++)
    {
        printf("%d %c %d %d %d %d %d \n",i, H[i].data, H[i].weight, H[i].parent, H[i].lchild, H[i].rchild, H[i].flag);
    }//遍历输出
    printf("\n");
}

思路

百度图片
-------------------------------从一个博主那里顺来的百度图片(感谢万分)--------------------------------------

如图所示

大致思路:

将所有具有权重的叶子节点一字排开,在其中找到的权重最小的两个叶子节点借助一个新的节点(根)链接成一棵树(一般两个节点中权重小的为左孩子,更大的为右孩子),这个根的权重就等于那两个叶子节点的权重之和,然后再将这个根放在那一堆还未选出的叶子节点中进行比较,再找到其中两个最小的节点链接成一棵树,反复重复上述操作,直到构建成一棵完整的赫夫曼树(本质上就上让权重越大的叶子节点越靠近根节点)

构造步骤

借助一个结构体数组存储这个赫夫曼树,结构体中包含权重,双亲的数组下标,左孩子的数组下标,右孩子的数组下标,一个标志节点是否已被建造的flag(直接用双亲判断也可以);
1.先初始化这个赫夫曼树
将结构体中所有的数据赋予0值。
2.创造赫夫曼树(借助一个函数寻找最小权重的两个节点)
从第n+1个数组位置开始创建用来链接两个叶子节点的“根节点”,在创建每一个“根节点”时,要,将两个叶子节点的双亲的数组下标存入(也就是当前这个根节点的下标),要存储“根节点”的权重,左右孩子的数组下标;在寻找最小权重的两个叶子节点的函数中,每找到一个节点时,记得将这个节点的flag值改为1,便于后续查找剩余节点中的最小节点时,可以跳过这个节点。
3.遍历输出赫夫曼树
很简单,直接将数组的每一位输出即可。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值