Implementación del lenguaje C de codificación HuffMan
Se realizan un método de codificación y dos métodos de decodificación.
La decodificación utiliza las hojas retrocediendo hasta la raíz.
Uno usa el proceso transversal desde la raíz.
código:
HuffManCodificación
//
// Created by Zza on 2022/4/23.
//
#ifndef DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEENCODING_H
#define DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEENCODING_H
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include "../../Chapter4/String.h"
typedef struct node{
char tar;
int freq;
} node;
#ifndef ELEM
#define ELEM
typedef node ELEMENT_TYPE;
#endif
#include "../Binary Tree/BinaryTree_Array.h"
typedef struct HuffManTree{
// 实际上这里应该自己再重新设置一个
Bin_Tree_Arr trees;
int curTop;
int treeNums;
int* roots;
bool encoded;
}HuffManTree;
typedef struct InitDataPackage{
int n;
node* init;
} pkg;
bool DisplayHuffManStruct(HuffManTree*);
__attribute__((unused)) bool PkgDestruct(pkg*);
__attribute__((unused)) bool Init_HuffMan(HuffManTree* tar, pkg* info);
__attribute__((unused)) bool HuffManEncoding(HuffManTree* tar);
bool HuffManDestruct(HuffManTree *tar);
//======================================================================================================================
bool _find_two_min_tree(HuffManTree* tar, int *min1, int *min2);
bool _tree_merge(HuffManTree* tar, int root1, int root2);
//======================================================================================================================
__attribute__((unused)) bool HuffManEncoding(HuffManTree* tar){
int timer = tar->treeNums - 1;
int cur_tree_l, cur_tree_r;
while (timer--){
// 找到最小的两个树,在roots中的位置
_find_two_min_tree(tar,&cur_tree_l,&cur_tree_r);
// 认为左结点会比右结点小,将树拼接,然后结点坐标存在roots的右边
_tree_merge(tar,cur_tree_l,cur_tree_r);
}
return true;
}
__attribute__((unused)) bool Init_HuffMan(HuffManTree* tar, pkg* info){
tar->trees = (Binary_Tree_Array*)malloc(sizeof(Binary_Tree_Array));
BinStaticTree_init(tar->trees, 2*info->n-1);
tar->treeNums = tar->curTop = tar->trees->cur =info->n;
tar->roots = (int*) malloc(sizeof(int)*info->n);
for(int i=0;i<info->n;i++){
tar->trees->elems[i].data = info->init[i];
tar->trees->elems[i].left = tar->trees->elems[i].right = -1;
tar->roots[i]=i;
}
tar->encoded = false;
return true;
}
//======================================================================================================================
bool _find_two_min_tree(HuffManTree* tar, int *min1, int *min2){
// 由于我们算法的设计,我们认为,0号位置一定会在交归纳中是最后一个树的根,用这个来预设
*min1 = *min2 = 0;
int temp;
// root负责记录是树根的结点位置
for(int i=1, j=0;i < tar->treeNums;i++){
temp = tar->roots[i];
if(temp>=0){
temp = tar->trees->elems[temp].data.freq;
if(temp <= tar->trees->elems[tar->roots[*min2]].data.freq){
if(temp < tar->trees->elems[tar->roots[*min1]].data.freq){
*min2 = *min1;
*min1 = i;
} else{
*min2 = i;
}
}
}
}
return true;
}
bool _tree_merge(HuffManTree* tar, int root_l, int root_r){
node l, r, cur;
l = tar->trees->elems[tar->roots[root_l]].data;
r = tar->trees->elems[tar->roots[root_r]].data;
tar->trees->elems[tar->roots[root_l]].parent = tar->trees->elems[tar->roots[root_r]].parent = tar->curTop;
// printf("merge %d,%d at %d,%d\n",root_l,root_r,tar->roots[root_l],tar->roots[root_r]);
// printf("with char: %c,%c\n",l.tar,r.tar);
// printf("with freq: %d,%d\n",l.freq,r.freq);
_StaticNode temp = {
{
's',l.freq + r.freq},tar->roots[root_l], tar->roots[root_r]};
tar->trees->elems[tar->curTop] = temp;
tar->roots[root_l] = tar->curTop;
tar->roots[root_r] = -1;
tar->curTop++;
return true;
}
bool HuffManDestruct(HuffManTree *tar){
BinStaticTree_destruct(tar->trees);
free(tar->trees);
free(tar->roots);
}
#endif //DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEENCODING_H
HuffManDecodificación
//
// Created by Zza on 2022/4/23.
//
#ifndef DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEDECODING_H
#define DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEDECODING_H
#include "./HuffManTreeEncoding.h"
#include <stdio.h>
#define HUFFMAN_CODE_NUMS 26
#define HUFFMAN_CODE_BASE_CHAR 'a'
typedef struct ResContainer{
char* res[HUFFMAN_CODE_NUMS];
}ResContainer;
bool ContainerDestruct(ResContainer*);
bool DisplayContainer(ResContainer*);
__attribute__((unused)) bool HuffManDecode_Display_Stack(HuffManTree* tar, int root);
bool HuffManDecode_Reverse(HuffManTree* tar, ResContainer*);
#ifndef TREE_STK
#define TREE_STK
typedef int tNode;
#endif
bool DisplayAct(char*, int, char);
// 我们应当好好利用哈夫曼树是一个完全二叉树的性质来进行解码
__attribute__((unused)) bool HuffManDecode_Display_Stack(HuffManTree* tar, int root){
Bin_Tree_Arr obj = tar->trees;
// 设置两个栈,一个栈用来存我们的行动路径,一个栈拿来存上一个根节点
char* routine = (char*) malloc(sizeof(char)*obj->cur);
int* nodes = (int*) malloc(sizeof(int)*obj->cur);
char act;
int i = 0, n = tar->treeNums;
// 总共访问n个叶子
while (n){
// 向左下搜索到最下方
printf("-----------------------\n"
"left searching, start root %d l:%d r:%d\n",
root,obj->elems[root].left,obj->elems[root].right);
while (root>=0 && obj->elems[root].left >= 0){
printf("%d-",root);
nodes[i] = root;
routine[i++] = '0';
root = obj->elems[root].left;
}
// 显示当前编码路径
DisplayAct(routine,i,obj->elems[root].data.tar);
n--;
// 向上退栈
// 首先,我们在路径栈中,存放的是我们以什么方式来到这个节点
// 如果我们是由向右操作,进入节点的话,说明我们已经访问过这个根的子树,应当再次向上
do {
if(!i)break;
root = nodes[--i];
act = routine[i];
// printf("trace back,act:%c, cur root %d l:%d r:%d\n",act,root,obj->elems[root].left,obj->elems[root].right);
// 每次路径退栈,也是反映我们是从左还是右回溯进入根的
}while (act == '1');
// 当我们一直向上走,如果我们是从左进入根时,认为左树遍历完成,我们就会退出循环,去访问右边
// 向右移动一次
root = obj->elems[root].right;
nodes[i] = root;
routine[i++] = '1';
// printf("right move, cur root %d l:%d r:%d\n",
// root,obj->elems[root].left,obj->elems[root].right);
}
return true;
}
bool HuffManDecode_Reverse(HuffManTree* tar, ResContainer* container){
int cur,temp,base;
for(int i=0;i<tar->treeNums;i++){
cur = i;
container->res[i] = (char*) malloc(sizeof(char)*tar->treeNums);
base = tar->treeNums;
container->res[i][--base] = '\0';
while (tar->trees->elems[cur].parent){
temp = tar->trees->elems[cur].parent;
container->res[i][--base] = (cur==tar->trees->elems[temp].left)?'0':'1';
cur = temp;
}
container->res[i][0] = (char)--base;
}
return true;
}
bool DisplayAct(char* tar, int len, char type){
printf("huffman code %c:",type);
for(int i=0;i<len;i++){
printf("%c",*tar);
tar++;
}
printf("\n");
}
bool ContainerDestruct(ResContainer* tar){
for (int i = 0; i < HUFFMAN_CODE_NUMS; ++i) {
free(tar->res[i]);
}
return true;
}
bool DisplayContainer(ResContainer* tar){
for (int i = 0; i < HUFFMAN_CODE_NUMS; ++i) {
printf("%c: %s\n",i+HUFFMAN_CODE_BASE_CHAR,&(tar->res[i][(tar->res[i][0])+1]));
}
return true;
}
#endif //DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREEDECODING_H
Envoltura de HuffMan
//
// Created by Zza on 2022/4/25.
//
#ifndef DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREE_H
#define DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREE_H
#include "HuffManTreeEncoding.h"
#include "HuffManTreeDecoding.h"
#include <stdio.h>
bool CalcCharFreq(const char* tar, pkg* res){
int map[HUFFMAN_CODE_NUMS];
for(int i=0;i<HUFFMAN_CODE_NUMS;i++){
map[i] = 0;
}
while (*tar){
map[(int)*tar-HUFFMAN_CODE_BASE_CHAR]++;
tar++;
}
res->init = (node*)malloc(sizeof(node)*HUFFMAN_CODE_NUMS);
res->n = HUFFMAN_CODE_NUMS;
for(int i=0;i<HUFFMAN_CODE_NUMS;i++){
res->init[i].tar = (char)(i+HUFFMAN_CODE_BASE_CHAR);
res->init[i].freq = map[i];
}
return true;
}
__attribute__((unused)) bool PkgDestruct(pkg* tar){
free(tar->init);
return true;
}
bool HuffManDisplay(const char* tar){
pkg info;
CalcCharFreq(tar,&info);
HuffManTree obj;
Init_HuffMan(&obj,&info);
HuffManEncoding(&obj);
DisplayHuffManStruct(&obj);
ResContainer container;
HuffManDecode_Reverse(&obj, &container);
DisplayContainer(&container);
HuffManDecode_Display_Stack(&obj, obj.curTop-1);
ContainerDestruct(&container);
HuffManDestruct(&obj);
PkgDestruct(&info);
return true;
}
bool DisplayHuffManStruct(HuffManTree* tar){
for(int i=0;i<tar->curTop;i++){
_StaticNode temp = tar->trees->elems[i];
printf("id: %d\t"
"char: %c\t"
"freq: %d\t"
"left: %d\t"
"right: %d\t"
"parent: %d\n",i,
temp.data.tar,temp.data.freq,temp.left,temp.right,temp.parent);
}
return true;
}
#endif //DATASTRUCTUREIMPLEMENTINGC_HUFFMANTREE_H