哈夫曼树的构造以及代码实现

一、哈夫曼树的构造

注意:哈夫曼树并不唯一,但带权路径长度一定是相同的。哈夫曼树构建转载该文

  • (1)8个结点的权值大小如下:
    在这里插入图片描述
  • (2)从19,21,2,3,6,7,10,32中选择两个权小结点。选中2,3。同时算出这两个结点的和5。
    在这里插入图片描述
  • (3)从19,21,6,7,10,32,5中选出两个权小结点。选中5,6。同时计算出它们的和11。
    在这里插入图片描述
  • (4)从19,21,7,10,32,11中选出两个权小结点。选中7,10。同时计算出它们的和17。
    (BTW:这时选出的两个数字都不是已经构造好的二叉树里面的结点,所以要另外开一棵二叉树;或者说,如果两个数的和正好是下一步的两个最小数的其中的一个,那么这个树直接往上生长就可以了,如果这两个数的和比较大,不是下一步的两个最小数的其中一个,那么就并列生长。
    在这里插入图片描述
  • (5)从19,21,32,11,17中选出两个权小结点。选中11,17。同时计算出它们的和28。
    在这里插入图片描述
  • (6)从19,21,32,28中选出两个权小结点。选中19,21。同时计算出它们的和40。另起一颗二叉树。
    在这里插入图片描述
  • (7)从32,28, 40中选出两个权小结点。选中28,32。同时计算出它们的和60。
    在这里插入图片描述
  • (8)从 40, 60中选出两个权小结点。选中40,60。同时计算出它们的和100。 好了,此时哈夫曼树已经构建好了。
    在这里插入图片描述

二、代码实现

#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cstdio>
using namespace std;
struct BTreeNode
{
	int data;
	struct BTreeNode* left;
	struct BTreeNode* right;
};
//一般打印输的结点
void Print_BTree(struct BTreeNode* BT)
{
	if (BT != NULL)
    {
        printf("%d", BT->data); //输出根结点的值
        if (BT->left != NULL || BT->right != NULL)
        {
            printf("(");
            Print_BTree(BT->left); //输出左子树
            if (BT->right != NULL)
                printf(",");
            Print_BTree(BT->right); //输出右子树
            printf(")");
        }
    }
}
//创建一颗哈夫曼树
struct BTreeNode* CreateHuffman(int a[],int n)
{
	struct BTreeNode **b;//结构体指针的指针b作为指针数组
	struct BTreeNode *q;//定义一个结构体P
	b=(BTreeNode**)malloc(n*sizeof(struct BTreeNode*));
	//对指针数组b进行初始化
	for(int i=0;i<n;i++)//初始化b指针数组,使每个指针元素指向a数组中对应的元素结点
	{
		b[i]=(BTreeNode*)malloc(n*sizeof(struct BTreeNode*));
		b[i]->data=a[i];
		b[i]->left=NULL;
		b[i]->right=NULL;
	}
	//利用循环创建一颗哈夫曼树
	for(int i=1;i<n;i++)//一共进行n-1次循环
	{
		int k1=-1,k2;
		for(int j=0;j<n;j++)//让k1初始指向森林中第一棵树,k2指向第二棵
		{
			if(b[j]!=NULL&&k1==-1)
			{
				k1=j;
				continue;
			}
			if(b[j]!=NULL)
			{
				k2=j;
				break;
			}
		}
		//从当前除过第一个结点之外的最小的那个结点
		for(int j=k2;j<n;j++)
		{
			if(b[j]!=NULL)
			{
				if(b[j]->data<b[k1]->data)
				{
					k2=k1;
					k1=j;
				}
				if(b[j]->data>b[k2]->data)
				{
					k2=j;
				}
			}
		}
		//利用最小值数和次小值树,建立哈夫曼树,将每次返回树根指针q;
		q=(BTreeNode*)malloc(sizeof(struct BTreeNode));
		q->data=b[k1]->data+b[k2]->data;//树根结点存放的是总路径
		q->left=b[k1];
		q->right=b[k2];
		b[k1]=q;//更新结点(将最新的根节点付给b[k1]当作是新的根节点)
		b[k2]=NULL;//将b[k2]指针置空
	}
	free(b);//将建立的动态数组释放
	return q;//放回根节点的指针
}
//求哈夫曼树的路径长度
int 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);
    }
}
//哈夫曼树解码
void Coding(struct BTreeNode *FBT,int len)
{
	static int a[10];//用来存储密码0  1
	if(FBT!=NULL)
	{
		if(FBT->left==NULL&&FBT->right==NULL)
		{
			printf("j结点权值为 %d 的编码:",FBT->data);
			for(int i=0;i<len;i++)
			{
				cout<<a[i]<<" ";
			}
			cout<<endl;
		}
		else
		{//遍历的层数加1
			a[len]=0;//左节点为0
			Coding(FBT->left,len+1);//采用递归实现
			a[len]=1;//右结点为1
			Coding(FBT->right,len+1);
		}
	}
}
//主函数
int main()
{
	int n;
	static int a[10];
	struct BTreeNode *fbt;
	cout<<"请输入节点数n :";
	cin>>n;//输入一共有多少个结点
	cout<<"请输入"<<n<<"个数作为权值:";
	for(int i=0;i<n;i++)//输入节点数
	{
		cin>>a[i];//作为权值
	}
	fbt=CreateHuffman(a,n);
	fbt = CreateHuffman(a, n);
	cout<<"打印一般的树的:";
	Print_BTree(fbt);
	cout<<endl;
	int t=WeightPathLength(fbt,0);
	cout<<"哈夫曼树的路径长度:"<<t<<endl;
	cout<<"哈夫曼树编码:"<<endl;
	Coding(fbt,0);
	return 0;
}
哈夫曼树是一种经典的数据结构,常用于数据压缩和编码。下面是C语言中哈夫曼树构造代码实现: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 typedef struct { int weight; int parent; int lchild; int rchild; } HTNode, *HuffmanTree; void Select(HuffmanTree HT, int n, int *s1, int *s2) { int i, min1, min2; min1 = min2 = MAX_SIZE; *s1 = *s2 = 0; for (i = 1; i <= n; i++) { if (HT[i].weight < min1 && HT[i].parent == 0) { min2 = min1; *s2 = *s1; min1 = HT[i].weight; *s1 = i; } else if (HT[i].weight < min2 && HT[i].parent == 0) { min2 = HT[i].weight; *s2 = i; } } } void CreateHuffmanTree(HuffmanTree *HT, int n) { if (n <= 1) { return; } int m = 2 * n - 1; *HT = (HuffmanTree) malloc((m + 1) * sizeof(HTNode)); HuffmanTree p; int i; for (p = *HT + 1, i = 1; i <= n; ++i, ++p) { scanf("%d", &p->weight); 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; } int s1, s2; for (i = n + 1; i <= m; ++i) { Select(*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; } } int main() { HuffmanTree HT; int n; printf("请输入叶子节点的个数:"); scanf("%d", &n); printf("请输入每个叶子节点的权值:"); CreateHuffmanTree(&HT, n); printf("哈夫曼树构造成功!\n"); return 0; } ``` 以上代码实现哈夫曼树构造,其中`Select`函数用于在哈夫曼树中选择权值最小的两个节点,`CreateHuffmanTree`函数用于构造哈夫曼树。在主函数中,用户需要输入叶子节点的个数和每个叶子节点的权值,程序会自动构造哈夫曼树并输出构造成功的信息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值