二叉树的基本操作及哈夫曼编码/译码系统的实现

实验目的和要求

  • 掌握二叉树的二叉链表存储表示及遍历操作实现方法。
  • 实现二叉树遍历运算的应用:求二叉树中叶结点个数、结点总数、二叉树的高度,交换二叉树的左右子树。
  • 掌握二叉树的应用——哈夫曼编码的实现。

二叉树的基本操作

#include <stdio.h>
#include <stdlib.h>//二叉树结点结构体typedef  char ElemType;
typedef struct btnode
{ElemType element;struct btnode *lChild;struct btnode *rChild;
}BTNode;//创建新节点
BTNode* NewNode(ElemType x, BTNode *ln, BTNode *rn);//先序构建二叉树
BTNode* PreCreateBT(BTNode *t);//先序遍历
void PreOrder(BTNode*t);
//中序遍历
void MidOrder(BTNode*t);
//后序遍历
void BehOrder(BTNode*t);//清空二叉树
void Clear(BTNode * t);//创建新节点BTNode* NewNode(ElemType x, BTNode *ln, BTNode *rn)
{BTNode *p = (BTNode*)malloc(sizeof(BTNode));p->element = x;p->lChild = ln;p->rChild = rn;
}//先序构建二叉树
BTNode* PreCreateBT(BTNode *t)
{char ch;ch = getchar();if(ch =='#')t = NULL;else{t = (BTNode *)malloc(sizeof(BTNode));t->element = ch;t->lChild = PreCreateBT(t->lChild);t->rChild = PreCreateBT(t->rChild);}return t;
}//先序遍历
void PreOrder(BTNode*t)
{if(!t)return;printf("%c ", t->element);PreOrder(t->lChild);PreOrder(t->rChild);
}//中序遍历
void MidOrder(BTNode*t)
{if(!t)return;MidOrder(t->lChild);printf("%c ", t->element);MidOrder(t->rChild);
}//后序遍历
void BehOrder(BTNode*t)
{if(!t)return;BehOrder(t->lChild);BehOrder(t->rChild); printf("%c ", t->element);
}//清空二叉树
void Clear(BTNode * t)
{if(!t)return;Clear(t->lChild);Clear(t->rChild);free(t);
}int main()
{BTNode *p;p = PreCreateBT(p);printf("\n先序遍历为:");PreOrder(p);printf("\n中序遍历为:");MidOrder(p);printf("\n后序遍历为:");BehOrder(p);printf("\n");Clear(p);system("pause");return 0;
}

采用先序输入,如果子树为空树就用#代替。

小小例子请笑纳:

二叉树的基本操作进阶

#include <stdio.h>
#include <stdlib.h>//二叉树结点结构体typedef  char ElemType;
typedef struct btnode
{ElemType element;struct btnode *lChild;struct btnode *rChild;
}BTNode;//创建新节点
BTNode* NewNode(ElemType x, BTNode *ln, BTNode *rn);//先序构建二叉树
BTNode* PreCreateBT(BTNode *t);//先序遍历
void PreOrder(BTNode*t);
//中序遍历
void MidOrder(BTNode*t);
//后序遍历
void BehOrder(BTNode*t);//清空二叉树
void Clear(BTNode * t);
//求二叉树的结点个数
int Size(BTNode *t);
//求二叉树的高度
int Height(BTNode *t);
//交换二叉树所有左右子树
void Swap(BTNode *t);//创建新节点BTNode* NewNode(ElemType x, BTNode *ln, BTNode *rn)
{BTNode *p = (BTNode*)malloc(sizeof(BTNode));p->element = x;p->lChild = ln;p->rChild = rn;
}//先序构建二叉树
BTNode* PreCreateBT(BTNode *t)
{char ch;ch = getchar();if(ch =='#')t = NULL;else{t = (BTNode *)malloc(sizeof(BTNode));t->element = ch;t->lChild = PreCreateBT(t->lChild);t->rChild = PreCreateBT(t->rChild);}return t;
}//先序遍历
void PreOrder(BTNode*t)
{if(!t)return;printf("%c ", t->element);PreOrder(t->lChild);PreOrder(t->rChild);
}//中序遍历
void MidOrder(BTNode*t)
{if(!t)return;MidOrder(t->lChild);printf("%c ", t->element);MidOrder(t->rChild);
}//后序遍历
void BehOrder(BTNode*t)
{if(!t)return;BehOrder(t->lChild);BehOrder(t->rChild); printf("%c ", t->element);
}//清空二叉树
void Clear(BTNode * t)
{if(!t)return;Clear(t->lChild);Clear(t->rChild);free(t);
}
//求二叉树的结点个数
int Size(BTNode *t)
{if(!t)return 0;return Size(t->lChild) + Size(t->rChild) + 1;
}
//求叶结点的个数
int LeafSize(BTNode *t)
{if(!t)return 0;else if(!(t->lChild) && !(t->rChild))return 1;return LeafSize(t->lChild) + LeafSize(t->rChild);}//求二叉树的高度
int Height(BTNode *t)
{if(!t)return 0;return Height(t->lChild) >= Height(t->rChild) ? Height(t->lChild) +1 : Height(t->rChild) + 1;
}//交换二叉树所有左右子树
void Swap(BTNode *t)
{BTNode *temp;if(!t)return;temp = t->lChild;t->lChild = t->rChild;t->rChild = temp;Swap(t->lChild);Swap(t->rChild);
}
int main()
{BTNode *p;p = PreCreateBT(p);printf("\n先序遍历为:");PreOrder(p);printf("\n中序遍历为:");MidOrder(p);printf("\n后序遍历为:");BehOrder(p);printf("\n二叉树的结点个数为:  %d", Size(p));printf("\n叶结点的个数:    %d", LeafSize(p));printf("\n二叉树的高度为:      %d", Height(p));Swap(p);printf("\n交换后先序遍历为:");PreOrder(p);printf("\n交换后中序遍历为:");MidOrder(p);printf("\n交换后后序遍历为:");BehOrder(p);printf("\n");Clear(p);system("pause");return 0;
}
  • 小小例子,附带二叉树图

哈夫曼编码/译码系统实现

点击查看详解

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>// 统计字符频度的临时结点
typedef struct {unsigned char uch;          // 以8bits为单元的无符号字符unsigned long weight;     // 每类(以二进制编码区分)字符出现频度
} TmpNode;// 哈夫曼树结点
typedef struct {unsigned char uch;              // 以8bits为单元的无符号字符unsigned long weight;         // 每类(以二进制编码区分)字符出现频度char *code;                      // 字符对应的哈夫曼编码(动态分配存储空间)int parent, lchild, rchild;        // 定义双亲和左右孩子
} HufNode, *HufTree;// 选择最小和次小的两个结点,建立哈夫曼树调用
void select(HufNode *huf_tree, unsigned int n, int *s1, int *s2)
{// 找最小unsigned int i;unsigned long min = ULONG_MAX;for(i = 0; i < n; ++i)           if(huf_tree[i].parent == 0 && huf_tree[i].weight < min){min = huf_tree[i].weight;*s1 = i;}huf_tree[*s1].parent=1;   // 标记此结点已被选中// 找次小min=ULONG_MAX;for(i = 0; i < n; ++i)            if(huf_tree[i].parent == 0 && huf_tree[i].weight < min){min = huf_tree[i].weight;*s2 = i;}
} // 建立哈夫曼树
void CreateTree(HufNode *huf_tree, unsigned int char_kinds, unsigned int node_num)
{unsigned int i;int s1, s2;for(i = char_kinds; i < node_num; ++i)  { select(huf_tree, i, &s1, &s2);       // 选择最小的两个结点huf_tree[s1].parent = huf_tree[s2].parent = i; huf_tree[i].lchild = s1; huf_tree[i].rchild = s2; huf_tree[i].weight = huf_tree[s1].weight + huf_tree[s2].weight; }
}// 生成哈夫曼编码
void HufCode(HufNode *huf_tree, unsigned char_kinds)
{unsigned int i;int cur, next, index;char *code_tmp = (char *)malloc(256*sizeof(char));        // 暂存编码,最多256个叶子,编码长度不超多255code_tmp[256-1] = '\0'; for(i = 0; i < char_kinds; ++i) {index = 256-1;  // 编码临时空间索引初始化// 从叶子向根反向遍历求编码for(cur = i, next = huf_tree[i].parent; next != 0; cur = next, next = huf_tree[next].parent)  if(huf_tree[next].lchild == cur) code_tmp[--index] = '0';  // 左‘0’else code_tmp[--index] = '1'; // 右‘1’huf_tree[i].code = (char *)malloc((256-index)*sizeof(char));            // 为第i个字符编码动态分配存储空间 strcpy(huf_tree[i].code, &code_tmp[index]);     // 正向保存编码到树结点相应域中} free(code_tmp);      // 释放编码临时空间
}// 压缩函数
int compress(char *ifname, char *ofname)
{unsigned int i, j;unsigned int char_kinds;     // 字符种类unsigned char char_temp;     // 暂存8bits字符unsigned long file_len = 0;FILE *infile, *outfile;TmpNode node_temp;unsigned int node_num;HufTree huf_tree;char code_buf[256] = "\0";       // 待存编码缓冲区unsigned int code_len;/*** 动态分配256个结点,暂存字符频度,** 统计并拷贝到树结点后立即释放*/TmpNode *tmp_nodes =(TmpNode *)malloc(256*sizeof(TmpNode));        // 初始化暂存结点for(i = 0; i < 256; ++i){tmp_nodes[i].weight = 0;tmp_nodes[i].uch = (unsigned char)i;     // 数组的256个下标与256种字符对应}// 遍历文件,获取字符频度infile = fopen(ifname, "rb");// 判断输入文件是否存在if (infile == NULL)return -1;fread((char *)&char_temp, sizeof(unsigned char), 1, infile);     // 读入一个字符while(!feof(infile)){++tmp_nodes[char_temp].weight;      // 统计下标对应字符的权重,利用数组的随机访问快速统计字符频度++file_len;fread((char *)&char_temp, sizeof(unsigned char), 1, infile);        // 读入一个字符}fclose(infile);// 排序,将频度为零的放最后,剔除for(i = 0; i < 256-1; ++i)           for(j = i+1; j < 256; ++j)if(tmp_nodes[i].weight < tmp_nodes[j].weight){node_temp = tmp_nodes[i];tmp_nodes[i] = tmp_nodes[j];tmp_nodes[j] = node_temp;}// 统计实际的字符种类(出现次数不为0)for(i = 0; i < 256; ++i)if(tmp_nodes[i].weight == 0) break;char_kinds = i;if (char_kinds == 1){outfile = fopen(ofname, "wb");                  // 打开压缩后将生成的文件fwrite((char *)&char_kinds, sizeof(unsigned int), 1, outfile);        // 写入字符种类fwrite((char *)&tmp_nodes[0].uch, sizeof(unsigned char), 1, outfile);      // 写入唯一的字符fwrite((char *)&tmp_nodes[0].weight, sizeof(unsigned long), 1, outfile);      // 写入字符频度,也就是文件长度free(tmp_nodes);fclose(outfile);}else{node_num = 2 * char_kinds - 1;       // 根据字符种类数,计算建立哈夫曼树所需结点数 huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));        // 动态建立哈夫曼树所需结点     // 初始化前char_kinds个结点for(i = 0; i < char_kinds; ++i) { // 将暂存结点的字符和频度拷贝到树结点huf_tree[i].uch = tmp_nodes[i].uch; huf_tree[i].weight = tmp_nodes[i].weight;huf_tree[i].parent = 0; }   free(tmp_nodes); // 释放字符频度统计的暂存区// 初始化后node_num-char_kins个结点for(; i < node_num; ++i) huf_tree[i].parent = 0; CreateTree(huf_tree, char_kinds, node_num);      // 创建哈夫曼树HufCode(huf_tree, char_kinds);     // 生成哈夫曼编码// 写入字符和相应权重,供解压时重建哈夫曼树outfile = fopen(ofname, "wb");                   // 打开压缩后将生成的文件fwrite((char *)&char_kinds, sizeof(unsigned int), 1, outfile);        // 写入字符种类for(i = 0; i < char_kinds; ++i){fwrite((char *)&huf_tree[i].uch, sizeof(unsigned char), 1, outfile);         // 写入字符(已排序,读出后顺序不变)fwrite((char *)&huf_tree[i].weight, sizeof(unsigned long), 1, outfile);        // 写入字符对应权重}// 紧接着字符和权重信息后面写入文件长度和字符编码fwrite((char *)&file_len, sizeof(unsigned long), 1, outfile);     // 写入文件长度infile = fopen(ifname, "rb");       // 以二进制形式打开待压缩的文件fread((char *)&char_temp, sizeof(unsigned char), 1, infile);     // 每次读取8bitswhile(!feof(infile)){// 匹配字符对应编码for(i = 0; i < char_kinds; ++i)if(char_temp == huf_tree[i].uch)strcat(code_buf, huf_tree[i].code);// 以8位(一个字节长度)为处理单元while(strlen(code_buf) >= 8){char_temp = '\0';      // 清空字符暂存空间,改为暂存字符对应编码for(i = 0; i < 8; ++i){char_temp <<= 1;       // 左移一位,为下一个bit腾出位置if(code_buf[i] == '1')char_temp |= 1;        // 当编码为"1",通过或操作符将其添加到字节的最低位}fwrite((char *)&char_temp, sizeof(unsigned char), 1, outfile);        // 将字节对应编码存入文件strcpy(code_buf, code_buf+8);        // 编码缓存去除已处理的前八位}fread((char *)&char_temp, sizeof(unsigned char), 1, infile);     // 每次读取8bits}// 处理最后不足8bits编码code_len = strlen(code_buf);if(code_len > 0){char_temp = '\0';        for(i = 0; i < code_len; ++i){char_temp <<= 1;     if(code_buf[i] == '1')char_temp |= 1;}char_temp <<= 8-code_len;       // 将编码字段从尾部移到字节的高位fwrite((char *)&char_temp, sizeof(unsigned char), 1, outfile);       // 存入最后一个字节}// 关闭文件fclose(infile);fclose(outfile);// 释放内存for(i = 0; i < char_kinds; ++i)free(huf_tree[i].code);free(huf_tree);}
}//compress// 解压函数
int extract(char *ifname, char *ofname)
{unsigned int i;unsigned long file_len;unsigned long writen_len = 0;       // 控制文件写入长度FILE *infile, *outfile;unsigned int char_kinds;      // 存储字符种类unsigned int node_num;HufTree huf_tree;unsigned char code_temp;        // 暂存8bits编码unsigned int root;      // 保存根节点索引,供匹配编码使用infile = fopen(ifname, "rb");       // 以二进制方式打开压缩文件// 判断输入文件是否存在if (infile == NULL)return -1;// 读取压缩文件前端的字符及对应编码,用于重建哈夫曼树fread((char *)&char_kinds, sizeof(unsigned int), 1, infile);     // 读取字符种类数if (char_kinds == 1){fread((char *)&code_temp, sizeof(unsigned char), 1, infile);     // 读取唯一的字符fread((char *)&file_len, sizeof(unsigned long), 1, infile);     // 读取文件长度outfile = fopen(ofname, "wb");                   // 打开压缩后将生成的文件while (file_len--)fwrite((char *)&code_temp, sizeof(unsigned char), 1, outfile);  fclose(infile);fclose(outfile);}else{node_num = 2 * char_kinds - 1;        // 根据字符种类数,计算建立哈夫曼树所需结点数 huf_tree = (HufNode *)malloc(node_num*sizeof(HufNode));        // 动态分配哈夫曼树结点空间// 读取字符及对应权重,存入哈夫曼树节点for(i = 0; i < char_kinds; ++i)     {fread((char *)&huf_tree[i].uch, sizeof(unsigned char), 1, infile);        // 读入字符fread((char *)&huf_tree[i].weight, sizeof(unsigned long), 1, infile);    // 读入字符对应权重huf_tree[i].parent = 0;}// 初始化后node_num-char_kins个结点的parentfor(; i < node_num; ++i) huf_tree[i].parent = 0;CreateTree(huf_tree, char_kinds, node_num);        // 重建哈夫曼树(与压缩时的一致)// 读完字符和权重信息,紧接着读取文件长度和编码,进行解码fread((char *)&file_len, sizeof(unsigned long), 1, infile); // 读入文件长度outfile = fopen(ofname, "wb");      // 打开压缩后将生成的文件root = node_num-1;while(1){fread((char *)&code_temp, sizeof(unsigned char), 1, infile);      // 读取一个字符长度的编码// 处理读取的一个字符长度的编码(通常为8位)for(i = 0; i < 8; ++i){// 由根向下直至叶节点正向匹配编码对应字符if(code_temp & 128)root = huf_tree[root].rchild;elseroot = huf_tree[root].lchild;if(root < char_kinds){fwrite((char *)&huf_tree[root].uch, sizeof(unsigned char), 1, outfile);++writen_len;if (writen_len == file_len) break;       // 控制文件长度,跳出内层循环root = node_num-1;        // 复位为根索引,匹配下一个字符}code_temp <<= 1;      // 将编码缓存的下一位移到最高位,供匹配}if (writen_len == file_len) break;       // 控制文件长度,跳出外层循环}// 关闭文件fclose(infile);fclose(outfile);// 释放内存free(huf_tree);}
}//extract()int main()
{while(1){int opt, flag  = 0;      // 每次进入循环都要初始化flag为0char ifname[256], ofname[256];      // 保存输入输出文件名// 输入所选择操作类型的数字代号:1:压缩,2:解压,3:退出printf("Please input the number of operations:\n 1: compress\n 2: extract\n 3: quit\n");scanf("%d", &opt);if (opt == 3)break;else{printf("Please input the infile name: ");fflush(stdin);     // 清空标准输入流,防止干扰gets函数读取文件名gets(ifname);printf("Please input the outfile name: ");fflush(stdin);gets(ofname);}switch(opt){case 1: printf("Compressing……\n");flag = compress(ifname, ofname); // 压缩,返回值用于判断是否文件名不存在break;      case 2: printf("Extracting……\n");flag = extract(ifname, ofname);     // 解压,返回值用于判断是否文件名不存在break;      }if (flag == -1)printf("Sorry, infile \"%s\" doesn't exist!\n", ifname);     // 如果标志为‘-1’则输入文件不存在elseprintf("Operation is done!\n");       // 操作完成}return 0;
}

二叉树的基本操作及哈夫曼编码/译码系统的实现相关推荐

  1. 哈夫曼编码 译码java_基于Java的哈夫曼编码译码系统_报告毕业论文

    基于Java的哈夫曼编码译码系统_报告毕业论文 1课 程 设 计Java 与面向对象程序设计课程设计基于 Java 的哈夫曼编码译码系统1.问题描述和分工情况1.1 问题描述使用 Java 语言实现哈 ...

  2. 数据结构c语言哈夫曼编码译码系统,数据结构C语言哈夫曼编码译码

    <数据结构C语言哈夫曼编码译码>由会员分享,可在线阅读,更多相关<数据结构C语言哈夫曼编码译码(16页珍藏版)>请在人人文库网上搜索. 1.实训报告题 目: 哈夫曼树编码译码院 ...

  3. 夫曼编码译码系统课程设计实验报告(含源代码c++_c语言),哈夫曼编码译码系统课程设计实验报告(含源代码C++_C语言)[1]...

    目 录 摘 要 ---------------------------..------ II Abstract ----------------------------..---... II 第一章 ...

  4. 哈夫曼编码/译码器:设计一个哈夫曼编码/译码系统,对一个文本文件中的字符进行哈夫曼编码,生成编码文件;反过来,可将一个编码文件译码还原为一个文本文件(.txt)。要求:① 输入一个待压缩的文本文件名

    目录 1.实验题目 2.概要设计 2.1 问题分析 2.2 流程图 2.3 功能模块 3.详

  5. 哈夫曼算法证明+哈夫曼编码译码程序实现

    哈夫曼算法证明 哈夫曼算法是一种贪心算法,我们考虑证明其最优子结构和贪心选择性质: 最优子结构:假设一个树是哈夫曼树,则以其任意节点为根节点的最大子树也是哈夫曼树. 证明:子树的根节点的值是其所有叶子 ...

  6. 树与二叉树转换,森林与二叉树的转换,哈夫曼编码例题详解

    二叉树的前序序列和后序序列正好相反,则该二叉树一定是(B) A.空或只有一个结点 B.高度等于其结点数 C.任一结点无左孩子 D.任一结点无右孩子 2.任何一棵二叉树的叶子结点在前序.中序.后序遍历序 ...

  7. 电文的编码和译码,哈夫曼编码译码(C语言)

    内容: 从键盘接收一串电文字符,输出对应的Huffman(哈夫曼)编码,同时,能翻译由Huffman编码生成的代码串,输出对应的电文字符串.设计要求: (1)构造一棵Huffman树:         ...

  8. 哈夫曼编码译码 C语言,【求助】严蔚敏版数据结构 哈夫曼编码译码

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 #include #include #include typedef char* HuffmanCode;/*动态分配数组,存储哈夫曼编码*/ typed ...

  9. 哈夫曼树与哈夫曼编码:

    定义:带权路径长度WPL最小的二叉树(在编写哈夫曼编码时用到的特殊二叉树) 构造过程: 其实就是每次在权值集合中选两个最小结点的组成新树,然后新树的根节点是二者的权值之和,将刚刚两个从集合中删掉,将新 ...

最新文章

  1. 中科创星米磊:从五个方向筛选“硬科技”企业
  2. webpack4 高手之路 第四天
  3. GridView:根据单元格的值给单元格着色
  4. Hive _函数(系统内置函数、自定义函数、自定义UDF函数)
  5. python每隔几秒执行一次_Python设置程序等待时间
  6. url存在宽字节跨站漏洞_【XSS漏洞】XSS漏洞相关总结v1.0
  7. KVM(五)libvirt 介绍
  8. mysql sum 慢_故障分析 | MySQL 优化案例 - select count(*)
  9. nginx的源码编译及相关文件配置
  10. Linux 网络编程 —— TCP编程之客户端 向服务器发送数据 接收服务器发来的数据
  11. Java用for语法找素数,求1-100的质数,用FOR循环。求救。。
  12. h5调用摄像头扫二维码_你的H5还没有升级到小程序吗
  13. java开发的程序怎么用_java安装后怎么使用?第一次编写java程序
  14. 国培计算机培训奥鹏,3515011349奥鹏国培培训网络研修总结
  15. 介绍一个可以轻松下载病毒样本的数据库
  16. ads pspice 导入_ADS中使用pspice模型
  17. 零基础数学建模学习日记Day1
  18. 中兴新支点操作系统上的快捷键
  19. java启动报错Port already in use: 1099
  20. os.path -- 常用路径操作

热门文章

  1. hash算法的介绍 【清晰易懂】
  2. [LeetCode] Length of Last Word - 最后一个单词的长度
  3. HarmonyOS之数据管理·关系型数据库的应用
  4. OpenGL ES之GLSL实现索引绘制及渲染纹理和颜色混合
  5. 1.1 什么是Hive
  6. Django中如何防范CSRF跨站点请求伪造攻击
  7. 中国大学MOOC 人工智能导论第三章测试
  8. Exhaustive Search Aizu - ALDS1_5_A
  9. GitLab私服搭建及使用实践
  10. 【IT资讯】TIOBE - 2020年6月编程语言排行