数据结构实验三:树的应用(对任意输入的一段英文,为每个字符编制其相应的赫夫曼编码;并利用该编码为任意输入的0、1序列进行解码)

该博客介绍了如何使用赫夫曼树为任意英文字符编制编码,并进行0、1序列的解码。实验涉及字符频度统计、赫夫曼树构建、编码与解码算法设计。主要内容包括字符串整合、赫夫曼树最小权值结点选择以及赫夫曼编码生成。
摘要由CSDN通过智能技术生成

前言:

实验三是针对图的应用,这里主要的是赫夫曼树的简单构建和编码解码过程,相信只要了解了具体的编码细节,那么解码过程便迎刃而解,这里的赫夫曼树构建主要是依据用户输入的字符串序列,以字符串中各个字符的频度为基准建立赫夫曼树,实验具体过程,包括数据结构定义,抽象数据结构,各部分核心算法设计如下,源码附在最后,建议大致浏览后再看源码喔。

实验三:树的应用

问题描述

对任意输入的一段英文,为每个字符编制其相应的赫夫曼编码;并利用该编码为任意输入的0、1序列进行解码.

基本要求

一个完整的系统应具有以下功能:
(1)初始化 从终端读入一段英文字符,统计每个字符出现的频率,建立赫夫曼树,并将该树存入某文件;
(2)编码 利用建好的赫夫曼树对各字符进行编码,用列表的形式显示在屏幕上,并将编码结果存入另一文件中;
(3)解码 利用保存的赫夫曼编码,对任意输入的0,1序列能正确解码;

实验基本原理与设计

1.数据结构的设计

1):依据实验要求构造相关结构体

//赫夫曼树结点
typedef struct HUffMANTREE {
   
	int weight;//权值
	int parent, lchild, rchild;//双亲左右孩子
	char CH;
}HTNode, * Tree;//赫夫曼树
//赫夫曼编码指针向量
typedef char** HuffmanCode;

//权值种类结点
typedef struct NUMBERNODE {
   
	int ww;//整合过程中作为标识,0则未整合,1表示已整合,>1值表示数据重复次数,即为频度,权值
	char cc;
	NUMBERNODE* next;
}NNode, * Num;
//整合过程权值指针向量
typedef NNode** NumberWeight;

2):抽象数据类型描述(ADT)

ADT Huffman{
   

数据对象:D={
   HT[i]| HT[i]∈HTNode,i=123,n,n≥0}

数据关系:R1={
   < HT[i-1], HT[i]>| HT[i-1], HT[i]∈D,i=123,n,n≥0}

基本操作:

	InitHffman(HuffmanTree &HT, NUMBER w, int n)

初始条件:权值w,字符种类数n已整合

操作结果:以w中所给权值,2*n-1个赫夫曼节点个数初始化赫夫曼树HT

	Status CreatHuffman(HuffmanTree&HT,HuffmanCode& HC, int n)

初始条件:赫夫曼树已初始化,字符种类数已知

操作结果:由初始化的赫夫曼树构造完整赫夫曼树,对每个字符赫夫曼编码,并将最后结果保存至指定文件

	printHT(HuffmanTree HT,int n)

初始条件:赫夫曼树已存在

操作结果:打印赫夫曼树

	printHC(HuffmanCode HC, HuffmanTree HT,int n)

初始条件:赫夫曼树赫夫曼编码已存在

操作结果:打印赫夫曼编码

	Decode(HuffmanTree &HT,int n)

初始条件:赫夫曼树解码

操作结果:对输入的以2结尾的01序列根据已知的赫夫曼编码解码

}ADT Huffman

2.核心算法设计

(1):字符串整合函数

Status MangeStr(char str, Num w)**

功能简介:

此函数用于对用户输入的一系列字符str进行整合,将整合结果以结构体数组形式储存(Num *w),其中w作为这个结构体数组的指针向量,函数返回整合后字符串中字符的种类个数。

参数

  • str:输入字符串
  • w: 权值结点向量

实现

  • 进入函数,首先以str字符串中每个字符作为元素,生成一个NNode结构体类型的链表(Num head),其中ww字段均置为0以表示此字符未整合。

  • 然后以指向此链表的Num cur游标作为while循环条件,如果ww值为0则表示此字符未被整合,为w指针向量分配内存,储存相关信息,并将此时游标cur指向ww值置为1表示已整合

  • 而后另设一游标p从cur->next开始遍历当前链表(可以预见cur之前的字符均被整合过),若其中含有与此时w储存字符相同且其ww值为0(未整合)则w权值+1,且将此时p游标指向元素ww值置为1,得到当前w表示的字符的所有整合

  • 如此往复直至cur指向NULL(即整合结束),便得到整合后的所需内容,返回退出循环时指针向量的下标j即为字符种类个数

  • 另由于整合过程中head链表涉及到对于堆内存的分配且之后程序不再使用此链表,所以在函数结束时利用Destroy函数释放内存

(2):赫夫曼树寻找最小无双亲两权值下标

void Select(HuffmanTree& HT, int range, int& s1, int& s2)

功能简介:

在已有且初始化后的赫夫曼树中,以参数值range为范围(1-range)在赫夫曼树HT中寻找两个最小权值无双亲结点下标,并由s1,s2分别储存其下标。

参数

  • HT:待搜索赫夫曼树
  • range:搜索范围
  • s1:储存搜索结果1
  • s2:储存搜索结果2

实现

  • 以赫夫曼树HT中的权值为依据,用一个for循环为数组save赋值(为契合赫夫曼树的储存,同样采取0号单元舍弃不用),其中为save赋值的元素需满足双亲为0

  • 然后利用选择排序法将数组save中按权值升序排列,此时得到的save[1],和save[2]即为此时(1-range)范围内最小两权值

  • 再次利用一个for循环结合break语句,分别寻找符合这两个权值条件的对应赫夫曼树中的元素,并将其下标赋值给相应的s1,s2,其中寻找s2的for循环还需满足此时的下标不等于已经赋值的s1

(3):赫夫曼编码

功能简介:

赫夫曼编码部分实现于函数Status CreatHuffman(Tree& HT, HuffmanCode& HC, int n)内部,是此函数的一个子过程,依据当前构建好的赫夫曼树来对每个字符进行编码,也可以将它单独提出来作为一个函数,不冲突

实现原理

  • 每个字符在构建好的赫夫曼树中是一个叶子节点,从叶子节点开始,每次寻找其父节点,识别其是左节点还是右节点(左为0,右为1),记录01数据作为路径,知道父节点为0,即到达根节点,完成编码
  • 用cd字符数组存储编码,n种字符构成的赫夫曼树,编码长度不超过n-1,为了匹配这样的从叶子结点的回溯过程,从cd数组末尾开始填充路径,用site标识当前哈夫曼编码的开始位置,一条编码完毕后,为赫夫曼编码指针向量分配相应编码大小内存,并利用strcpy字符串复制函数,从site位置开始赋值
  • 赫夫曼解码过程便可参照编码过程,解码即为编码的逆过程,详见源码void Decode(Tree& HT, int n)函数

此部分源码如下:

//赫夫曼编码
HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));//赫夫曼编码头指针向量,0号单元未用
cd = (char*)malloc(n * sizeof(char));//编码长度最长为n-1,最后一位作为结束标识
cd[n - 1] = '\0';
for (i = 1; i <= n; i++)//共有n个字符,对应n串编码
{
   
	site = n - 1;
	c = i, f = HT[i].parent;
	for (; f != 0; c = f, f = HT[f].parent)
		if (HT[f].lchild == c)
			cd[--site] = '0';
		else
			cd[--site] = '1';
	HC[i] = (char*)malloc((n - site) * sizeof(char));//为字符的赫夫曼编码分配空间
	strcpy(HC[i], &cd[site]);//从site位置开始复制到HC[i]
}

源码

//实现对二叉树的一个指定操作或用二叉树解决实际问题
//问题描述,对任意输入的一段英文,为每个字符编制其相应的哈夫曼编码
//并利用该编码为任意输入的0,1序列进行解码
#define _CRT_SECURE_NO_WARNINGS
#include<
  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值