哈夫曼編碼演算法
來源:互聯網
上載者:User
huffman.h
#ifndef __HUFFMAN_H_FE
#define __HUFFMAN_H_FE// 哈夫曼樹的節點結構
typedef struct _huff_node ...{
float weight; // 節點權重
int lchild; // 節點的左孩子
int rchild; // 節點的右孩子
int parent; // 節點的父節點
} HUFF_NODE, *PHUFF_NODE;// 哈夫曼樹
typedef struct _huff_tree ...{
int leaf_num; // 樹中分葉節點也就是需要編碼的節點的數目
int node_num; // 對應於分葉節點的數目,哈夫曼樹中一共需要 2*leaf_num - 1 個節點
PHUFF_NODE nodes; // 樹中所有的節點,用一個數組存放這些節點
char** huff_code; // 分葉節點對應的哈夫曼編碼
} HUFF_TREE;// 初始化一棵哈夫曼樹,包括為這棵樹分配空間以及權重等的初始化
void init_huff_tree(float *weights, int leaf_num, HUFF_TREE &tree);// 建立一棵哈夫曼樹,前提是必須已經初始化了
void create_huff_tree(HUFF_TREE &tree);// 列印一棵已經建立好的哈夫曼樹的分葉節點對應的哈夫曼編碼
void print_huff_code(HUFF_TREE &tree);// 銷毀一棵哈夫曼樹,釋放初始化時申請的節點以及編碼空間
void destroy_huff_tree(HUFF_TREE &tree);#endifhuffman.cpp
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <memory.h>
#include "huffman.h"void huff_encode(HUFF_TREE &tree);// 初始化一棵哈夫曼樹
void init_huff_tree(float *weights, int leaf_num, HUFF_TREE &tree)
...{
// 儲存分葉節點數
tree.leaf_num = leaf_num; // 根據分葉節點數計算整棵哈夫曼樹需要的節點數
// 一棵二叉樹中,出度為0、1、2的節點之間有如下關係:
// n = n0 + n1 + n2 且 n = n1 + 2*n2 + 1
// 因此,有 n2 = n0 - 1
// 在哈夫曼樹中,只有出度為0和2的節點
// 因此,n = n0 + n2 = 2*n0 - 1
tree.node_num = 2 * leaf_num - 1; // 為節點分配空間
tree.nodes = new HUFF_NODE[tree.node_num];
if (tree.nodes == NULL) ...{
printf("memry out. ");
exit(1);
} // 為每個分葉節點分配儲存哈夫曼編碼的字元數組
tree.huff_code = new char*[leaf_num];
if (tree.huff_code == NULL) ...{
printf("memory out. ");
exit(1);
}
else ...{
for (int i = 0; i < leaf_num; i++) ...{
if ((tree.huff_code[i] = new char[leaf_num + 1]) == NULL) ...{
printf("memory out. ");
exit(1);
}
else ...{
memset(tree.huff_code[i], 0, leaf_num + 1);
}
}
} // 對節點值進行初始化
for (int i = 0; i < tree.node_num; i++) ...{
// 分葉節點儲存在節點數組前部,且賦上它們的初始權值
if (i < leaf_num) ...{
tree.nodes[i].weight = weights[i];
}
else ...{
tree.nodes[i].weight = 0;
} // 左右孩子以及父親節點指標(數組索引)初始化為空白(-1)
tree.nodes[i].parent = -1;
tree.nodes[i].lchild = -1;
tree.nodes[i].rchild = -1;
}
}// 根據初始化之後的哈夫曼樹建立整棵完整的哈夫曼樹,包括每個分葉節點的哈夫曼編碼
void create_huff_tree(HUFF_TREE &tree)
...{
float min1 = FLT_MAX, min2 = FLT_MAX; // min1存放當前最小值,min2存放當前次小值
int lchild_temp = -1, rchild_temp = -1; // 組織二叉樹的結構
// 每一輪從那些還沒有父節點的節點中選出權值最小的兩個節點
// 節點數組中的下一個節點的左右孩子指標分別指向最小和次小的兩個節點
// 並且,權值置為以上兩個節點的和
// 最小節點和次小節點的父節點指標置為該節點的索引
for (int i = tree.leaf_num; i < tree.node_num; i++) ...{
// 從那些還沒有父節點的數組中選擇權值最小的兩個節點
for (int j = 0; j < i; j++) ...{
if (tree.nodes[j].parent == -1) ...{
if (tree.nodes[j].weight < min1) ...{
min2 = min1;
rchild_temp = lchild_temp;
min1 = tree.nodes[j].weight;
lchild_temp = j;
}
else if (tree.nodes[j].weight < min2) ...{
min2 = tree.nodes[j].weight;
rchild_temp = j;
}
}
} tree.nodes[lchild_temp].parent = i;
tree.nodes[rchild_temp].parent = i;
tree.nodes[i].lchild = lchild_temp;
tree.nodes[i].rchild = rchild_temp;
tree.nodes[i].weight = min1 + min2; min1 = FLT_MAX;
min2 = FLT_MAX;
lchild_temp = -1;
rchild_temp = -1;
} // 對哈夫曼樹的分葉節點進行編碼
huff_encode(tree);
}// 對哈夫曼樹的分葉節點進行編碼
void huff_encode(HUFF_TREE &tree)
...{
// 一個臨時數組,從後向前儲存哈夫曼編碼
char* code_temp = new char[tree.leaf_num + 1];
memset(code_temp, 0, tree.leaf_num + 1);
// 寫指標初始位於臨時數組末尾
int start_pos = tree.leaf_num; // 從分葉節點開始,一直向上直到根節點位置
// 為每一個分葉節點進行編碼
for (int i = 0; i < tree.leaf_num; i++) ...{
int cur_node = i;
int parent = tree.nodes[i].parent;
// 一直到根節點
while (parent != -1) ...{
// 若當前節點是父節點的左孩子,則編碼為0
if (tree.nodes[parent].lchild == cur_node) ...{
code_temp[--start_pos] = '0';
}
// 若當前節點是父節點的右孩子,則編碼為1
else if (tree.nodes[parent].rchild == cur_node) ...{
code_temp[--start_pos] = '1';
}
// 繼續向上
cur_node = parent;
parent = tree.nodes[parent].parent;
} // 將臨時編碼數組中的編碼拷貝到哈夫曼樹中的節點對應的編碼儲存空間中
memcpy(tree.huff_code[i], (code_temp + start_pos), (tree.leaf_num - start_pos + 1)); memset(code_temp, 0, tree.leaf_num + 1);
start_pos = tree.leaf_num;
} delete[] code_temp;
}// 列印每個分葉節點的哈夫曼編碼
void print_huff_code(HUFF_TREE &tree)
...{
for (int i = 0; i < tree.leaf_num; i++) ...{
printf("node weight: %.2f", tree.nodes[i].weight);
printf(" huffman code: %s ", tree.huff_code[i]);
}
}// 銷毀哈夫曼樹
void destroy_huff_tree(HUFF_TREE &tree)
...{
// 釋放節點空間
if (tree.nodes != NULL) ...{
delete[] tree.nodes;
} // 釋放哈夫曼編碼空間
if (tree.huff_code != NULL) ...{
for (int i = 0; i < tree.leaf_num; i++) ...{
if (tree.huff_code[i] != NULL) ...{
delete[] tree.huff_code[i];
}
}
delete[] tree.huff_code;
}
}使用樣本
#include <stdio.h>
#include <stdlib.h>
#include "huffman.h"int main(void)
...{
float weights[10] = ...{ 14, 3, 7, 9, 34, 8, 12, 1, 5, 20 };
HUFF_TREE huff_tree; printf("weights of the nodes are: ");
for (int i = 0; i < 10; i++) ...{
printf("%.2f ", weights[i]);
}
printf(" "); init_huff_tree(weights, 10, huff_tree);
create_huff_tree(huff_tree);
print_huff_code(huff_tree);
destroy_huff_tree(huff_tree); system("pause"); return 0;
}