文章目录

  • 一、 问题
    • 需求分析
    • 代码分析
      • 结构体定义使用
      • 建立哈夫曼树,首先需要找到两个权值最小的两个叶子结点,然后建树
      • 哈夫曼编码(我采用的是从叶子结点-->根节点,所以实际是反过来的)
      • 使用哈夫曼树译码(包括文件保存)
  • 全部代码(测试文件之类的在下面的链接)
  • 源码及文件
  • 总结

一、 问题

需求分析

此图转载于账号u014447560(深海鲸歌)

代码分析

结构体定义使用

需要定义树的结构,打印树的结构时需要用的队列

typedef struct node{char data;int weight;int parent;int lchild,rchild;int mark;
}huffmanTree;typedef  struct  code_N{char ch;char Bi_code[100];
}Char_coding;typedef struct queue_node{int data;struct LinkNode *next;
}LinkNode;typedef struct queue{struct queue_node* rear,*front;
}LinkQueue;
int allchar =0;     //记录所有字母的个数

建立哈夫曼树,首先需要找到两个权值最小的两个叶子结点,然后建树

初始化树


void find_min(huffmanTree *tree,int max,int *firstMin,int *secMin){//查找两个最小的值int smallindex[2];for(int j = 0;j<2;j++){int temp = 9999;int count = 0;int final_index =0;for(int k = 0;k<=max;k++) {if(tree[k].mark==0){if(tree[k].weight<temp){final_index = k;temp = tree[k].weight;}}else{count++;}
//            最后一个结点if(count ==max &&j ==0){return ;}}tree[final_index].mark =1;smallindex[j] = final_index;}*firstMin = smallindex[0];*secMin =smallindex[1];}
//建树
huffmanTree * Init_huffmanTree(huffmanTree *tree,char *ch,int *weight){int all_node;int count = strlen(ch);if(strlen(ch)<0){return NULL;}all_node = 2*count -1;
//    初始化哈夫曼树tree = (huffmanTree*) malloc((all_node)*sizeof (huffmanTree));for(int i = 0;i<count;i++){tree[i].data =ch[i];tree[i].weight = weight[i];tree[i].parent =-1;tree[i].lchild=-1;tree[i].rchild =-1;tree[i].mark =0;}for(int j = count;j<all_node;j++){tree[j].data ='#';tree[j].parent =-1;tree[j].weight =-1;tree[j].parent =tree[j].rchild=tree[j].lchild =-1;tree[j].mark =0;}for(int i = count;i<all_node;i++){int fristMin,secMin;fristMin = secMin = 0;find_min(tree,i-1,&fristMin,&secMin);       //找到最小索引的两个的下标tree[fristMin].parent = i;tree[secMin].parent = i;tree[i].weight = tree[fristMin].weight+tree[secMin].weight;tree[i].lchild = fristMin;tree[i].rchild = secMin;}return tree;        //返回初始化的哈夫曼树
}

哈夫曼编码(我采用的是从叶子结点–>根节点,所以实际是反过来的)

Char_coding * print_huffmancode(huffmanTree *tree,Char_coding *coding){//    编码int ch_length = allchar;    //总数coding = (Char_coding*) malloc(sizeof (Char_coding)*(ch_length));Char_coding s;for (int i = 0;i<ch_length;i++) {int child_curr = i;int parent_curr = tree[i].parent;int j = 0;  //记录字符的索引int length_coding =0;       //记录编码的长度,在最后设置\000while (parent_curr != -1) {if (tree[parent_curr].lchild == child_curr) {//                左子树设为0s.Bi_code[j] = '0';child_curr = parent_curr;parent_curr = tree[child_curr].parent;length_coding++;j++;} else {//                右子树设为1s.Bi_code[j] = '1';child_curr = parent_curr;parent_curr = tree[child_curr].parent;length_coding++;j++;}}s.ch = tree[i].data;coding[i] = s;
//        处理串的末尾coding[i].Bi_code[length_coding] ='\000';
//        printf("%d %s\n",i, coding[i].Bi_code);}return coding;      //返回编码好的哈夫曼编码,从叶子到根节点
}

使用哈夫曼树译码(包括文件保存)

void Decoding(Char_coding *coding,huffmanTree *tree,char *f_name,char *fp_write){//    译码FILE *fp1;FILE *fp_w;int length = allchar;fp_w = fopen(fp_write,"w+");fp1= fopen(f_name,"r");if(fp1 ==NULL){printf("译码文件不存在");}int root_index = 2*length-2;int child_root = root_index;while (!feof(fp1)){char temp = fgetc(fp1);if(temp!='\n'){if(temp == '0'){child_root = tree[child_root].lchild;
//                找到叶子结点if(tree[child_root].lchild ==-1 &&tree[child_root].rchild ==-1){//                    printf("%c",tree[child_root].data);fputc(tree[child_root].data,fp_w);
//                    回溯到根节点child_root = root_index;}}else {if (tree[child_root].rchild != -1) {child_root = tree[child_root].rchild;if (tree[child_root].lchild == -1 && tree[child_root].rchild == -1) {//                        printf("%c", tree[child_root].data);fputc(tree[child_root].data,fp_w);child_root = root_index;}}}}else{continue;}}fclose(fp1);fclose(fp_w);
}

全部代码(测试文件之类的在下面的链接)

#include <stdio.h>
#include <string.h>
#include <malloc.h>typedef struct node{char data;int weight;int parent;int lchild,rchild;int mark;
}huffmanTree;typedef  struct  code_N{char ch;char Bi_code[100];
}Char_coding;typedef struct queue_node{int data;struct LinkNode *next;
}LinkNode;typedef struct queue{struct queue_node* rear,*front;
}LinkQueue;int allchar =0;     //记录所有字母的个数void find_min(huffmanTree *tree,int max,int *firstMin,int *secMin){//查找两个最小的值int smallindex[2];for(int j = 0;j<2;j++){int temp = 9999;int count = 0;int final_index =0;for(int k = 0;k<=max;k++) {if(tree[k].mark==0){if(tree[k].weight<temp){final_index = k;temp = tree[k].weight;}}else{count++;}
//            最后一个结点if(count ==max &&j ==0){return ;}}tree[final_index].mark =1;smallindex[j] = final_index;}*firstMin = smallindex[0];*secMin =smallindex[1];}Char_coding * print_huffmancode(huffmanTree *tree,Char_coding *coding){//    编码int ch_length = allchar;    //总数coding = (Char_coding*) malloc(sizeof (Char_coding)*(ch_length));Char_coding s;for (int i = 0;i<ch_length;i++) {int child_curr = i;int parent_curr = tree[i].parent;int j = 0;  //记录字符的索引int length_coding =0;       //记录编码的长度,在最后设置\000while (parent_curr != -1) {if (tree[parent_curr].lchild == child_curr) {//                左子树设为0s.Bi_code[j] = '0';child_curr = parent_curr;parent_curr = tree[child_curr].parent;length_coding++;j++;} else {//                右子树设为1s.Bi_code[j] = '1';child_curr = parent_curr;parent_curr = tree[child_curr].parent;length_coding++;j++;}}s.ch = tree[i].data;coding[i] = s;
//        处理串的末尾coding[i].Bi_code[length_coding] ='\000';
//        printf("%d %s\n",i, coding[i].Bi_code);}return coding;      //返回编码好的哈夫曼编码,从叶子到根节点
}huffmanTree * Init_huffmanTree(huffmanTree *tree,char *ch,int *weight){int all_node;int count = strlen(ch);if(strlen(ch)<0){return NULL;}all_node = 2*count -1;
//    初始化哈夫曼树tree = (huffmanTree*) malloc((all_node)*sizeof (huffmanTree));for(int i = 0;i<count;i++){tree[i].data =ch[i];tree[i].weight = weight[i];tree[i].parent =-1;tree[i].lchild=-1;tree[i].rchild =-1;tree[i].mark =0;}for(int j = count;j<all_node;j++){tree[j].data ='#';tree[j].parent =-1;tree[j].weight =-1;tree[j].parent =tree[j].rchild=tree[j].lchild =-1;tree[j].mark =0;}for(int i = count;i<all_node;i++){int fristMin,secMin;fristMin = secMin = 0;find_min(tree,i-1,&fristMin,&secMin);       //找到最小索引的两个的下标tree[fristMin].parent = i;tree[secMin].parent = i;tree[i].weight = tree[fristMin].weight+tree[secMin].weight;tree[i].lchild = fristMin;tree[i].rchild = secMin;}return tree;        //返回初始化的哈夫曼树
}huffmanTree * Init_file_tree(huffmanTree *tree,char* fp_save){FILE *fp;fp = fopen(fp_save,"r");if(fp ==NULL){printf("初始化文件不存在:%s",fp_save);exit(0);}int count = 0;while(!feof(fp)){char temp[200];fgets(temp,200,fp);count++;}
//   根据文件进行初始化fclose(fp);tree = (huffmanTree *) malloc(sizeof (huffmanTree)*(count-1));fp = fopen(fp_save,"r");for(int i = 0;i<count-1;i++){fscanf(fp,"%c,%d,%d,%d,%d,%d\n",&tree[i].data,&tree[i].weight,&tree[i].parent,&tree[i].lchild,&tree[i].rchild,&tree[i].mark);}allchar = (count+1)/2;
//    printf("%c",tree[0].data);return tree;        //返回初始化的哈夫曼树
}void set_tree(huffmanTree *tree,char *file_save){int length = allchar;int node_len = 2*length -1;FILE *fp_save;fp_save = fopen(file_save,"w+");if (fp_save==NULL){printf("文件打开错误");exit(0);}for(int i = 0; i<node_len;i++){fprintf(fp_save,"%c,%d,%d,%d,%d,%d\n",tree[i].data,tree[i].weight,tree[i].parent,tree[i].lchild,tree[i].rchild,tree[i].mark);
//        printf("%c %d %d %d %d\n",tree[i].data,tree[i].parent,tree[i].lchild,tree[i].rchild,tree[i].mark);}fclose(fp_save);
}void seting_file(Char_coding *coding,huffmanTree *tree,char *word,char *f_name){//    保存目标文本编码到文件int length  = allchar;int char_length = strlen(word);FILE *fp;fp = fopen(f_name,"w+");if(fp==NULL){printf("文件打开错误");exit(0);}unsigned long count_line = 0;for(int i = 0;i<char_length;i++){for(int j = 0;j<length;j++){if(coding[j].ch == word[i]){for(int k =strlen(coding[j].Bi_code)-1;k>=0;k--){//                    printf("%c",coding[j].Bi_code[k]);fputc(coding[j].Bi_code[k],fp);
//                    在写入文件时50个换行
//                    if((count_line+1)%50==0){//                        fputc('\n',fp);
//                    }count_line++;}break;}}}fclose(fp);
}void Decoding(Char_coding *coding,huffmanTree *tree,char *f_name,char *fp_write){//    译码FILE *fp1;FILE *fp_w;int length = allchar;fp_w = fopen(fp_write,"w+");fp1= fopen(f_name,"r");if(fp1 ==NULL){printf("译码文件不存在");}int root_index = 2*length-2;int child_root = root_index;while (!feof(fp1)){char temp = fgetc(fp1);if(temp!='\n'){if(temp == '0'){child_root = tree[child_root].lchild;
//                找到叶子结点if(tree[child_root].lchild ==-1 &&tree[child_root].rchild ==-1){//                    printf("%c",tree[child_root].data);fputc(tree[child_root].data,fp_w);
//                    回溯到根节点child_root = root_index;}}else {if (tree[child_root].rchild != -1) {child_root = tree[child_root].rchild;if (tree[child_root].lchild == -1 && tree[child_root].rchild == -1) {//                        printf("%c", tree[child_root].data);fputc(tree[child_root].data,fp_w);child_root = root_index;}}}}else{continue;}}fclose(fp1);fclose(fp_w);
}//入队
void InQueue(LinkQueue *queue,int x){//生成新节点LinkNode *p = (LinkNode*) malloc(sizeof (LinkNode*));p->data = x;p->next = NULL;if(queue->front ==NULL){queue->front = queue->rear = p;}else {queue->rear->next = p;queue->rear = p;}
}
//出队列
int DeQueue(LinkQueue *queue){if(queue->front ==NULL){return 0;}LinkNode *p = queue->front;int temp = p->data;        //保存出队列的值queue->front = p->next;
//    free(p);return temp;
}void init_queue(LinkQueue *queue){queue->front = queue->rear =NULL;
}void traverse_tree(huffmanTree*tree){//    层次遍历LinkQueue queue;init_queue(&queue);int length = allchar;int all_node = 2*length-1;int count = all_node;int root_index = all_node-1;int ceng_index = root_index;int cennum =1;printf("下面是按照凹入表示法打印的哈夫曼树");while(count>0){for(int i = 0;i<cennum;i++){printf("-");}printf("%c\n",tree[root_index].data);count--;int l_child_index = tree[root_index].lchild;int right_index = tree[root_index].rchild;if(l_child_index!=-1){InQueue(&queue,l_child_index);}if(ceng_index == root_index){cennum++;
//            printf("\n");if(l_child_index !=-1 &&right_index !=-1 ){ceng_index = right_index;}else if(l_child_index ==-1 && right_index !=-1){ceng_index = right_index;}else if(l_child_index !=-1&& right_index ==-1){ceng_index = l_child_index;}else{ceng_index = tree[tree[tree[root_index].parent].lchild].rchild;}}if(right_index!=-1){InQueue(&queue,right_index);}root_index = DeQueue(&queue);}}void showface() {printf("\n\n");printf("\t\t\t====================哈夫曼树译码系统====================\n");printf("\t\t\t*                                                      *\n");printf("\t\t\t*         1>.初始化哈夫曼树 \n");printf("\t\t\t*         2>. 编码\n");printf("\t\t\t*         3>. 译码\n");printf("\t\t\t*         4>. 打印字符编码文件信息\n");printf("\t\t\t*         5>. 打印哈夫曼树\n");printf("\t\t\t*         0>. 退出本系统\n");printf("\t\t\t*         欢迎使用本系统!\n\n");printf("\t\t\t=========================================================\n");
}huffmanTree * input_data(huffmanTree *tree){int num;printf("请输入字符总数\n");scanf("%d",&num);allchar = num;int weight[27] = {186, 64, 13, 22, 32, 103, 21,15, 47, 57 ,1 ,5, 32,20 ,57, 63, 15, 1 ,48 ,51, 80, 23 ,8, 18 ,1, 16, 1};char ch[27][2] = {' ','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};tree= Init_huffmanTree(&tree,ch,&weight);       //初始化哈夫曼树return  tree;
}void printf_code_print(char *filename){FILE *fp;fp = fopen(filename,"r");if(fp==NULL){printf("文件不存在");exit(0);}int count=0;while(!feof(fp)){char temp = fgetc(fp);if(temp !=EOF){printf("%c",temp);}if((count+1)%50 ==0){printf("\n");}count++;}
}int main() {int button;huffmanTree *tree;char word[200];int num;Char_coding *coding;int isinit = 0;char fp_save[200] ="../save_tree.txt";char fp [200]="../codeing.txt";char fp_w [200] = "../textfile.txt";do {showface();printf("请输入相应的数字,进行相应的操作:\n");scanf("%d", &button);switch (button) {case 1:tree = input_data(&tree);set_tree(tree,fp_save);isinit =1;break;case 2:if(isinit ==0){isinit =1;tree = Init_file_tree(&tree,fp_save);}printf("请输入你想要编码的字符串\n");scanf("%s",word);coding =print_huffmancode(tree,&coding);seting_file(coding,tree,word,fp);break;case 3:if(isinit ==0){isinit =1;tree = Init_file_tree(&tree,fp_save);}Decoding(coding,tree,fp,fp_w);break;case 4:if(isinit ==0){isinit =1;tree = Init_file_tree(&tree,fp_save);}printf_code_print(fp);break;case 5:if(isinit ==0){isinit =1;tree = Init_file_tree(&tree,fp_save);}traverse_tree(tree);break;case 0:printf("即将退出.....");exit(0);default:printf("您输入的指令不正确,请重新输入");break;}printf("\n\n");} while (button);return 0;
}

源码及文件

链接:https://pan.baidu.com/s/154ub53uLrhoXN4IYwn5gUw
提取码:1314

总结

上述是哈夫曼树的编码和译码过程,本文的字母是自己已经固定了,但是基本不变,本人是菜鸡一枚,需要的可以自取,如果有问题,可以在评论区交流,或者私信我。

数据结构哈夫曼树(C语言版)相关推荐

  1. 数据结构---哈夫曼树

    数据结构-哈夫曼树 原理:参考趣学数据结构 代码: #include<stdio.h> #include<stdlib.h> #define N 100 #define INF ...

  2. 【数据结构——哈夫曼树及其应用】

    [数据结构--哈夫曼树及其应用] 一.哈夫曼树的基本概念 二.哈夫曼树的构造算法 (一)哈夫曼树的构造过程 (二)哈夫曼树构造算法的实现 1.初始化 2.创建树 3.完整的创建哈夫曼树代码 三.哈夫曼 ...

  3. 数据结构哈夫曼树实现26个英文字符的编码和译码

    数据结构哈夫曼树实现26英文字符的编码和译码 那么首先什么是哈夫曼树?(知道的略过,直奔下面代码就好!) 在计算机数据处理中,霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编 ...

  4. 数据结构--赫夫曼树

    数据结构 –赫夫曼树 文章目录 数据结构 一.一些概念 二.最优二叉树(赫夫曼树) 三.赫夫曼树的构造 四.赫夫曼编码 五.前缀编码 一.一些概念 路径:从树中一个结点到另一个结点之间的分支构成这两个 ...

  5. 数据结构(哈夫曼树,哈夫曼编码)入门篇,JAVA实现

    什么是哈夫曼树 哈夫曼树就是一种最优判定树,举个例子,如下一个判断逻辑 if(s<60) g=1; else if(s<70) g=2 else if(s<80) g=3 else ...

  6. 字符串哈夫曼树C语言,C语言实现哈夫曼树的方法

    本文实例为大家分享了C语言实现哈夫曼树的具体代码,供大家参考,具体内容如下 准备工作: 1.定义一个结构体,表示一个节点.其中,这个结构体有4个成员变量,分别表示是这个节点的权值,父节点及左右子节点的 ...

  7. 蓝桥哈夫曼树C语言,实验四 哈夫曼树及哈夫曼编码

    实验目的## 掌握哈夫曼树的概念.哈夫曼编码及其应用. 掌握生成哈夫曼树的算法. 会用哈夫曼树对传输报文进行编码. 掌握二叉树的二叉链表存储方式及相应操作的实现. ##实验内容## 用哈夫曼编码进行通 ...

  8. 数据结构 - 赫夫曼树

    wpl最小的就是赫夫曼树(所有叶子节点的带权路径长度之和最小) 写出来两个节点连接,然后循环就可以了 package tree.huffmantree;import java.util.ArrayLi ...

  9. 数据结构--赫夫曼树及其应用

    讲解请参考 赫夫曼 ------ 赫夫曼树和赫夫曼编码的存储表示------ typedef struct {unsigned int weight;unsigned int parent,lchil ...

最新文章

  1. 如此通俗的分布式锁讲解,如果还搞不定那就...
  2. 全球变暖java_第九届 蓝桥杯 JavaB组 全球变暖
  3. java简单的死锁检测(转载线下代码)
  4. 阿里云MaxCompute印度开服,加速大数据产业升级
  5. WebStorm打开设置界面
  6. AI表情迁移、电影字幕自动翻译等,原来是这么玩的!
  7. click和blur冲突的问题
  8. python有什么证可以考1002python有什么证可以考_离python二级考还有十几天,吓的我赶紧买了本python教程...
  9. 第六步_安装SSH服务
  10. 微波烹调,营养损失多or少?
  11. 你需要启用steam社区界面功能以进行购买_steam官网手机版免费下载-steam官网手机客户端下载...
  12. MFC实现文字随鼠标移动
  13. Blast2GO使用方法详解(命令界面)
  14. 关于solidworks+workbench的参数化建模分析的一点心得1
  15. echarts 时间轴处理_echarts 带时间轴可缩放的折线图
  16. 初创企业选择阿里云服务器与传统自建服务器的对比与选择
  17. 排序算法的时间与空间复杂度分析
  18. linux 脚本 input,Linux 下通过命令行和脚本开关笔记本触控板和其他输入外设
  19. PCI总线---深入理解PCI总线
  20. 机器学习常用的五种预测结果评价

热门文章

  1. Rabbitmq 安全账号管理方案
  2. 对比学习的应用(SimCSE,CLEAR,DeCLUTR,DiffCSE)
  3. 阿里云服务器部署(2)---配置EMQX服务器(企业版)
  4. 37岁程序员被裁,120天没找到工作,无奈去小公司,结果蒙了
  5. 文本搜索引擎Lucene之filed详解和代码测试
  6. 德语计算机相关的动词,德语常用计算机词汇汇总
  7. CSS中已经定义宽度的样式 英文不执行换行
  8. 【发现】中国与日德最可怕的差距,看着寒心
  9. licode erizo pipleline 1 : handlercontext
  10. 作为零基础的新手,如何自学Java和JavaEE开发技术?