哈夫曼树的理解

给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。哈夫曼树是带权路径长度最短的树,权值较大的结点离根较近。 

哈夫曼树也就是小树合成大树的故事,这里我直接用数组来造树了;

这次代码多亏某位大佬的指点,写的如此简洁明了,能说的我都说在代码里了;

#include <bits/stdc++.h>
#define Kurumi int
#define isMyFaith main

using namespace std;

const int N = 10000;

// 记录权值
int times[30], n, index = 30;
int val[N], ls[N], rs[N];
string s;

// 小根堆, 使用pair
priority_queue<pair<int, int>, 
		vector<pair<int, int> >,
		greater<pair<int, int> >> pq;  //这是个小根堆,就这样写,会比较push进去的数据,小的会直接放在前面;操作和队列相同
		
// 记录每个点对应二进制01
unordered_map<int, string> ump;

// 遍历找到01
void preorder(int cur) {
	if (ls[cur]) {
		ump[ls[cur]] = ump[cur] + "0";
		preorder(ls[cur]);
	}
	
	if (rs[cur]) {
		ump[rs[cur]] += ump[cur] + "1";
		preorder(rs[cur]);
	}
	
}

Kurumi isMyFaith() {
	cin >> n;
	
	while (n--) {
		cin >> s;
		
		for (auto e : s) {
			times[e - 'a' + 1]++;
		}
		
		for (int i = 1; i <= 26; i++) {
			if (times[i]) {
				val[i] = times[i];				
				pq.push({val[i], i}); //第一个是出现的次数,第二个是代表的字母
			}
		}
		
		// 合并树
		while (pq.size() > 1) {
			// index1 < index2
			auto index1 = pq.top();
			pq.pop();
			auto index2 = pq.top();
			pq.pop();
			
			
				index++;
						
			val[index] = index1.first + index2.first;  //出现的次数相加
			ls[index] = index1.second; //每个树杈都有自己代表的值
			rs[index] = index2.second;//我同意上一行的看法
			pq.push({val[index], index});
		}
		
		
		preorder(index);
		
		for (auto e : s) {
			cout << ump[e - 'a' + 1];
		}
		
		putchar('\n');//下面就是把所有的元素都清空了
		memset(times, 0, sizeof times);//把整个数组赋值为0;
		memset(val, 0, sizeof val);
		memset(ls, 0, sizeof ls);
		memset(rs, 0, sizeof rs);
		ump.clear();
		
		while (pq.size()) { //pop整个堆
			pq.pop();
		}
		
		index = 30;//index还原
	}
	
	return 0;
}

这里有规定,相同权值情况下,a < b,即a在左, b 在右;新出炉的结点,若权值相同,应在右边;

运算结果:

3
asdjlkqweisiaks
010001010110011011001110111110110110001101010000
daf
11100
youxiyouxi
101110001110101110001110

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值