赫夫曼树介绍
概念
赫夫曼树是最优二叉树的别名,他通过每个叶子节点算权值和,取最小权值和的那棵树便是哈夫曼树。
如何实现
将所有数排成一个数组内,找到其质量(他的价值)最小的两个,将其合成一颗树,左边是最小的,右边是第二小的,然后将其质量相加便是这颗新树的质量。然后再次搜索,找到质量最小的两个,一直往复直到只剩下一棵树,那便是哈夫曼树。
代码如下:
#include<iostream>
#include<iomanip>//这是输出格式的头文件
#define bug(a) (cout<<"*"<<a<<endl)
#define bugg(a,b) (cout<<"*"<<a<<' '<<b<<endl)
#define buggg(a,b,c) (cout<<"*"<<a<<' '<<b<<' '<<c<<endl)
#define endl '\n'
#define MAX 0x3f3f3f
using namespace std;
typedef long long ll;
const int M = 1000;
int arr[M];
typedef struct node
{
int wei;
int fa, l, r;
char* code;
}banode, * bitree;//创建这个数组的结构体指针方便运用
void mi(bitree& s, int n, int& a, int& b) {//将这个数组和已经运算到的长度(注:是会随着你的运算增大不是不变的)
int i, j, k;//还有最小的两个值通过引用变量来带出
for (i = 1; i < n; i++) {//这里不能等于n,因为n是我们要得到值的位置,现在还是没有值的
if (s[i].fa == 0) {//找到第一个没父母节点的
a = i;//将其坐标赋值给a
break;
}
}
for (i = 1; i < n; i++) {
if (s[i].fa == 0 && s[i].wei < s[a].wei)a = i;//然后搜索最小的质量并将其坐标赋值给a
}
for (k = 1; k < n; k++) {
if (s[k].fa == 0 && k != a) {//与之前一样找到第一个没父母节点的
b = k;//并将其坐标赋值给b
break;
}
}
for (k = 1; k < n; k++) {
if (s[k].fa == 0 && s[k].wei < s[b].wei && k != a)b = k;//找到除坐标等于a的外最小的位置
}
}
void hfm(bitree& s, int arr[], int n) {//将要建立的哈夫曼树的数组和初始数组以及长度放进去
int i;
for (i = 1; i <= 2 * n - 1; i++) {//因为从一开始所以可以赋值为0
s[i].fa = 0;
s[i].l = 0;
s[i].r = 0;
s[i].wei = 0;
}
for (i = 1; i <= n; i++) {//输入质量
s[i].wei = arr[i];
}
for (i = n + 1; i <= 2 * n - 1; i++) {//下面是哈夫曼树的判断之前讲了
int mil, mir;
mi(s, i, mil, mir);
s[mil].fa = i;
s[mir].fa = i;
s[i].l = mil;
s[i].r = mir;
s[i].wei = s[mil].wei + s[mir].wei;
}
}
void out(bitree s, const int t) {
cout << "位置 质量 父母节点 左孩子 右孩子 赫夫曼编码" << endl;
cout << left;
for (int i = 1; i <= t; i++) {
cout << setw(5) << i << " ";//这个节点所在位置
cout << setw(7) << s[i].wei << " ";//输出其质量
cout << setw(7) << s[i].fa << " ";//父母节点位置
cout << setw(7) << s[i].l << " ";//左孩子位置
cout << setw(10) << s[i].r ;//输出右孩子位置
if (i <= (t + 1) / 2)for (int j = strlen(s[i].code) - 1; j >= 0; j--) {
cout << s[i].code[j];
}
else cout << "无赫夫曼编码";
cout << endl;
}
}
void pre(bitree s,int n) {//将赫夫曼编码弄出来
for (int i = 1; i <= n; i++) {
int j = i,k=0;
s[i].code = new char[n+1];
while (s[j].fa) {
if (s[s[j].fa].l==j) {如果父母节点的左孩子坐标等于这个坐标,那就是左孩子
s[i].code[k++] = '0';
}
else s[i].code[k++] = '1';
j = s[j].fa;
}
s[i].code[k] = '\0';
}
}
int main()
{
bitree s;
int n, i;
cout << "输入数组长度:" << endl;
cin >> n;
cout << "输入赫夫曼数的数组:" << endl;
for (i = 1; i <= n; i++)
cin >> arr[i];//下面的有2n-1个
s = new banode[2 * n];//创建空间,记得多创一个因为我们这个是从1开始的
hfm(s, arr, n);
pre(s, n);
out(s, 2 * n - 1);
return 0;
}
测试数据:
8
5 29 7 8 14 23 3 11
输出:
输入数组长度:
8
输入赫夫曼数的数组:
5 29 7 8 14 23 3 11
位置 质量 父母节点 左孩子 右孩子 赫夫曼编码
1 5 9 0 0 0001
2 29 14 0 0 10
3 7 10 0 0 1110
4 8 10 0 0 1111
5 14 12 0 0 110
6 23 13 0 0 01
7 3 9 0 0 0000
8 11 11 0 0 001
9 8 11 7 1 无赫夫曼编码
10 15 12 3 4 无赫夫曼编码
11 19 13 9 8 无赫夫曼编码
12 29 14 5 10 无赫夫曼编码
13 42 15 11 6 无赫夫曼编码
14 58 15 2 12 无赫夫曼编码
15 100 0 13 14 无赫夫曼编码
给个链接------>我是在这学的
给道例题
题目打出来不好看就直接给链接了
---->摘果子(洛谷)
就是要我们求搬运的和的最小,就是权的和。
不过我一开始不是那么想的,我想的是除了根节点以外所有节点的和,结果答案是对的,相当于说明了这个也可以求出权值。
下面是代码(跟之前的代码基本没区别,但是为了记忆这边建议重新手敲一遍,不然忘贼快)
#include<iostream>
#include<iomanip>
#define bug(a) (cout<<"*"<<a<<endl)
#define bugg(a,b) (cout<<"*"<<a<<' '<<b<<endl)
#define buggg(a,b,c) (cout<<"*"<<a<<' '<<b<<' '<<c<<endl)
#define endl '\n'
#define MAX 0x3f3f3f
using namespace std;
typedef long long ll;
const int M = 10005;
int arr[M];
typedef struct {
int wei;
int fa, l, r;
}tree,*bitree;
void mi(bitree s,int n,int &a,int &b) {
int i,j;
for (i = 1; i < n; i++) {
if (s[i].fa == 0) {
a = i;
break;
}
}
for (i = 1; i < n; i++) {
if (s[i].fa == 0 && s[i].wei < s[a].wei)a = i;
}
for (j = 1; j < n; j++) {
if (s[j].fa == 0 && j != a)b = j;
}
for (j = 1; j < n; j++) {
if (s[j].fa == 0 && j != a && s[j].wei < s[b].wei)b = j;
}
}
void hfm(bitree& s, int arr[], int n) {
int i;
for (i = 1; i <= n; i++) {
s[i].wei = s[i].l = s[i].r = s[i].fa = 0;
}
for (i = 1; i <= n; i++)
s[i].wei = arr[i];
for (i = n + 1; i <= 2 * n - 1; i++) {
int ml, mr;
mi(s, i, ml, mr);
s[ml].fa = i;
s[mr]. fa = i;
s[i].l = ml;
s[i].r = mr;
s[i].wei = s[ml].wei + s[mr].wei;
}
}
int main()
{
bitree s;
int n, i,ans=0;
cin >> n;
for (i = 1; i <= n; i++) {
cin >> arr[i];
ans += arr[i];
}
s = new tree[2 * n];
hfm(s, arr, n);
for (i = n + 1; i < 2 * n - 1; i++) {
ans += s[i].wei;
}
cout << ans << endl;
return 0;
}