#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CODE_LENGTH 100 //编码的最大长度
/*该结构体用来存储哈夫曼树的节点*/
typedef struct node_structure
{
int weight; //权值
char ch; //节点的字符信息
struct node_structure * leftchild; //坐子树
struct node_structure * rightchild; //右子树
}HuffmanTreeNode,*HFMTNodePointer;
/*该结构体用来存储从终端读入的叶子节点的字符和权值信息*/
typedef struct leafnode_structure
{
HuffmanTreeNode data; //哈夫曼树节点
struct leafnode_structure * next; //指向下一个节点
}LeafNode,*LeafNodePointer;
/*该结构体用来存储编码信息*/
typedef struct coding_structure
{
char ch; //叶子节点的字符信息
char code[CODE_LENGTH]; //该叶子节点对应的编码
struct coding_structure * next; //指向下一个叶子节点
}Coding, * CodingPointer;
void GetInfor(LeafNodePointer &info); //读入叶子节点
void HuffmanTreeCreating(HFMTNodePointer &rootnode,LeafNodePointer &info); //创建哈夫曼树
void PreOrderTraverse(HuffmanTreeNode *node); //前序遍历
void InOrderTraverse(HuffmanTreeNode *node); //中序遍历
void PostOrderTraverse(HuffmanTreeNode *node); //后序遍历
void PrintHuffmanTree(HuffmanTreeNode *node); //打印哈夫曼树
void GetCode(HuffmanTreeNode * rootnode,CodingPointer &codetable,char *temp); //求各叶子节点编码
void Encording(Coding *table); //编码
void Decording(HuffmanTreeNode * rootnode); //译码
int main()
{
printf("--------------------初始化---------------------\n");
/*变量初始化*/
char _code[CODE_LENGTH]; //编码缓冲区
int i;
for(i=0;i<CODE_LENGTH;i++)
_code[i]='\0';
HuffmanTreeNode *TreeRoot=NULL; //哈夫曼树的根节点指针
LeafNode *NodeInfo=NULL; //指向叶子节点所组成的链表
Coding * CodeTable=NULL; //指向叶子节点编码信息所组成的链表
GetInfor(NodeInfo); //从终端读入叶子节点字符和权值
HuffmanTreeCreating(TreeRoot,NodeInfo); //创建哈夫曼树
GetCode(TreeRoot,CodeTable,_code); //遍历树,存储编码
printf("\n-------------------编码&译码-------------------\n");
Encording(CodeTable); //编码
Decording(TreeRoot); //译码
printf("\n--------------打印各叶子节点编码---------------\n");
while(CodeTable!=NULL)
{
printf("%c : %s\n",CodeTable->ch,CodeTable->code);
CodeTable = CodeTable->next;
}
printf("\n-----------------打印哈夫曼树------------------\n");
PrintHuffmanTree(TreeRoot); //按照三种遍历顺序打印节点权值
printf("\n");
return 0;
}
/*************************************************
*
*功能简介:从终端读取字符和权值
* 根据权值的大小顺序插入链表中
*参数简介:info:上述链表指针引用,
* 指向叶子节点所组成的链表
*返回值: 无返回值
*
*************************************************/
void GetInfor(LeafNodePointer &info)
{
int n,i;
LeafNode * temp;
LeafNode * check;
info=NULL;
/*读入叶子节点数量*/
printf("请输入字符数量:\n");
scanf("%d",&n);
getchar();
while(n<2)
{
printf("数量不正确,请重新输入:\n");
scanf("%d",&n);
getchar();
}
/*读取&排序*/
printf("请输入字符和权值(形如:a,10 b,20 ... ):\n");
for(i=0;i<n;i++)
{
check = info;
if((temp=(LeafNode *)malloc(sizeof(LeafNode)))!=NULL)
{
/*读入叶子节点信息*/
if(i<n-1)
scanf("%c,%d ",&((temp->data).ch),&((temp->data).weight));
else
scanf("%c,%d",&((temp->data).ch),&((temp->data).weight));
//因为是叶子节点,所以左右子树指针为空
(temp->data).leftchild=NULL;
(temp->data).rightchild=NULL;
/*根据权值大小顺序插入链表中,越靠近头指针,权值越小*/
if(check==NULL||(check->data).weight>(temp->data).weight)
{
temp->next = info;
info=temp;
}
else
{
while(1)
{
if((check->next!=NULL&&(check->next->data).weight>(temp->data).weight)||check->next==NULL)
{
temp->next = check->next;
check->next = temp;
break;
}
check=check->next;
}
}
}
else
printf("内存分配异常!\n");
}
getchar(); //读取多余换行符
}
/*************************************************
*
*功能简介:创建哈夫曼树
*参数简介:rootnode:根节点指针的引用
* info:字符和权值信息指针的引用
*返回值: 无返回值
*
*************************************************/
void HuffmanTreeCreating(HFMTNodePointer &rootnode,LeafNodePointer &info)
{
LeafNode *root;
LeafNode *check;
while(1)
{
/*构造权值最轻的两个叶子节点的父节点。因为函数GetInfor已
经排序,所以最靠近叶子节点链表头指针的两个节点权值最轻*/
if((root=(LeafNode *)malloc(sizeof(LeafNode)))!=NULL)
{
root->data.ch='*'; //非叶子节点的字符默认为‘*’
root->data.weight=info->data.weight+info->next->data.weight; //父节点的权值等于两个子节点权值之和
root->data.rightchild=&(info->data); //指向子节点
root->data.leftchild=&(info->next->data);
info=info->next->next;//头指针指向第三个节点(将子节点从叶子节点链表中删除)
check=info;
if(check==NULL)//此时构造完成,因为没有零散的节点
break;
/*将上述构造的父节点按权值大小顺序插入节点链表*/
if((check->data).weight>(root->data).weight)
{
root->next = info;
info=root;
}
else
{
while(1)
{
if((check->next!=NULL&&(check->next->data).weight>(root->data).weight)||check->next==NULL)
{
root->next = check->next;
check->next = root;
break;
}
check=check->next;
}
}
}
}
rootnode=&(root->data);
}
/*************************************************
*
*功能简介:前序遍历哈夫曼树
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void PreOrderTraverse(HuffmanTreeNode *node)
{
if(node!=NULL)
{
printf("%d ",node->weight);
PreOrderTraverse(node->leftchild);
PreOrderTraverse(node->rightchild);
}
}
/*************************************************
*
*功能简介:中序遍历哈夫曼树
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void InOrderTraverse(HuffmanTreeNode *node)
{
if(node!=NULL)
{
InOrderTraverse(node->leftchild);
printf("%d ",node->weight);
InOrderTraverse(node->rightchild);
}
}
/*************************************************
*
*功能简介:中序遍历哈夫曼树
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void PostOrderTraverse(HuffmanTreeNode *node)
{
if(node!=NULL)
{
PostOrderTraverse(node->leftchild);
PostOrderTraverse(node->rightchild);
printf("%d ",node->weight);
}
}
/*************************************************
*
*功能简介:按照三种遍历顺序打印节点权值
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void PrintHuffmanTree(HuffmanTreeNode *node)
{
printf("用三种遍历方法打印树的各个节点权值:\n");
printf("\t前序遍历:");
PreOrderTraverse(node);
printf("\n");
printf("\t中序遍历:");
InOrderTraverse(node);
printf("\n");
printf("\t后序遍历:");
PostOrderTraverse(node);
}
/*************************************************
*
*功能简介:前序遍历哈夫曼树,并将沿途的编码信息
* 存入缓冲区,当访问叶子节点时将缓冲区
* 的编码和节点字符信息存入链表中
*参数简介:rootnode:根节点指针的引用
* codetable:指向上述链表
* temp:指向上述缓冲区
*返回值: 无返回值
*
*************************************************/
void GetCode(HuffmanTreeNode * rootnode,CodingPointer &codetable,char *temp)
{
int i;
CodingPointer codetemp;
if(rootnode!=NULL)
{
if(rootnode->leftchild==NULL&&rootnode->rightchild==NULL) //叶子节点
{
/*运用头插法向链表中插入新元素,并把编码信息记录到该元素*/
if((codetemp=(CodingPointer)malloc(sizeof(Coding)))!=NULL)
{
codetemp->ch=rootnode->ch;
strcpy(codetemp->code,temp);
codetemp->next=codetable;
codetable=codetemp;
}
}
else
{
/*前序遍历*/
i=strlen(temp);
temp[i]='0'; //遍历左子树编码为0
temp[i+1]='\0';
GetCode(rootnode->leftchild,codetable,temp);
temp[strlen(temp)-1]='1'; //遍历右子树编码为1
GetCode(rootnode->rightchild,codetable,temp);
temp[strlen(temp)-1]='\0'; //从右子树返回,退格
}
}
}
/*************************************************
*
*功能简介:编码。从终端读入字符信息,查询
* 编码信息所组成的链表,打印编码
*参数简介:table:指向编码链表
*返回值: 无返回值
*
*************************************************/
void Encording(Coding *table)
{
char ch;
Coding *temp;
//getchar();
printf("请输入需要编码的字符集(以‘#’结束):\n");
while((ch=getchar())!='#') //判断是否读完
{
/*查询链表*/
temp=table;
while(ch!=temp->ch&&temp!=NULL)
temp=temp->next;
if(ch==temp->ch)
printf("%s",temp->code);
}
getchar(); //读取多余换行符
printf("\n");
}
/*************************************************
*
*功能简介:译码。从终端读入编码信息。根据
* 编码信息访问子树,‘0’访问左子树,
* ‘1’访问右子树。如若访问的是叶子
* 节点就输出节点字符信息,下一轮循
* 环并从根节点开始访问子树。
*参数简介:rootnode:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void Decording(HuffmanTreeNode * rootnode)
{
HuffmanTreeNode *temp=rootnode;
char ch;
printf("请输入需要译码的字符数字(0,1;以'#'结束)\n");
while((ch=getchar())!='#') //判断是否读完
{
if(temp->leftchild!=NULL&&temp->rightchild!=NULL) //非叶子节点
{
/*访问子树*/
if(ch=='0')
temp=temp->leftchild;
else if(ch=='1')
temp=temp->rightchild;
}
if(temp->leftchild==NULL&&temp->rightchild==NULL) //叶子节点
{
printf("%c",temp->ch); //打印字符
temp=rootnode; //从根节点开始
}
}
getchar(); //读取多余换行符
printf("\n");
}
#include <stdlib.h>
#include <string.h>
#define CODE_LENGTH 100 //编码的最大长度
/*该结构体用来存储哈夫曼树的节点*/
typedef struct node_structure
{
int weight; //权值
char ch; //节点的字符信息
struct node_structure * leftchild; //坐子树
struct node_structure * rightchild; //右子树
}HuffmanTreeNode,*HFMTNodePointer;
/*该结构体用来存储从终端读入的叶子节点的字符和权值信息*/
typedef struct leafnode_structure
{
HuffmanTreeNode data; //哈夫曼树节点
struct leafnode_structure * next; //指向下一个节点
}LeafNode,*LeafNodePointer;
/*该结构体用来存储编码信息*/
typedef struct coding_structure
{
char ch; //叶子节点的字符信息
char code[CODE_LENGTH]; //该叶子节点对应的编码
struct coding_structure * next; //指向下一个叶子节点
}Coding, * CodingPointer;
void GetInfor(LeafNodePointer &info); //读入叶子节点
void HuffmanTreeCreating(HFMTNodePointer &rootnode,LeafNodePointer &info); //创建哈夫曼树
void PreOrderTraverse(HuffmanTreeNode *node); //前序遍历
void InOrderTraverse(HuffmanTreeNode *node); //中序遍历
void PostOrderTraverse(HuffmanTreeNode *node); //后序遍历
void PrintHuffmanTree(HuffmanTreeNode *node); //打印哈夫曼树
void GetCode(HuffmanTreeNode * rootnode,CodingPointer &codetable,char *temp); //求各叶子节点编码
void Encording(Coding *table); //编码
void Decording(HuffmanTreeNode * rootnode); //译码
int main()
{
printf("--------------------初始化---------------------\n");
/*变量初始化*/
char _code[CODE_LENGTH]; //编码缓冲区
int i;
for(i=0;i<CODE_LENGTH;i++)
_code[i]='\0';
HuffmanTreeNode *TreeRoot=NULL; //哈夫曼树的根节点指针
LeafNode *NodeInfo=NULL; //指向叶子节点所组成的链表
Coding * CodeTable=NULL; //指向叶子节点编码信息所组成的链表
GetInfor(NodeInfo); //从终端读入叶子节点字符和权值
HuffmanTreeCreating(TreeRoot,NodeInfo); //创建哈夫曼树
GetCode(TreeRoot,CodeTable,_code); //遍历树,存储编码
printf("\n-------------------编码&译码-------------------\n");
Encording(CodeTable); //编码
Decording(TreeRoot); //译码
printf("\n--------------打印各叶子节点编码---------------\n");
while(CodeTable!=NULL)
{
printf("%c : %s\n",CodeTable->ch,CodeTable->code);
CodeTable = CodeTable->next;
}
printf("\n-----------------打印哈夫曼树------------------\n");
PrintHuffmanTree(TreeRoot); //按照三种遍历顺序打印节点权值
printf("\n");
return 0;
}
/*************************************************
*
*功能简介:从终端读取字符和权值
* 根据权值的大小顺序插入链表中
*参数简介:info:上述链表指针引用,
* 指向叶子节点所组成的链表
*返回值: 无返回值
*
*************************************************/
void GetInfor(LeafNodePointer &info)
{
int n,i;
LeafNode * temp;
LeafNode * check;
info=NULL;
/*读入叶子节点数量*/
printf("请输入字符数量:\n");
scanf("%d",&n);
getchar();
while(n<2)
{
printf("数量不正确,请重新输入:\n");
scanf("%d",&n);
getchar();
}
/*读取&排序*/
printf("请输入字符和权值(形如:a,10 b,20 ... ):\n");
for(i=0;i<n;i++)
{
check = info;
if((temp=(LeafNode *)malloc(sizeof(LeafNode)))!=NULL)
{
/*读入叶子节点信息*/
if(i<n-1)
scanf("%c,%d ",&((temp->data).ch),&((temp->data).weight));
else
scanf("%c,%d",&((temp->data).ch),&((temp->data).weight));
//因为是叶子节点,所以左右子树指针为空
(temp->data).leftchild=NULL;
(temp->data).rightchild=NULL;
/*根据权值大小顺序插入链表中,越靠近头指针,权值越小*/
if(check==NULL||(check->data).weight>(temp->data).weight)
{
temp->next = info;
info=temp;
}
else
{
while(1)
{
if((check->next!=NULL&&(check->next->data).weight>(temp->data).weight)||check->next==NULL)
{
temp->next = check->next;
check->next = temp;
break;
}
check=check->next;
}
}
}
else
printf("内存分配异常!\n");
}
getchar(); //读取多余换行符
}
/*************************************************
*
*功能简介:创建哈夫曼树
*参数简介:rootnode:根节点指针的引用
* info:字符和权值信息指针的引用
*返回值: 无返回值
*
*************************************************/
void HuffmanTreeCreating(HFMTNodePointer &rootnode,LeafNodePointer &info)
{
LeafNode *root;
LeafNode *check;
while(1)
{
/*构造权值最轻的两个叶子节点的父节点。因为函数GetInfor已
经排序,所以最靠近叶子节点链表头指针的两个节点权值最轻*/
if((root=(LeafNode *)malloc(sizeof(LeafNode)))!=NULL)
{
root->data.ch='*'; //非叶子节点的字符默认为‘*’
root->data.weight=info->data.weight+info->next->data.weight; //父节点的权值等于两个子节点权值之和
root->data.rightchild=&(info->data); //指向子节点
root->data.leftchild=&(info->next->data);
info=info->next->next;//头指针指向第三个节点(将子节点从叶子节点链表中删除)
check=info;
if(check==NULL)//此时构造完成,因为没有零散的节点
break;
/*将上述构造的父节点按权值大小顺序插入节点链表*/
if((check->data).weight>(root->data).weight)
{
root->next = info;
info=root;
}
else
{
while(1)
{
if((check->next!=NULL&&(check->next->data).weight>(root->data).weight)||check->next==NULL)
{
root->next = check->next;
check->next = root;
break;
}
check=check->next;
}
}
}
}
rootnode=&(root->data);
}
/*************************************************
*
*功能简介:前序遍历哈夫曼树
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void PreOrderTraverse(HuffmanTreeNode *node)
{
if(node!=NULL)
{
printf("%d ",node->weight);
PreOrderTraverse(node->leftchild);
PreOrderTraverse(node->rightchild);
}
}
/*************************************************
*
*功能简介:中序遍历哈夫曼树
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void InOrderTraverse(HuffmanTreeNode *node)
{
if(node!=NULL)
{
InOrderTraverse(node->leftchild);
printf("%d ",node->weight);
InOrderTraverse(node->rightchild);
}
}
/*************************************************
*
*功能简介:中序遍历哈夫曼树
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void PostOrderTraverse(HuffmanTreeNode *node)
{
if(node!=NULL)
{
PostOrderTraverse(node->leftchild);
PostOrderTraverse(node->rightchild);
printf("%d ",node->weight);
}
}
/*************************************************
*
*功能简介:按照三种遍历顺序打印节点权值
*参数简介:node:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void PrintHuffmanTree(HuffmanTreeNode *node)
{
printf("用三种遍历方法打印树的各个节点权值:\n");
printf("\t前序遍历:");
PreOrderTraverse(node);
printf("\n");
printf("\t中序遍历:");
InOrderTraverse(node);
printf("\n");
printf("\t后序遍历:");
PostOrderTraverse(node);
}
/*************************************************
*
*功能简介:前序遍历哈夫曼树,并将沿途的编码信息
* 存入缓冲区,当访问叶子节点时将缓冲区
* 的编码和节点字符信息存入链表中
*参数简介:rootnode:根节点指针的引用
* codetable:指向上述链表
* temp:指向上述缓冲区
*返回值: 无返回值
*
*************************************************/
void GetCode(HuffmanTreeNode * rootnode,CodingPointer &codetable,char *temp)
{
int i;
CodingPointer codetemp;
if(rootnode!=NULL)
{
if(rootnode->leftchild==NULL&&rootnode->rightchild==NULL) //叶子节点
{
/*运用头插法向链表中插入新元素,并把编码信息记录到该元素*/
if((codetemp=(CodingPointer)malloc(sizeof(Coding)))!=NULL)
{
codetemp->ch=rootnode->ch;
strcpy(codetemp->code,temp);
codetemp->next=codetable;
codetable=codetemp;
}
}
else
{
/*前序遍历*/
i=strlen(temp);
temp[i]='0'; //遍历左子树编码为0
temp[i+1]='\0';
GetCode(rootnode->leftchild,codetable,temp);
temp[strlen(temp)-1]='1'; //遍历右子树编码为1
GetCode(rootnode->rightchild,codetable,temp);
temp[strlen(temp)-1]='\0'; //从右子树返回,退格
}
}
}
/*************************************************
*
*功能简介:编码。从终端读入字符信息,查询
* 编码信息所组成的链表,打印编码
*参数简介:table:指向编码链表
*返回值: 无返回值
*
*************************************************/
void Encording(Coding *table)
{
char ch;
Coding *temp;
//getchar();
printf("请输入需要编码的字符集(以‘#’结束):\n");
while((ch=getchar())!='#') //判断是否读完
{
/*查询链表*/
temp=table;
while(ch!=temp->ch&&temp!=NULL)
temp=temp->next;
if(ch==temp->ch)
printf("%s",temp->code);
}
getchar(); //读取多余换行符
printf("\n");
}
/*************************************************
*
*功能简介:译码。从终端读入编码信息。根据
* 编码信息访问子树,‘0’访问左子树,
* ‘1’访问右子树。如若访问的是叶子
* 节点就输出节点字符信息,下一轮循
* 环并从根节点开始访问子树。
*参数简介:rootnode:根节点指针的引用
*返回值: 无返回值
*
*************************************************/
void Decording(HuffmanTreeNode * rootnode)
{
HuffmanTreeNode *temp=rootnode;
char ch;
printf("请输入需要译码的字符数字(0,1;以'#'结束)\n");
while((ch=getchar())!='#') //判断是否读完
{
if(temp->leftchild!=NULL&&temp->rightchild!=NULL) //非叶子节点
{
/*访问子树*/
if(ch=='0')
temp=temp->leftchild;
else if(ch=='1')
temp=temp->rightchild;
}
if(temp->leftchild==NULL&&temp->rightchild==NULL) //叶子节点
{
printf("%c",temp->ch); //打印字符
temp=rootnode; //从根节点开始
}
}
getchar(); //读取多余换行符
printf("\n");
}