路径:从树中一个结点到另一个结点之间的分支构成这两个结点间的路径
结点的路径长度:两结点之间的边数
树的路径长度:从根节点到每一个结点的路径长度之和。
权:将树中某个结点赋一个数值,则这个数值称为该结点的权
结点的带权路径长度:从根结点到该结点之间的路径长度与该结点的权的乘积.
树的带权路径长度:树中所有叶子结点的带权路径长度之和.记作:WPL(Weighted Path Length)
哈夫曼树:最优树(带权路径长度(WPL)最短的树)
特点:
1满二叉树不一定是哈夫曼树.
2哈夫曼树中权越大的叶子离根越近.
3具有相同带权结点的哈夫曼树不唯一.
对于哈夫曼树的构造,我们的节点结构中需要包含权值,双亲,左右孩子。由哈夫曼树的性质可知,节点权值越大,则该节点离根节点越近,反之越远。所以我们只需要找出2个权值最小的节点构造一颗子树然后把他们的父节点的权值记为两节点权值和再依次进行此过程即可。
节点结构:
typedef struct {
int weight;
int parent;
int lChild, rChild;
}HuffmanNode,*HuffmanTree;
查找最小和第二小:
void find(HuffmanTree tree, int n, int* s1, int* s2) {
int minn= 0;
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0) {
minn = i;
break;
}
}
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0 && tree[i].weight < tree[minn].weight) {
minn = i;
}
}
*s1 = minn;
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0 && i != *s1) {
minn = i;
break;
}
}
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0 && i != *s1 && tree[i].weight < tree[minn].weight) {
minn = i;
}
}
*s2 = minn;
}
树的构造:
HuffmanTree createHuffmanTree(int w[], int n) {
int m = 2 * n - 1;//总结点个数
HuffmanTree tree = new HuffmanNode [m+1];
//初始化数组
for (int i = 1;i <= m;i++) {
tree[i].lChild = tree[i].rChild = tree[i].parent = 0;
tree[i].weight = 0;
}
//将叶子节点放入数组
for (int i = 1;i <= n;i++) {
tree[i].weight = w[i - 1];
}
//添加剩下的节点,构造哈夫曼树
int s1, s2;
for (int i = n + 1;i <= m;i++) {
find(tree, i - 1, &s1, &s2);
tree[s1].parent = tree[s2].parent = i;
tree[i].lChild = s1;
tree[i].rChild = s2;
tree[i].weight = tree[s1].weight + tree[s2].weight;
}
return tree;
}
哈夫曼编码基于贪婪算法,可以用来做文件压缩,提高传输效率等。
char** createCode(HuffmanTree tree, int n) {
char* temp = new char[n];
char** code = new char* [n];
memset(code, 0, sizeof(char*) * n);
int start, p, pos;
for (int i = 1;i <= n;i++) {
start = n - 1;
temp[start] = '\0';
pos = i;
p = tree[pos].parent;
while (p) {
start--;
temp[start] = (tree[p].lChild == pos ? '1' : '0');
pos = p;
p = tree[p].parent;
}
code[i - 1] = (char*)malloc(sizeof(char) * (n - start));
strcpy(code[i - 1], &temp[start]);
}
delete[] temp;
temp = NULL;
return code;
}
整体代码如下:
#include
#include
using namespace std;
typedef struct {
int weight;
int parent;
int lChild, rChild;
}HuffmanNode,*HuffmanTree;
void find(HuffmanTree tree, int n, int* s1, int* s2) {
int minn= 0;
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0) {
minn = i;
break;
}
}
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0 && tree[i].weight < tree[minn].weight) {
minn = i;
}
}
*s1 = minn;
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0 && i != *s1) {
minn = i;
break;
}
}
for (int i = 1;i <= n;i++) {
if (tree[i].parent == 0 && i != *s1 && tree[i].weight < tree[minn].weight) {
minn = i;
}
}
*s2 = minn;
}
HuffmanTree createHuffmanTree(int w[], int n) {
int m = 2 * n - 1;//总结点个数
HuffmanTree tree = new HuffmanNode [m+1];
//初始化数组
for (int i = 1;i <= m;i++) {
tree[i].lChild = tree[i].rChild = tree[i].parent = 0;
tree[i].weight = 0;
}
//将叶子节点放入数组
for (int i = 1;i <= n;i++) {
tree[i].weight = w[i - 1];
}
//添加剩下的节点,构造哈夫曼树
int s1, s2;
for (int i = n + 1;i <= m;i++) {
find(tree, i - 1, &s1, &s2);
tree[s1].parent = tree[s2].parent = i;
tree[i].lChild = s1;
tree[i].rChild = s2;
tree[i].weight = tree[s1].weight + tree[s2].weight;
}
return tree;
}
char** createCode(HuffmanTree tree, int n) {
char* temp = new char[n];
char** code = new char* [n];
memset(code, 0, sizeof(char*) * n);
int start, p, pos;
for (int i = 1;i <= n;i++) {
start = n - 1;
temp[start] = '\0';
pos = i;
p = tree[pos].parent;
while (p) {
start--;
temp[start] = (tree[p].lChild == pos ? '1' : '0');
pos = p;
p = tree[p].parent;
}
code[i - 1] = (char*)malloc(sizeof(char) * (n - start));
strcpy(code[i - 1], &temp[start]);
}
delete[] temp;
temp = NULL;
return code;
}
int main() {
char s[8] = { 'A','B','C','D','E','F','G','H' };
int w[8] = { 5,29,7,8,14,23,3,11 };
HuffmanTree tree = createHuffmanTree(w, 8);
char** code = createCode(tree, 8);
for (int i = 0;i < 8;i++) {
printf("%c :%s\n", s[i], code[i]);
}
return 0;
}