数据结构——哈夫曼树的创建

1. 算法思想

构造哈夫曼树算法思路:
1.初始化HT[1…2n-1], lch=rch=parent=0.

2.输入n个叶子结点,置于HT[1…n]的weight(权值)。

3.进行n-1次合并,依次产生n-1个结点HT[i], i = n+1…2n-1;
a) 在HT[1…i-1]中选两个未被选过(从parent==0的结点中选)的weight最小的两个结点HT[s1]和HT[s2], s1,s2为两个最小结点的下标
b) 修改HT[s1]和HT[s2]的parent值:HT[s1].patent=i, HT[s2].patent=i ;
c) 修改新产生的的HT[i];
1. HT[i].weight = HT[s1].weight + HT[s2].weight;
2. HT.lch = s1; HT[i].rch = s2;

2.完整代码

#include<iostream>
using namespace std;

//结点类型定义(采用顺序存储结构—一维结构数组)
typedef struct{
	int weight;		//结点的权值
	int parent, lch, rch; 
}HTNode, *HuffmanTree;

//返回哈夫曼树t的前i个结点中权值最小的树的根结点的序号 
int min(HuffmanTree t, int i)
{
	int j, m;
	unsigned int k = UINT_MAX;	//k存最小权值,初值去取一个不小于树中可能的值(无符号整型最大值)
	for (j = 1; j <= i; ++j)	//对于前i个结点 
	{
		if ( t[j].weight <= k && t[j].parent == 0 )		//t[i]的权值小于k,又是树的根结点 
		{
			k = t[j].weight;		//t[j]的权值赋给k 
			m = j;					//序号赋给m 
		}		
	} 
	t[m].parent = 1;		//给选中的根结点双亲赋非0值,避免第二次查找 
	return m;
}

//在哈夫曼树t的前i个结点中选择权值最小的树的根结点的序号 
void select(HuffmanTree t, int i, int &s1, int &s2)
{
	int j;
	s1 = min(t, i);		//权值最小的根结点的序号 
	s2 = min(t, i);		//权值第二小的根结点的序号 
	if (s1 > s2)
	{
		j = s1;
		s1 = s2;
		s2 = j;
	}
}

//构造哈夫曼树算法思路:
//1.初始化HT[1....2n-1], lch=rch=parent=0.

//2.输入n个叶子结点,置于HT[1....n]的weight(权值)。

//3.进行n-1次合并,依次产生n-1个结点HT[i], i = n+1....2n-1;
//	a) 在HT[1...i-1]中选两个未被选过(从parent==0的结点中选)的weight最小的两个结点HT[s1]和HT[s2], s1,s2为两个最小结点的下标
//	b) 修改HT[s1]和HT[s2]的parent值:HT[s1].patent=i, HT[s2].patent=i ;
//	c)  修改新产生的的HT[i];
//		1. HT[i].weight = HT[s1].weight + HT[s2].weight;
//		2. HT.lch = s1; HT[i].rch = s2; 

void CreatHuffmanTree(HuffmanTree HT, int n)
{
	int m, i, s1, s2;
	if (n <= 1 )
		return;
	m = 2 * n - 1;					//数组共有2n-1个元素
	HT = new HTNode[m+1];			//0号单元未用,HT[m]表示根结点
	for (i = 1; i <= m; ++i)		//将2n-1个元素的lch,rch,parent置为0	
	{
		HT[i].lch = 0;
		HT[i].rch = 0;
		HT[i].parent = 0;				
	}
	for (i = 1; i <= n; ++i)		//输入前n个元素的weight值 
	{
		cin >> HT[i].weight;	
	} 
	//初始化结束,下面开始建立哈夫曼树 
	for (i = n+1; i <= m; i++)
	{
		select(HT, i-1, s1, s2);	//在HT[k](1<=k<=i-1)中选择两个其双亲域为0,且权值最小的结点 
		HT[s1].parent = i;
		HT[s2].parent = i;			//表示删除s1,s2 
		HT[i].lch = s1;
		HT[i].rch = s2;				//s1,s2分别为i的左右孩子 
		HT[i].weight = HT[s1].weight + HT[s2].weight;		//i的权值为左右孩子之和 
	}
	
	//打印哈夫曼树 
	cout << "下标\t" << "权重\t" << "双亲\t" << "左孩子\t" << "右孩子" << endl;
	for (int j = 1; j < i; j++)
	{
		cout << j << "\t" << HT[j].weight << "\t" << HT[j].parent << "\t" << HT[j].lch << "\t" << HT[j].rch << endl;
	}
}

/********************主函数**********************/ 
int main()
{
	HuffmanTree HT = NULL;
	int n;
	cout << "请输入字符个数:" << endl;
	cin >> n;
	cout << "请输入权值:" << endl;
	CreatHuffmanTree(HT, n); 
	
	return 0;	
} 

3.测试结果

在这里插入图片描述

  • 9
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值