从头结点开始编码的赫夫曼树

Posted rainbow-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从头结点开始编码的赫夫曼树相关的知识,希望对你有一定的参考价值。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#ifndef MACRO_//
#define MACRO_
#define OK 1
#define FALSE 0
#define ERROR 0
#define TURE 1
#define OVERFLOW -2
#define INFEASIBLE -1
typedef int Status;
typedef int BOOL;
#endif 
/*注意,自顶向下求编码会破坏HT的原本数据,都变成2,要想克服,需采用自底向上求编码
      或者另设记录每个元素访问记录的数组
    同时,也无法正确解码 -----------------严蔚敏教材缺陷---------------
*/ typedef struct { int weight; int parent, lchild, rchild; }HTNode, *HuffmanTree;//动态分配数组存储赫夫曼树 typedef char **HuffmanCode;//动态分配数组存储赫夫曼编码表 Status Input(int *ElemNum, int **WeightArray); //输入权值 //成功返回OK,ElemNum不合适返回ERROR void SlectMin(int i, int *S1, int *S2, HuffmanTree HT); //从HuffmanTree中选出Parent为0,权值最小的两个数,分别将下标存放在S1和S2中,其中S1中存放的值<S2中存放的值 //i表示当前有效结点的下标 void CreatHuffmanTree(HuffmanTree *HT, int *WeightArray, int ElemNum); //WeightArray存放ElemNum个字符的权值(均>0),构造赫夫曼树HT void HuffmanCoding_FromRoot(HuffmanTree HT, HuffmanCode *HC, int ElemNum); //从头结点开始遍历,求出n个字符的赫夫曼编码HC void Decode(HuffmanTree HT, int ElemNum); //输入哈夫曼编码,解码 int main() { int ElemNum, *WeightArray; HuffmanTree HT; HuffmanCode HC; while (Input(&ElemNum, &WeightArray) == ERROR) printf("The value of ElemNum is not feasible ! "); CreatHuffmanTree(&HT, WeightArray, ElemNum); HuffmanCoding_FromRoot(HT, &HC, ElemNum); for (int i = 1; i <= ElemNum; ++i) printf("%-3d ,coding is : %s ", HT[i].weight, HC[i]); /*注意,自顶向下求编码会破坏HT的原本数据,都变成2,要想克服,需采用自底向上求编码 或者另设记录每个元素访问记录的数组 -----------------严蔚敏教材缺陷--------------- */ Decode(HT, ElemNum); system("pause"); } Status Input(int *ElemNum,int **WeightArray) //输入权值 //成功返回OK,ElemNum不合适返回ERROR { printf("How many elems ? "); scanf("%d", ElemNum); if (*ElemNum>1)//小于2还建什么Huffman树呢? { *WeightArray = (int *)malloc(sizeof(int)*(*ElemNum)); if (!(*WeightArray)) exit(OVERFLOW); printf(" Please Enter the weight "); for (int i = 0; i < (*ElemNum); ++i) scanf("%d", &(*WeightArray)[i]); return OK; }//if return ERROR; }//CrearHuffmanTree void CreatHuffmanTree(HuffmanTree *HT,int *WeightArray,int ElemNum) //WeightArray存放ElemNum个字符的权值(均>0),构造赫夫曼树HT { for (int i = 0; i < ElemNum; ++i) printf("%d ", WeightArray[i]); int TotalNum = 2 * ElemNum - 1;//总结点数 *HT = (HuffmanTree)malloc(sizeof(HTNode)*(TotalNum + 1));//0号单元弃用,动态分配数组存储赫夫曼树 if (!*HT)exit(OVERFLOW);//分配失败 HuffmanTree p = *HT; int i,S1,S2; for (i = 1; i <=ElemNum; ++i) (*HT)[i] = {WeightArray[i-1], 0, 0, 0 };//初始化赫夫曼树前ElemNum个结点 for (i; i <= TotalNum; ++i) (*HT)[i] = { 0, 0, 0, 0 };//初始化后面的结点 for (i = 0; i < ElemNum-1; ++i)//ElemNum需循环建树ElemNum-1次 { SlectMin(i + ElemNum, &S1, &S2, *HT);//选出两个最小值S1,S2,其中S1的值小于S2的值 //printf(" Take %d %d ", S1, S2); (*HT)[S1].parent = (*HT)[S2].parent = i + ElemNum + 1;//i+ElemNum+1的值是父节点的下标 (*HT)[i + ElemNum + 1].lchild = S1; (*HT)[i + ElemNum + 1].rchild = S2; (*HT)[i + ElemNum + 1].weight = (*HT)[S1].weight + (*HT)[S2].weight; }//for printf(" ---------------------Creat HuffmanTree OK !--------------------- "); }//CreatHuffmanTree void SlectMin(int i,int *S1,int *S2,HuffmanTree HT) //从HuffmanTree中选出Parent为0,权值最小的两个数,分别将下标存放在S1和S2中,其中S1中存放的值<S2中存放的值 //i表示当前有效结点的下标 { int j; *S1 = *S2 = INT_MAX; for (j = 1; j <= i; ++j)//选出第一个最小值 { if (HT[j].parent != 0)//父节点需为0 continue; if (HT[*S1].weight > HT[j].weight) *S1 = j; }//for for (j = 1; j <= i; ++j)//选出第二个最小值 { if (HT[j].parent != 0)//父节点需为0 continue; if (j == *S1)//不能选刚选过的 continue; if (HT[*S2].weight > HT[j].weight) *S2 = j; }//for }//SlectMin void HuffmanCoding_FromRoot(HuffmanTree HT,HuffmanCode *HC,int ElemNum) //从头结点开始遍历,求出n个字符的赫夫曼编码HC { *HC = (HuffmanCode)malloc(sizeof(char *)*(ElemNum + 1)); if (!(*HC))exit(OVERFLOW); char *buffer = (char *)malloc(sizeof(char)*ElemNum);//分配编码缓冲区大小 if (!buffer)exit(OVERFLOW); int CodeNum = 2 * ElemNum - 1;//正在访问结点的下标 int CodeLen = 0;//编码长度 for (int i = 1; i <= CodeNum; ++i) HT[i].weight = 0;//遍历赫夫曼树时用作结点状态标志(相当于初始化访问次数) while (CodeNum)//访问到根结点的父节点即0,说明遍历完该树 { if (HT[CodeNum].weight == 0)//还没被访问过 { HT[CodeNum].weight = 1;//标记访问一次 if (HT[CodeNum].lchild != 0)//有左子树,访问它的左子树 { CodeNum = HT[CodeNum].lchild; buffer[CodeLen++] = 0;//向左访问,编码为0 }//if else if (HT[CodeNum].rchild == 0)//左子树右子树都为0,说明它是叶子结点 { buffer[CodeLen] = ; (*HC)[CodeNum] = (char *)malloc(sizeof(char)*(CodeLen + 1)); if (!(*HC)[CodeNum])exit(OVERFLOW);//分配存储空间失败 strcpy((*HC)[CodeNum], buffer);//将编码拷贝 }//else if }//if else if (HT[CodeNum].weight==1)//被访问过一次,即该结点左子树被访问过,接下来访问它的右子树 { HT[CodeNum].weight = 2;//标记访问2次 if (HT[CodeNum].rchild != 0)//有右子树,访问它的右子树 { CodeNum = HT[CodeNum].rchild; buffer[CodeLen++] = 1;//向右访问,编码为1 }//if }//else if else//被访问过2次,即左子树右子树都被访问过,回溯 { --CodeLen; CodeNum = HT[CodeNum].parent; }//else }//while }//HuffmanCoding void Decode(HuffmanTree HT,int ElemNum) //输入哈夫曼编码,解码 { int i = 2*ElemNum-1; char buffer[20]; fflush(stdin); printf("Enter the huffmanCode : "); gets(buffer); int j = 0; while (buffer[j]!=) { if (buffer[j]==0) i = HT[i].lchild; else i = HT[i].rchild; ++j; }//while printf("The num is %d", HT[i].weight); }//Decode

 


以上是关于从头结点开始编码的赫夫曼树的主要内容,如果未能解决你的问题,请参考以下文章

赫夫曼树编码

哈夫曼树和哈夫曼编码

赫夫曼树及赫夫曼编码

哈夫曼树和哈夫曼编码

赫夫曼树和赫夫曼编码

哈夫曼树与哈夫曼编码