Huffman算法
霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编码表是通过一种评估来源符号出现概率的方法得到的,出现概率高的字母使用较短的编码,反之出现概率低的则使用较长的编码,这便使编码之后的字符串的平均长度、期望值降低,从而达到无损压缩数据的目的。
来自文库
演算过程
(一)进行霍夫曼编码前,我们先创建一个霍夫曼树。
⒈将每个英文字母依照出现频率由小排到大,最小在左.
⒉每个字母都代表一个终端节点(叶节点),比较F.O.R.G.E.T六个字母中每个字母的出现频率,将最小的两个字母频率相加合成一个新的节点。如Fig.2所示,发现F与O的频率最小,故相加2+3=5。
⒊比较5.R.G.E.T,发现R与G的频率最小,故相加4+4=8。
⒋比较5.8.E.T,发现5与E的频率最小,故相加5+5=10。
⒌比较8.10.T,发现8与T的频率最小,故相加8+7=15。
⒍最后剩10.15,没有可以比较的对象,相加10+15=25。
最后产生的树状图就是霍夫曼树
(二)进行编码
1.给霍夫曼树的所有左链接’0’与右链接’1’。
2.从树根至树叶依序记录所有字母的编码
在这里, 我们主程序其实是排序, 我选用的是堆排序, 因为用起来方便, 不需要每次新开辟空间 代码稍微有点变化
每次将最小的放在第一个, 将第一保存后再放在最后, 然后数组大小 -1;
//排序, 使用的是堆排序
void sort(int first, int last)
{
int i = first * 2 + 1;
node tmp = arr[first];
for (; i < last; first = i, i = i * 2 + 1)
{
if (i < last - 1 && arr[i].num > arr[i + 1].num)
i++;
if (arr[first].num > arr[i].num)
arr[first] = arr[i];
else
break;
}
arr[first] = tmp;
}
//交换, 堆排序里的必要步骤, 将第一个位置与最后一个位置的进行交换
void Swap(int i, int j)
{
node tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//进行sort 和 Swap
T sort_min(int &size_arr)
{
//L : 存储arr[0]的链表
T L = new Node;
*L = arr[0];
Swap(0, size_arr - 1);
sort(0, size_arr - 2);
size_arr--;
return L;
}
源代码
#include <stdlib.h>
#include <stdio.h>
typedef int Type;
struct Node;
typedef struct Node *T;
typedef struct Node node;
struct Node
{
Type num;
T Left;
T Right;
Node() : Left(NULL), Right(NULL) {}
};
void Swap(int i, int j);
void sort(int first, int last);
T sort_min(int &size_arr);
void Create(int a[], int size);
void Add(T L, T R, int size_arr);
void Print(T Huff);
int main()
{
int a[] = { 10, 15, 13, 12, 3, 4, 1 };
int size_arr = sizeof(a) / sizeof(a[0]);
Create(a, size_arr);
system("pause");
return 0;
}
//arr是 Node 的数组;
node *arr;
//排序, 使用的是堆排序
void sort(int first, int last)
{
int i = first * 2 + 1;
node tmp = arr[first];
for (; i < last; first = i, i = i * 2 + 1)
{
if (i < last - 1 && arr[i].num > arr[i + 1].num)
i++;
if (arr[first].num > arr[i].num)
arr[first] = arr[i];
else
break;
}
arr[first] = tmp;
}
//交换, 堆排序里的必要步骤, 将第一个位置与最后一个位置的进行交换
void Swap(int i, int j)
{
node tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
//进行sort 和 Swap
T sort_min(int &size_arr)
{
//L : 存储arr[0]的链表
T L = new Node;
*L = arr[0];
Swap(0, size_arr - 1);
sort(0, size_arr - 2);
size_arr--;
return L;
}
//将两个最小的数相加, 得到新的链表
void Add(T L, T R, int size_arr)
{
T tmp = new Node;
tmp->num = L->num + R->num;
tmp->Left = L;
tmp->Right = R;
arr[size_arr - 1] = *tmp;
}
//执行所有功能
void Create(int a[], int size)
{
//size_arr : 数组的大小;
int size_arr;
size_arr = size;
//初始化arr;
arr = (T)malloc(sizeof(node) * size);
for (int i = 0; i < size; i++)
{
arr[i].num = a[i];
arr[i].Left = arr[i].Right = NULL;
}
//L : 左节点;
//R : 右节点;
T L = new Node, R = new Node;
for (int i = 0; i < size - 1; i++)
{
//堆排序
for (int j = size_arr / 2; j >= 0; j--)
sort(i, size_arr);
L = sort_min(size_arr);
R = sort_min(size_arr);
size_arr++;
Add(L, R, size_arr);
}
T Huff = new Node;
*Huff = arr[0];
Print(Huff);
/*
当然也可以直接传 &arr[0]的地址;
*/
}
void Print(T Huff)
{
if (Huff != NULL)
{
printf("%d ", Huff->num);
Print(Huff->Left);
Print(Huff->Right);
}
}