哈夫曼树的建立和哈夫曼编码

创建哈夫曼树

#include <iostream>
#pragma warning(disable:4996)//忽视strcpy函数安全性较低得问题
using namespace std;
//函数结果状态代码
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
typedef int MyWeight;
typedef char MyDataType;
typedef char** HuffmanCode;//哈夫曼码
typedef struct HuffmanTrees {//哈夫曼树
	MyWeight weight;//计算权重
	int parent, lch, rch;//双亲,左孩子,右孩子
	MyDataType cc;
}*HuffmanTree;
void Select(HuffmanTree& ht, int a, int& num1, int& num2) {//在ht[k](1<=k<=a)个叶子结点中选择两个双亲为0且权值较小的结点,并用s1,s2返回他们的下标--选用两小
	int min;
	for (int i = 1; i <= a; ++i) {
		if (ht[i].parent == 0) {
			min = ht[i].weight; break;//选出第一个符合条件的结点作为被比较的对象
		}
	}
	for (int i = 1; i <= a; ++i) {
		if (ht[i].parent == 0 && ht[i].weight <= min) {
			min = ht[i].weight; num1 = i;
		} //选出第一个最小的值
	}
	for (int i = 1; i <= a; ++i) {
		if (ht[i].parent == 0 && i != num1) {
			min = ht[i].weight; break;//选出第二个符合条件的结点作为被比较的对象
		}
	}
	for (int i = 1; i <= a; ++i) {
		if (ht[i].parent == 0 && ht[i].weight <= min && i != num1) {
			min = ht[i].weight; num2 = i;
		}
	}
}
int CreateHuffmanTree(HuffmanTree& ht, int n) {//创建哈夫曼树,n个叶子结点
	if (n <= 1)return ERROR;
	int m = 2 * n - 1;//含有n个叶子结点得哈夫曼树含有2n-1个结点
	ht = new HuffmanTrees[m + 1];//0号未使用,为m个结点开辟空间
	for (int i = 1; i <= m; ++i) {
		ht[i].lch = 0; ht[i].rch = 0; ht[i].parent = 0;//将每个结点的双亲,左右孩子置为0
	}//初始化工作完成
	for (int i = 1; i <= n; ++i) cin >> ht[i].weight;//输入每个结点的数据和权重
	//开始建立哈夫曼树
	//口诀:1、构造森林全是树-->2、选用两小造新树-->3、删除两小添新人-->4、重复23剩单根
	for (int i = n + 1; i <= m; ++i) {
		int s1, s2;
		Select(ht, i - 1, s1, s2); //选出叶子结点中权值较小的两个--选用两小
		ht[s1].parent = i; ht[s2].parent = i;//表示第i个结点为s1和s2的双亲,即删除s1和s2--删除两小添新人
		ht[i].lch = s1; ht[i].rch = s2; ht[i].weight = ht[s1].weight + ht[s2].weight;//造新树,将s1和s2分别作为左右孩子,将权重相加
	}
	return OK;
}
void CreateHuffmanCode(HuffmanTree& ht, HuffmanCode& hc, int n) {//将哈夫曼树ht中的n个叶子结点编成哈夫曼码存储到hc中
	hc = new char* [n + 1];//开辟n+1个空间,从1-n存储哈夫曼码
	char* chars = new char[n];//n个叶子结点变成哈夫曼树最多有n-1层,所以最多有n-1个码,多开辟一个存储单元,第n-1个存储单元存储换行符
	chars[n - 1] = '\n';
	for (int i = 1; i <= n; ++i) {//为每个叶子结点编制哈夫曼编码
		int storeLabel = n - 1; int  count = i; int fm = ht[i].parent;//storeLabel用于表示第几个存储单元,因为要回溯存储,所以下标从后面开始,
		//fm是该叶子结点的双亲结点的存储单元,count是叶子结点序号
		while (fm != 0) {//从叶子结点向上查找,直到找到没有双亲的根结点为止
			//因为不确定循环层数,但知道循环停止条件,用while
			--storeLabel;//向前移动一个存储单元
			if (ht[fm].lch == count) chars[storeLabel] = '0';//是左孩子存储0
			else chars[storeLabel] = '1';//是右孩子存储1
			count = fm;//改变接下来要判断的结点,继续向上回溯
			fm = ht[fm].parent;//改变双亲为接下来要判断结点的双亲s
		}//当前第i个叶子结点的编码工作完成
		hc[i] = new char[n - storeLabel];//为第i个字符串分配空间
		strcpy(hc[i], &chars[storeLabel]);//将求得的编码从临时空间复制到哈夫曼编码中
	}
	delete[] chars;//编码结束释放临时空间
	chars = NULL;
}
int main()
{
	HuffmanTree HT;
	int k; cin >> k;
	CreateHuffmanTree(HT, k);
	HuffmanCode HC;
	CreateHuffmanCode(HT, HC, k);
	for (int i = 1; i <= k; ++i) {
		cout << HC[i] << endl;
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

撑一把纸伞.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值