哈夫曼树构造算法的实现

一、哈夫曼(Huffman)树的基本概念

1、树的带权路径长度:树中所有叶子结点的带权路径长度之和;
在这里插入图片描述
2、哈夫曼树:带权路径长度WPL最小的二叉树称作最优二叉树或哈夫曼树。

例如:
在这里插入图片描述

二、哈夫曼树的构造算法实现

(1)Huffman树中结点的结构可设计成4分量形式:
在这里插入图片描述

typedef struct{
    int weight;//权值分量(可放大取整)
    int parent,lchild,rchild; //双亲和孩子分量
}HTNode,*HuffmanTree;//用动态数组存储Huffman树

哈夫曼树的各个节点就存储在HuffmanTree定义的动态数组中,数组0号单元不用,从1号开始使用。将叶子节点集中存储在数组前面的n个位置。
(2)算法思想
1.初始化:动态申请2n个单元,将HT[1…2n-1]中的lchild=rchild=parent=0; 输入n个叶子结点的权值,即设置HT[1…n]的weight值。

void CreatHuffmanTree(HuffmanTree &HT, int n){//算法5.10 创建哈夫曼树
	if (n<=1) return ;
	int m = 2*n-1;
	HT = new HTNode[m+1];
	for(i=1;i<=m;++i)//将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0 
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	cout<<"请输入叶子结点的权值:"<<endl;
	for(i = 1; i<=n;++i ) 
	{
		cin>>HT[i].weight; 
	}//算法未完待续。。。
	//未完待续......

初始化结果如图所示:
在这里插入图片描述

2.创建树:进行以下n-1次合并,依次产生HT[i],i=n+1…2n-1:
①在HT[1…i-1]中选两个未被选过的weight最小的两个结点HT[s1]和HT[s2] (从parent = =0 的结点中选)
②修改HT[s1]和HT[s2]的parent值: parent=i
③置HT[i].weight=HT[s1].weight + HT[s2].weight ,
HT[i].lchild=s1, HT[i].rchild=s2。

for(i=n+1; i<=m; ++i)
  {
  	Select(HT,i-1,s1,s2) ;//在HT[k](1≤k≤i-1)中选择两个其双亲域为0, 且权值最小的结点, 并返回它们在HT中的序号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;
  }
}

创建结果如图所示:
在这里插入图片描述
补充:创建树算法中的Select(HT,i-1,s1,s2)函数:
在HT[k](1≤k≤i-1)中选择两个其双亲域为0, 且权值最小的结点, 并返回它们在HT中的序号s1和s2。设置两个最小变量min1和min2(先对min1和min2赋最大值,其int型中最大值)。

void Select(HuffmanTree &HT,int n,int &s1,int &s2){
//选择权值最小的两个结点
	int i;
	int min1 = 2147483647, min2 = 2147483647;//先赋予最大值
	for(i=1;i<=n;i++)
	{
		if(HT[i].weight<min1&&HT[i].parent==0)
		{
			min1=HT[i].weight;
			s1=i;
		}	
	}
	for(i=1;i<=n;i++)
	{
		if(HT[i].weight<min2&&HT[i].parent==0&&i!=s1)
		{
			min2=HT[i].weight;
			s2=i;
		}
	}
}

三、构造Huffman树的完整代码

C++代码实现,可经过简单修改,同样可以C语言实现

#include<iostream>
#include<string.h>
using namespace std;

typedef struct{
	int weight;
	int parent, lchild, rchild;
}HTNode,*HuffmanTree;


void Select(HuffmanTree &HT,int n,int &s1,int &s2){
//选择权值最小的两个结点
	int i;
	int min1 = 2147483647, min2 = 2147483647;//先赋予最大值
	for(i=1;i<=n;i++)
	{
		if(HT[i].weight<min1&&HT[i].parent==0)
		{
			min1=HT[i].weight;
			s1=i;
		}	
	}
	for(i=1;i<=n;i++)
	{
		if(HT[i].weight<min2&&HT[i].parent==0&&i!=s1)
		{
			min2=HT[i].weight;
			s2=i;
		}
	}
}


//构造哈夫曼树
void CreatHuffmanTree(HuffmanTree &HT, int n){//算法5.10 创建哈夫曼树
	if (n<=1) return ;
	int m = 2*n-1;
	int i,s1,s2;
	HT = new HTNode[m+1];
	for(i=1;i<=m;++i)//将1~m号单元中的双亲、左孩子,右孩子的下标都初始化为0 
	{
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	cout<<"请输入叶子结点的权值:"<<endl;
	for(i = 1; i<=n;++i ) 
	{
		cin>>HT[i].weight; 
	}
	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;
	}
}


void outputHuffman(HuffmanTree HT, int m){//输出哈夫曼树
	cout<<"结点\t"<<"权\t"<<"双亲\t"<<"左孩子\t"<<"右孩子\n"; 
	for(int i =1;i<=m;i++){
		cout<<i<<"\t";
		cout<<HT[i].weight<<"\t";
		cout<<HT[i].parent<<"\t";
		cout<<HT[i].lchild<<"\t";
		cout<<HT[i].rchild<<"\n";
	}
}


int main()
{	HuffmanTree HT;
	int n,m;
	cout<<"请输入叶子结点的个数:\n";
	cin>>n;
	CreatHuffmanTree(HT,n);
	m=2*n-1;
	outputHuffman(HT,m);
	delete[] HT;  // 释放内存
	return 0;
}


四、实验结果

在这里插入图片描述
从实验结果可以看出,成功实现了HuffmanTree的构建。哈夫曼编码的实现:哈夫曼编码
嘿 兄弟,很高兴在这里遇见你,美好的事情即将发生~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值