具体的原理可以去看原博主的文章,很详细。
/*构造哈夫曼树的算法步骤:
① 初始化:用给定的 n 个权值{w1,w2,…,wn}构造 n 棵二叉树并构成的森林F={T1,T2,…,Tn},其中每一棵二叉树Ti(1<=i<=n)都只有一个权值为 wi 的根结点,其左、右子树为空。
② 找最小树:在森林 F 中选择两棵根结点权值最小的二叉树,作为一棵新二叉树的左、右子树,标记新二叉树的根结点权值为其左、右子树的根结点权值之和。
③ 删除与加入:从 F 中删除被选中的那两棵二叉树,同时把新构成的二叉树加入到森林 F 中。
④ 判断:重复②、③操作,直到森林中只含有一棵二叉树为止,此时得到的这棵二叉树就是哈夫曼树。
简单的说就是先选择权小的,所以权小的结点被放置在树的较深层,而权较大的离根较近,这样一来所构成的哈夫曼树就具有最小带权路径长度。
————————————————
版权声明:本文为CSDN博主「素锦流年つ」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_51450101/article/details/122893828*/
#include <climits>
#include<iostream>
#include <vector>
using namespace std;
typedef struct {
int weigth; // 出现的次数
int code; // 当前点的哈夫曼编码
int ParLabel; // 当前点的父节点标签
int LChLabel; // 当前点的左子叶节点标签
int RChLabel; // 当前点的右子叶节点标签
}HuffmanNode;
// 次函数将完成挑选权重最小的父节点,以建树
void myselect(vector<HuffmanNode>& HT, int sz, int* label1, int* label2){
int min1 = INT_MAX, min2 = INT_MAX;
*label1 = 0, *label2 = 0;
for(int j = 1; j <= sz; j++){
if(HT[j].code == 0){
if(HT[j].weigth < min1){ // min1是最小的一个
// 先把min1的当前值给到老二(min2)
min2 = min1;
*label2 = *label1;
// 再更新自己
min1 = HT[j].weigth;
*label1 = j;
}
else if (HT[j].weigth < min2) {
min2 = HT[j].weigth;
*label2 = j;
}
}
}// 最后返回的是最小父节点的两个标签
}
int main(){
int CharTypeNumber = 0;
cin >> CharTypeNumber;
// 用vector来记录哈夫曼树
vector<HuffmanNode> HuffmanTree(CharTypeNumber+1, {0});
HuffmanTree[0] = {INT_MAX, INT_MAX, INT_MAX, INT_MAX, INT_MAX};
for(int i = 1; i < CharTypeNumber + 1; i++){
cin >> HuffmanTree[i].weigth;
}
// 开始建树操作
for(int j = 0; j < CharTypeNumber - 1; j++){
int l1 = 0, l2 = 0;
myselect(HuffmanTree, CharTypeNumber + j, &l1, &l2);
HuffmanNode temp = {0};
temp.weigth = HuffmanTree[l1].weigth + HuffmanTree[l2].weigth;
HuffmanTree[l1].code = 1; // 利用code来标志是否访问过该子树
HuffmanTree[l2].code = 1; // 利用code来标志是否访问过该子树
temp.LChLabel = l1;
temp.RChLabel = l2;
HuffmanTree.push_back(temp);
HuffmanTree[l1].ParLabel = HuffmanTree.size()-1;
HuffmanTree[l2].ParLabel = HuffmanTree.size()-1;
HuffmanTree[HuffmanTree.size()-1].ParLabel = 0;
}
// 开始编码操作,顺带把路径和长度算了
int k = HuffmanTree.size() - 1;
int depth = 0, sum = 0;
while(HuffmanTree[k].LChLabel != 0 && HuffmanTree[k].RChLabel != 0){
int l1 = 0, l2 = 0;
l1 = HuffmanTree[k].LChLabel;
l2 = HuffmanTree[k].RChLabel;
HuffmanTree[l1].code = 0;
HuffmanTree[l2].code = 1;
// 上面完成了编码,下面是算路径和长度
/*depth++;
if(HuffmanTree[l1].LChLabel == 0 && HuffmanTree[l1].RChLabel == 0){
sum = depth*HuffmanTree[l1].weigth + sum;
}
if(HuffmanTree[l2].LChLabel == 0 && HuffmanTree[l2].RChLabel == 0){
sum = depth*HuffmanTree[l2].weigth + sum;
}*/
k--;
}
cout << sum << endl;
return 0;
}