哈夫曼树的创建以及哈夫曼编码的实现

哈夫曼树的创建以及哈夫曼编码的实现

哈夫曼树的创建

  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:
    • 在HT[1……i-1]中选两个未被选过(从parent==0的结点中选)的weight最小的两个结点HT[s1]和HT[s2],s1和s2为两个最小结点下标;
    • 修改HT[s1]和HT[s2]的parent值:HT[s1].parent=i;HT[s2].parent=i;
    • 修改新产生的HT[i]:
      • HT[i].weight=HT[s1].weight+HT[s2].weight;
      • HT[i].lch=s1;HT[i].rch=s2;

哈夫曼编码

不等长编码设计关键:必须使任一字符的编码都不是另一个字符的编码的前缀。——前缀编码

哈夫曼编码:前缀码+电文总长度最短

方法:

  1. 统计字符集中每个字符在电文中出现的平均概率(概率越大,要求编码越短)
  2. 利用哈夫曼树的特点:权越大的叶子离根越近;将每个字符的概率值作为权值,构造哈夫曼树。则概率越大的结点,路径越短。
  3. 在哈夫曼树的每个分支上标0/1;结点的左分支标0,右分支标1;把从根到每个叶子的路径上的标号连接起来,作为该叶子代表的字符编码。
    在这里插入图片描述
#include <iostream>
#include<cmath>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;
typedef char** HuffmanCode;
using namespace std;
//哈夫曼树的结点的类型
typedef struct {
	int weight;//权重
	char word;//结点存放的字符
	int parent, lch, rch;
}HTNode, * HuffmanTree;
//构造森林全是根
int InitHuffmanTree(HuffmanTree& T) {
	int n;
	cout << "请输入哈夫曼树的结点的个数:" << "";
	cin >> n;
	cout << "请按顺序输入每个结点的权值和字符:" << "\n";
	for (int i = 1; i <= n; i++) {
		cin >> T[i].weight;
		cin>>T[i].word;
		T[i].parent = 0;
		T[i].lch = 0;
		
		T[i].rch = 0;
	}
	return n;
}
//选用两小造新树
void createHuffmanTree(HuffmanTree& H, int n) {
	for (int i = n + 1; i <= 2 * n - 1; i++)
	{
		int minIndex = 0, secondMinIndex = 0;
		int min = 1000000, secondMin = 1000000;;//最小值现在设置为无穷大
		//选择parent为0的最小的两个结点构造一棵新的树,然后把原来这两棵树删除掉(即把原来的两棵树的parent设置为这个新的节点)
		for (int j = 1; j < i; j++) {
			if (H[j].parent == 0)
			{
				if (H[j].weight <= min) {
					secondMin = min;
					min = H[j].weight;
					secondMinIndex = minIndex;
					minIndex = j;
				}
				if (H[j].weight > min && H[j].weight < secondMin) {
					secondMin = H[j].weight;
					secondMinIndex = j;
				}
			}
		}
		//已经选出来了最小权重对应的结点的下标为minIndex,第二小的结点对应的下标为secondMinIndex
		H[i].parent = 0;
		H[i].lch = minIndex;
		H[i].rch = secondMinIndex;
		H[i].weight = H[minIndex].weight + H[secondMinIndex].weight;
		H[i].word = NULL;
		//哎啊,忘记把lch和rch的parent设置为新节点啦
		H[minIndex].parent = i;
		H[secondMinIndex].parent = i;
	}
}
void Transerver(HuffmanTree H, int n) {
	for (int i = 1; i < 2 * n; i++) {
		if (i <= n) {
			printf("%c %d %d %d %d\n",H[i].word,H[i].weight, H[i].parent, H[i].lch, H[i].rch);
		}
		else {
			printf("%d %d %d %d\n", H[i].weight, H[i].parent, H[i].lch, H[i].rch);
		}
	}
}
//哈夫曼编码
void createHuffmanCode(HuffmanTree H, HuffmanCode& HC, int n) {
	char* cd = new char[n];//用于记录每一个字符的编码
	//这里说一下为要n呢?n个结点构成的哈夫曼树,
	//每两个结点之间就新建一个连接,最多有n-1个分支
	//这里定义字符数组的长度为n是因为还要存储字符串的结束符\0
	cd[n - 1] = '\0';
	for (int i = 1; i <= n; i++)
	{
		//因为是从叶子结点开始找到根结点,所以在写入字符数组的时候的顺序是反着来写的
		int start = n - 1;
		//为了找到究竟是parent的lch还是rch,我们这里还需要存储当前结点
		int pre = i;
		int j = H[i].parent;
		//从叶子结点开始找,一直找到根(什么时候是根呢,就是那个parent是0的那个啊)
		while (j != 0) {
			--start;
			if (H[j].lch==pre)//上一个结点是parent的左孩子
			{
				//左孩子给编号0
				cd[start] = '0';
			}
			else {
				//右孩子给编号1
				cd[start] = '1';
			}
			pre = j;
			j = H[j].parent;
		}
		HC[i] = new char[n];
		strcpy(HC[i], &cd[start]);

	}
	delete cd;
}


//用一维数组存储哈夫曼树
int main() {
	HuffmanTree H = new HTNode[MAXSIZE];
	int n = InitHuffmanTree(H);
	createHuffmanTree(H, n);
	Transerver(H, n);
	HuffmanCode HC = new char*[MAXSIZE];
	//要注意了,虽然讲课的时候讲的是new char*[n+1],但是定义数组的时候,数组的大小必须确定,虽然也可以写,但是呢不太好
	createHuffmanCode(H, HC, n);
	for (int i = 1; i <= n; i++)
	{
		printf("%c %s\n", H[i].word, HC[i]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

菜菜iwi

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

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

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

打赏作者

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

抵扣说明:

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

余额充值