题目
:给定一个字符串,求哈夫曼编码的最短长度。
输入样例:
aaaaabbbbcccdde
输出样例:
33
题解
:本题需要模拟手动创建哈夫曼树的过程,最终计算结果 = Σ(每个叶子结点出现频次*其哈夫曼编码的长度),过程如下:
(1)创建结点node结构体,其内容要包括:①val:代表频次和;②指向父结点的指针,用以计算层数;③name:表示结点名,用以后续寻找该结点;
(2)遍历给定的字符串,用数组记录各字母出现频次,然后建立结点记录这些字母及出现频次,而后初始化两个vector保存它们(一个临时保存,一个用于最后的计算总和);
(3)sort排序,每次挑选最小的两个结点生成一个新结点,构建哈夫曼树,加入数组,遍历size-1次(这是由于哈夫曼树的新结点是叶结点总数-1个);
(4)每个叶结点(保存在一个vector中)的层数-1(编码长度) 乘以 频次,求和即可得字符串的哈夫曼编码长度。
代码(C++)
:
#include <bits/stdc++.h>
using namespace std;
struct node{
char name;
struct node *parent;
int val;
node(char name,struct node *parent,int val) : name(name), parent(parent),val(val) {}
};
int main(){
string str; // 输入字符串
vector<node *> vec,temp; // 存储字符串元素构成的结点
int cnt[26] = {0}; // 字符串元素计数
int res = 0; // 求和
// 输入
cin >> str;
// 主体
for(char c : str){ // 计数
cnt[c - 'a']++;
}
for(int i = 0; i < sizeof (cnt) / sizeof (int); i++){ // 构建存储结点的数组
if(cnt[i] != 0){
node *cur = new node('a'+i, nullptr,cnt[i]);
temp.push_back(cur);
vec.push_back(cur);
}
}
for(int i = 0; i < vec.size() - 1; i++){ // 构建哈夫曼树
sort(temp.begin(), temp.end(), [](node *p1, node *p2){return p1->val < p2->val;});
node *c1 = temp[0]; // 取出来两个结点
node *c2 = temp[1];
node *p = new node('0'+i, nullptr,c1->val + c2->val);
c1->parent = p;
c2->parent = p;
temp.push_back(p);
temp.erase(temp.begin());
temp.erase(temp.begin());
}
for(auto p : vec){ // 计算每个结点的层数-1 * 频次,而后求和
int level = 0; // 层数
int num = p->val; // 频次
while(p->parent != nullptr){
level++;
p = p->parent;
}
res += level * num;
}
//输出
printf("%d",res);
return 0;
}
写在后面
这个专栏主要是我在刷题的过程中总结的一些笔记,因为我学的也很一般,如果有错误和不足之处,还望大家在评论区指出。希望能给大家的学习带来一点帮助,共同进步!!!