思路
因爲哈夫曼樹的特殊性質,我們在求最小總長度、WPL、長度均值的時候,均不採用建樹法.
方向:哈夫曼樹的編碼長度等於各個葉節點權值與路徑長度乘積之和,同時這個值等於非葉節點之和。
非葉節點的權值之和=路徑葉節點權值=哈夫曼編碼的所有元素總長(編碼長度元素個數==路徑*權值)
題目一:求WPL
題目描述
哈夫曼樹,第一行輸入一個數n,表示葉結點的個數。需要用這些葉結點生成哈夫曼樹,根據哈夫曼樹的概念,這些結點有權值,即weight,題目需要輸出所有結點的值與權值的乘積之和。
輸入描述:
輸入有多組數據。
每組第一行輸入一個數n,接着輸入n個葉節點(葉節點權值不超過100,2<=n<=1000)。
輸出描述:
輸出權值。
示例1
輸入
5
1 2 2 5 9
輸出
37
代碼:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
vector<int>myvector;
while(n--)
{
int x;
scanf("%d",&x);
myvector.push_back(x);
}
sort(myvector.begin(),myvector.end());
int sum=0;
while(myvector.size()>1)
{
int a=myvector[0];
int b=myvector[1];
sum=sum+a+b;
myvector.erase(myvector.begin(),myvector.begin()+2);
myvector.push_back(a+b);
sort(myvector.begin(),myvector.end());
}
cout<<sum<<endl;
return 0;
}
第二題:字符串的哈夫曼編碼長度
思路:這就是不把權值給你,你自行判斷權值,再進行求解,大同小異
題目:
字符串的哈夫曼編碼長度
問題描述:
給定一個字符串(長度不超過100),求哈夫曼編碼的最短長度
樣例輸入:
輸入1:
abbcccdddd
輸出1:
19
輸入2:
we will we will r u
輸出2:
50
代碼
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100;
string str;
map<char, int> mp;
priority_queue<int, vector<int>, greater<int> >q;
int main(){
getline(cin, str);
int len = str.length();
for(int i = 0; i < len; i++){
if(mp.find(str[i]) == mp.end()){
mp[str[i]] = 1;
}
else{
mp[str[i]]++;
}
}
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
q.push(it->second);
}
int ans = 0;
while(q.size() != 1){
int a, b, temp;
a = q.top();
q.pop();
b = q.top();
q.pop();
temp = a + b;
ans += temp;
q.push(temp);
}
cout << ans << endl;
return 0;
}
第三題:求哈夫曼編碼平均長度
注意:這裏可能是兩種處理方式:
第一種最簡單:wpl/所有權值和,這就不說了
第二種較困難:是每個權值編碼的長度和除以葉子的個數(見下面題目)
題目:
求霍夫曼編碼長度
輸入:
兩行
第一行:個數N
第二行:N個以空格隔開的數,表示這N個字符的出現次數
輸出:
一行,哈夫曼編碼的平均長度
樣例輸入:
6
1 3 6 2 7 3
樣例輸出:
2.666667
代碼:
#include <bits/stdc++.h>
using namespace std;
struct Point{ //利用truenum進行求結果,利用num進行排序。每次排序有順序要求的!
int num;
int truenum;
Point(int n,int t):num(n),truenum(t){}
bool operator<(const Point& c)const{
if(num==c.num) return truenum>c.truenum;
else return num>c.num;
}
};
int main()
{
int n;
while(cin>>n)
{
priority_queue<Point>myqueue;
for(int i=0;i<n;i++)
{
int x; cin>>x;
myqueue.push(Point(x,1));
}
double sum=0;
while(myqueue.size()!=1)
{
Point a=myqueue.top();
myqueue.pop();
Point b=myqueue.top();
myqueue.pop();
sum+=(a.truenum+b.truenum);
myqueue.push(Point(a.num+b.num,a.truenum+b.truenum));
}
printf("%.6lf\n",(double)sum/n);
}
return 0;
}