void BuildMinHeap(HNodeType Hf[], int n);//将线性表Hf改造成一个最小堆
void MinHeapSiftDown(HNodeType Hf[], int n, int pos);//向下调整二叉堆的第pos个元素,使其满足最小堆的特征
void HuffmanTree (HNodeType Hf[], int n);//将线性表改造成赫夫曼树
void DisplayCodebook(HCodeType Cb[], int n);//显示密码本中的明码和对应密码信息
int InsertCodeLib(HCodeType Cb[], int n, ElemType x, char *s, int len);//将新结点插入到密码本的编码线性表中
int HfCoding(HCodeType Cb[], HNodeType Hf[], int n);//根据赫夫曼树进行赫夫曼编码,生成密码本
int main(void)
{
HNodeType Hf[MAXSIZE*2]; //赫夫曼树
HCodeType codebook[MAXSIZE]; //密码本
int lenHf = 5; //赫夫曼树叶子结点个数
int lenCb; //密码本长度(等于lenHf)
int i;
/*
函数功能:将线性表改造成赫夫曼树
初始条件:非递减线性表Hf已经存在
操作结果:先将原线性表改造成最小堆(优先队列),然后按照如下顺序处理该最小堆:
删除权重最小的两个结点,并将他们加入到队列尾部,将该两个最小结点的权值相加,生成一个新结点,并将新结点加入到优先队列。
不断调整该最小堆,直到只剩下一个结点,即得到赫夫曼树。
注意:每次产生新结点时,只需设置新结点的权重及孩子结点信息,双亲结点信息等赫夫曼树构造完毕后再统一计算。
*/
void HuffmanTree (HNodeType Hf[], int n)
{
int i;
int len = 2*n - 1;
int front = n -1;
int rear = len - 1;
/*
函数功能:将新结点插入到密码本的编码线性表中
初始条件:每个编码的明文和密文信息分别记录在x和s中,len是字符串s的长度
操作结果:先折半查找插入位置,然后插入新结点,将x和s的信息复制给新结点,注意s中存储的结点编码的路径是从叶子到根,存储到密码本时需要逆序复制 。
*/
int InsertCodeLib(HCodeType Cb[], int n, ElemType x, char *s, int len)//采用二分查找插入排序
{
int i, mid;
int left = 0, right = n-1;
/*
函数功能:根据赫夫曼树进行赫夫曼编码,生成密码本
初始条件:赫夫曼树Hf已经存在,n是赫夫曼树的长度
操作结果:对赫夫曼树的叶子结点进行编码,并存储到密码本,返回密码本长度。
对密码本中的各个结点采用二分查找插入,构造非递减序列,以便于查找和编码。
*/
int HfCoding(HCodeType Cb[], HNodeType Hf[], int n)
{
int i, j, k, f;
int top = 0; //为编码结构体构造一个栈,top指示栈顶
char str[MAXSIZE]; //存储编码的临时字符串
for (i=0; i<n; i++)
{
if (Hf[i].lchild == -1)//是叶子结点
{
j = i;
f = Hf[j].parent;
k = 0;