Greedy——HDUOJ 1553 - Entropy(哈夫曼樹求解)
阿新 • • 發佈:2018-11-09
原題:
Problem Description
哈夫曼解釋……..(內容過多)
Sample Input
AAAAABCD
THE_CAT_IN_THE_HAT
ENDSample Output
64 13 4.9
144 51 2.8
解題思路:
首先,得理解哈夫曼樹的原理和使用的價值。。。。
題目大概意思就是:
怎麼通過演算法讓字串儲存的空間大幅度的減少。
貪心:
一般一個字元用8bit儲存,所以一個字串(10個字元)就得80位的儲存空間。
通過哈夫曼樹:用01二進位制去表示每一個字元,對於出現頻率多的字元則01數量少,對於出現頻率少的則01數量就多了。
構建完後,如上圖2-1(c)所示,對於C字元,出現的次數是5(也就是說需要用到5次C,可以理解為M到C需要經過5次,即T->M->C需要經過5次,因為C表示’10’(B),所以一共有5個’10’來儲存C,即10bit)
可以把所有非葉子節點的權值加起來,就是所有字元需要儲存的空間。
用哈夫曼樹演算法構建成數的種類有很多種,但總結果都是相同的。
程式碼:
#include <iostream>
#include <string>
#include <queue>
#include <functional>
using namespace std;
int main()
{
string test;
int letterNum[27], sum;
priority_queue<int, vector<int>, greater<>> HuffmanTree;//優先佇列,每次輸出堆頂(小頂堆)
while (cin >> test)
{
if (!test.compare("END"))
break;
while (!HuffmanTree.empty())HuffmanTree.pop();
memset(letterNum, 0, sizeof(letterNum));
sum = 0;
for (const char&t : test)//計算每個字母出現的次數
{
if (t == '_')letterNum[26]++;//空格用_表示
else letterNum[t - 'A']++;
}
for (const int&t : letterNum)//將每個字母出現的次數存入堆中
if (t != 0)HuffmanTree.emplace(t);
if (HuffmanTree.size() == 1)sum = test.size();//如果只有一種字母,則字串長度就是該字串的儲存空間
while (HuffmanTree.size() > 1)
{
int temp = 0;
for (int i = 0; i < 2; i++)//構建哈夫曼樹
{//每次都將最小的兩個數提取出來構建
temp += HuffmanTree.top();
HuffmanTree.pop();
}
sum += temp;
HuffmanTree.emplace(temp);
}
printf("%d %d %.1f\n", test.size() * 8, sum, test.size() * 8.0 / sum);
}
}