数据结构 | 第六章 树

一、树

1、树的基本概念
1.1 树的定义

出一个或多个(n≥0)结点组成的有限集合T ,有且仅有一个结点称为根(root),当n>1
时,其余的结点分为m(m>=0)个互不相交的有限集合T1,T2,... Tm。每个集合本身
又是棵,被称作这个根的子树

1.2 结构特点
  • 非线性结构, 有一个直接前驱,但可能有多个直接后继
  • 树的定义具有递归性,树中还有树;
  • 树可以为空,即节点个数为0
1.3 常见术语
  • 根:结点,没有前驱;
  • 叶子:终端结点,没有后继;
  • 森林:指删除根后的所有的子树的集合;
  • 有序树:从左往右不能互换,左为第一;
  • 无序树:子树各结点可互换;
  • 双亲:直接前驱parent
  • 孩子:直接后继child
  • 兄弟:同一双亲下的同层结点sibling
  • 堂兄弟:不为同一个双亲,但双亲位于同一个结点cousin
  • 祖先:根结点;
  • 子孙:即该下层子树中的任意结点;
  • 结点:树的数据元素;
  • 结点的度:结点挂接的子树数(度等于直接后继个数);
  • 结点的层次:从根到该结点的层数(根我第一层);
  • 终端结点:度为0的结点(叶子);
  • 分支结点:除树根以外的结点(内部结点);
  • 树的度:所有结点度中的最大值;
  • 树的深度:所有结点中最大的层数;
2、树的表示法
2.1 图形表示法

在这里插入图片描述

2.2 广义表示法

使用括号进行嵌套:

  • A(B(E),C(F(I,G)))
2.3 左孩子右兄弟表示法

在这里插入图片描述

转变成左孩子右兄弟=>

在这里插入图片描述

二、二叉树

1、基本概念
1.1 定义

n ( n≥0 )个结点的有限集合,由一个根结点以及两棵互不相交的、分别称为左子树和
右子树的二叉树组成。

1.2 基本特征
  • 每个结点最多俩颗树
  • 左孩子和右子树次序不能颠倒的有序树
1.3 各个形态

在这里插入图片描述

  • (a):左、右子树非空;
  • (b):右子树为空;
  • (c):左子树非空;
  • (d):只有一个根结点;
  • (e):空二叉树。
1.4 二叉树性质
  • 在二叉树的第i层(深度)上至多右2^i-1个结点;
  • 对任意二叉树T,若叶子结点数为n0,度为2的节点数为n2,则有n0=n2+1
  • 满二叉树:每一层的结点都是的;

在这里插入图片描述

  • 完全二叉树:除了最后一层其他都是满的;

在这里插入图片描述

  • 具有n个结点的完全二叉树的深度为

在这里插入图片描述

  • 若一颗有n个结点的完全二叉树的结点,每层从左往右:
    • i=1,结点i是根结点,无双亲,若i>1,则其双亲结点是结点i/2
    • 2i>n,则结点i无左孩子,该结点为叶子结点;否则其左孩子是结点2i
    • 2i+1>n,则结点i无右孩子,该结点为叶子结点;否则其右孩子是结点2i+1
2、顺序存储

将根结点编为1,在一次从上往下从左往右依次编号。若该结点不存在,则该编号跳过。

  • 若为左孩子,则编号为2i
  • 若为右孩子,则编号为2i+1

在这里插入图片描述

由此可见,该存储结构会造成大量的空间浪费

3、链式存储

该链表的结点分为三个域:

  • 左指针域;
  • 数据域;
  • 右指针域;

在这里插入图片描述

该结构便于查找左右结点,以及查找双亲结点【可以在以上的基础上添加一个双亲指针域】,缺点在于会增加存储空间的开销。

三、遍历二叉树

1、基本概念

按某种顺序访问二叉树中的所有结点【不重复】,使得遍历的结点成了序列之间有一对一的关系。

  • 用途:是插入、删除、修改、排序的前提,是二叉树一切运算的基础和核心。
  • 二叉树中,只需遍历根节点(D)左子树(L)右子树(R)即可遍历一颗二叉树。
  • 遍历方法:(DLR)、(LDR)、(LRD)、(DRL)、(RDL)、(RLD)
  • 若限定先左后右:DLRKDRLRD
    • DLR:先序遍历,先根再左再右;
    • LDR:中序遍历,先左再根再右;
    • LRD:后序遍历,先左再右再根;
  • 注意:先、中、后】意思是访问结点D是先于子树还是后于子树。对于递归来看三种算法是相同的,或者说三种遍历的访问路径相同,只是访问结点时机不同。

例:

在这里插入图片描述

  • 先序遍历:ABCDEFGH
  • 中序遍历:BDCEAFHG
  • 后序遍历:DECBHGFA
    使用方法:先看成一个整体的树,在按顺序一直衍生,直到该树衍生不下去,在切换。
1.1 代码实现
#include<stdio.h>
#include<stdlib.h>


typedef struct treeNode
{
	char data;
	struct treeNode* lchild;
	struct treeNode* rchild;
}TreeNode;

// 先根再左再右
void DLR(TreeNode *root)
{
	if (root == NULL)
	{
		return;
	}

	printf("%2c", root->data);
	DLR(root->lchild);
	DLR(root->rchild);
}

// 先左再根再右
void LDR(TreeNode* root)
{
	if (root == NULL)
	{
		return;
	}

	LDR(root->lchild);
	printf("%2c", root->data);
	LDR(root->rchild);
}

// 先左再右再根
void LRD(TreeNode* root)
{
	if (root == NULL)
	{
		return;
	}

	LRD(root->lchild);
	LRD(root->rchild);
	printf("%2c", root->data);
}


int main()
{
	// 创建各个结点
	TreeNode nodeA = { 'A', NULL, NULL };
	TreeNode nodeB = { 'B', NULL, NULL };
	TreeNode nodeC = { 'C', NULL, NULL };
	TreeNode nodeD = { 'D', NULL, NULL };
	TreeNode nodeE = { 'E', NULL, NULL };
	TreeNode nodeF = { 'F', NULL, NULL };
	TreeNode nodeG = { 'G', NULL, NULL };
	TreeNode nodeH = { 'H', NULL, NULL };

	// 将各个结点指向
	nodeA.lchild = &nodeB;
	nodeA.rchild = &nodeF;
	nodeB.rchild = &nodeC;
	nodeC.lchild = &nodeD;
	nodeC.rchild = &nodeE;
	nodeF.rchild = &nodeG;
	nodeG.lchild = &nodeH;

	printf("\nDLR\n");
	DLR(&nodeA);
	printf("\nLDR\n");
	LDR(&nodeA);
	printf("\nLRD\n");
	LRD(&nodeA);

	return 0;
}

在这里插入图片描述

2、二叉树的其他操作
2.1 深度的计算

/*
	* 二叉树求叶子结点数
*/
#include<stdio.h>

int num=0;

void get_LeafNum(TreeNode *root)
{

	if (root == NULL)
		return;

	if (root->rchild == NULL && root->lchild == NULL)// 当该结点的左右子树都为空时为叶子结点
		num++;

	get_LeafNum(root->lchild);
	get_LeafNum(root->rchild);
}

int main()
{
	TreeNode nodeA = { 'A', NULL, NULL };
	TreeNode nodeB = { 'B', NULL, NULL };
	TreeNode nodeC = { 'C', NULL, NULL };
	TreeNode nodeD = { 'D', NULL, NULL };
	TreeNode nodeE = { 'E', NULL, NULL };
	TreeNode nodeF = { 'F', NULL, NULL };
	TreeNode nodeG = { 'G', NULL, NULL };
	TreeNode nodeH = { 'H', NULL, NULL };

	nodeA.lchild = &nodeB;
	nodeA.rchild = &nodeF;
	nodeB.rchild = &nodeC;
	nodeC.lchild = &nodeD;
	nodeC.rchild = &nodeE;
	nodeF.rchild = &nodeG;
	nodeG.lchild = &nodeH;
	
	get_LeafNum(&nodeA);
	printf("叶子结点数:%d", num);

	return 0;
}
2.2 计算高度
#include<stdio.h>

int get_High(TreeNode *root)
{
	if (root == NULL)
	{
		return NULL;
	}
	int l = get_High(root->lchild);	
	int r = get_High(root->rchild);

	int h = l > r ? l + 1: r + 1;// 递归到最后一个结点再往回计算

	return h;
}

int main()
{
	TreeNode nodeA = { 'A', NULL, NULL };
	TreeNode nodeB = { 'B', NULL, NULL };
	TreeNode nodeC = { 'C', NULL, NULL };
	TreeNode nodeD = { 'D', NULL, NULL };
	TreeNode nodeE = { 'E', NULL, NULL };
	TreeNode nodeF = { 'F', NULL, NULL };
	TreeNode nodeG = { 'G', NULL, NULL };
	TreeNode nodeH = { 'H', NULL, NULL };

	nodeA.lchild = &nodeB;
	nodeA.rchild = &nodeF;
	nodeB.rchild = &nodeC;
	nodeC.lchild = &nodeD;
	nodeC.rchild = &nodeE;
	nodeF.rchild = &nodeG;
	nodeG.lchild = &nodeH;

	int h = get_High(&nodeA);
	printf("深度:%d\n", h);
	return 0;
}

在这里插入图片描述

2.3 二叉树的复制
/*
	* 遍历二叉树:先根再左再右
*/
void DLR(TreeNode *root)
{
	if (root == NULL)
	{
		return;
	}

	printf("%2c", root->data);
	DLR(root->lchild);
	DLR(root->rchild);
}


/*
	* 二叉树的复制
*/
TreeNode* copyTree(TreeNode* root)
{
	if (NULL == root)
		return NULL;

	TreeNode* lrchid = copyTree(root->lchild);
	TreeNode* rchild = copyTree(root->rchild);

	TreeNode *newNode = (TreeNode *)malloc(sizeof(TreeNode*)*10);
	newNode->lchild = lrchid;
	newNode->rchild = rchild;
	newNode->data = root->data;

	return newNode;
}


int main()
{
	TreeNode nodeA = { 'A', NULL, NULL };
	TreeNode nodeB = { 'B', NULL, NULL };
	TreeNode nodeC = { 'C', NULL, NULL };
	TreeNode nodeD = { 'D', NULL, NULL };
	TreeNode nodeE = { 'E', NULL, NULL };
	TreeNode nodeF = { 'F', NULL, NULL };
	TreeNode nodeG = { 'G', NULL, NULL };
	TreeNode nodeH = { 'H', NULL, NULL };

	nodeA.lchild = &nodeB;
	nodeA.rchild = &nodeF;
	nodeB.rchild = &nodeC;
	nodeC.lchild = &nodeD;
	nodeC.rchild = &nodeE;
	nodeF.rchild = &nodeG;
	nodeG.lchild = &nodeH;

	TreeNode *root =  copyTree(&nodeA);
	printf("复制前:\n");
	DLR(&nodeA);
	printf("\n复制后:\n");
	DLR(root);
	return 0;
}

在这里插入图片描述

2.4 二叉树遍历

若不适用递归遍历二叉树,则需要借助

main.c

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include "stackList.h"
#include "treeNode.h"

int main()
{
	TreeNode node = Create_Tree();	// 创建树

	ForeachTree(&node);	// 将树排序
	return 0;
}

stackList.c

#include "stackList.h"

/*
	功能:初始化栈
*/
SeqStack* Init_SeqStack()
{
	SeqStack* stack = (SeqStack*)malloc(sizeof(SeqStack*)*MAXLEN);

	if (stack == NULL)
		return NULL;

	memset(stack, 0, sizeof(SeqStack*)*MAXLEN);
	stack->size = -1;

	return stack;
}

/*
	功能:判断栈空
	返回值:
		· NULL:该栈不存在;
		· 0:为空栈;
		· 1:不为空。
*/
int Judge_SeqStackNull(SeqStack* Stack)
{
	if (Stack == NULL)
		return NULL;

	if (Stack->size == -1)
		return 0;

	return 1;
}
/*
	功能:判断栈满
	返回值:
		· NULL:该栈不存在;
		· 0:为满栈;
		· 1:栈不为满栈。
*/
int Judge_SeqStackFull(SeqStack* Stack)
{
	if (Stack == NULL)
		return NULL;

	if (Stack->size == MAXLEN - 1)
		return 1;

	return 0;
}

/*
	功能:进栈
*/
void Push_SeqStack(SeqStack* Stack, void* data)
{
	if (Judge_SeqStackFull(Stack))
	{
		printf("满栈,不能进栈!");
		return;
	}
	Stack->size++;
	Stack->data[Stack->size] = data;

}

/*
	功能:出栈
*/
void Pop_SeqStack(SeqStack* Stack)
{
	if (Stack == NULL)
		return;

	if (!Judge_SeqStackNull(Stack))
	{
		printf("空栈,不能出栈!");
		return;
	}

	Stack->data[Stack->size] = NULL;
	Stack->size--;
}

/*
	功能:去栈顶
*/
void* Get_SeqStack(SeqStack* Stack)
{

	if (Stack == NULL)
		return NULL;

	if (Stack->size == -1)
		return NULL;

	void* x = Stack->data[Stack->size];
	
	return x;
}

/*
	功能:显示函数
*/
void Display(SeqStack* Stack)
{
	int i;
	for (i = 0; i < Stack->size+1; i++)
	{
		printf("%5d", *(int *)Stack->data[i]);
	}

	printf("\n");
}

/*
	功能:释放空间
*/
void Destroy_SeqStack(SeqStack *Stack)
{
	if (Stack != NULL)
	{
		free(Stack);
	}
}

treeForeach.c

#include "stackList.h"
#include "treeNode.h"


/*
	* 创建树
*/
TreeNode Create_Tree()
{
	TreeNode nodeA = { 'A', NULL, NULL };
	TreeNode nodeB = { 'B', NULL, NULL };
	TreeNode nodeC = { 'C', NULL, NULL };
	TreeNode nodeD = { 'D', NULL, NULL };
	TreeNode nodeE = { 'E', NULL, NULL };
	TreeNode nodeF = { 'F', NULL, NULL };
	TreeNode nodeG = { 'G', NULL, NULL };
	TreeNode nodeH = { 'H', NULL, NULL };

	nodeA.lchild = &nodeB;
	nodeA.rchild = &nodeF;
	nodeB.rchild = &nodeC;
	nodeC.lchild = &nodeD;
	nodeC.rchild = &nodeE;
	nodeF.rchild = &nodeG;
	nodeG.lchild = &nodeH;

	return nodeA;
}

/*
	* 创建新结点,赋标志
*/
Info* Create_Info(TreeNode* root, bool flag)
{
	Info* info = (Info*)malloc(sizeof(Info*) * 10);
	info->flag = flag;
	info->node = root;

	return info;
}


/*
	* 遍历排序二叉树
*/
void ForeachTree(TreeNode* root)
{
	SeqStack* stack = Init_SeqStack();// 初始化栈
	Push_SeqStack(stack, Create_Info(root, false));// 入栈

	while (stack->size >= 0)
	{

		Info* info = (Info*)Get_SeqStack(stack);// 获取栈顶元素
		Pop_SeqStack(stack);// 出栈

		if (info->flag)// 判断标志,true则打印,flase则继续执行
		{
			printf("%3c", info->node->data);
			free(info); // 当打印后,后续就不需要用到此结点,所以将其释放
			continue; // 后续不再有其他结点,则直接跳回循环
		}
		// 右结点入栈
		if (info->node->rchild != NULL)
		{
			Push_SeqStack(stack, Create_Info(info->node->rchild, false));
		}

		// 左结点入栈
		if (info->node->lchild != NULL)
		{
			Push_SeqStack(stack, Create_Info(info->node->lchild, false));
		}

		// 根节点入栈
		info->flag = true;
		Push_SeqStack(stack, info);
	}
}

/*
	* 先根再左再右
	* 由于栈的先进后出则进栈顺序与正常的二叉树排序相反
*/
void DLR(SeqStack* stack, Info* info)
{
	// 右结点入栈
	if (info->node->rchild != NULL)
	{
		Push_SeqStack(stack, Create_Info(info->node->rchild, false));
	}

	// 左结点入栈
	if (info->node->lchild != NULL)
	{
		Push_SeqStack(stack, Create_Info(info->node->lchild, false));
	}

	// 根节点入栈
	info->flag = true;
	Push_SeqStack(stack, info);
}

/*
	* 先左再根再右
*/
void LDR(SeqStack* stack, Info* info)
{
	// 右结点入栈
	if (info->node->rchild != NULL)
	{
		Push_SeqStack(stack, Create_Info(info->node->rchild, false));
	}

	// 根节点入栈
	info->flag = true;
	Push_SeqStack(stack, info);

	// 左结点入栈
	if (info->node->lchild != NULL)
	{
		Push_SeqStack(stack, Create_Info(info->node->lchild, false));
	}


}

/*
	* 先左再右在根
*/
void LRD(SeqStack* stack, Info* info)
{
	// 根节点入栈
	info->flag = true;
	Push_SeqStack(stack, info);

	// 右结点入栈
	if (info->node->rchild != NULL)
	{
		Push_SeqStack(stack, Create_Info(info->node->rchild, false));
	}

	// 左结点入栈
	if (info->node->lchild != NULL)
	{
		Push_SeqStack(stack, Create_Info(info->node->lchild, false));
	}
}

stackList.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#ifdef __cplusplus
extern "C" {
#endif 

#define MAXLEN 1024

	typedef struct SeqStack
	{
		void* data[MAXLEN];	// 存储数据
		int size;		// 存储数据个数
	}SeqStack;
	// 初始化栈
	SeqStack* Init_SeqStack();
	// 判断栈空
	int Judge_SeqStackNull(SeqStack*);
	// 判断栈满
	int Judge_SeqStackFull(SeqStack*);
	// 进栈
	void Push_SeqStack(SeqStack*, void*);
	// 出栈
	void Pop_SeqStack(SeqStack*);
	// 取栈顶
	void* Get_SeqStack(SeqStack*);
	// 打印栈
	void Display(SeqStack*);
	// 销毁释放内存
	void Destroy_SeqStack(SeqStack*);
#ifdef __cplusplus
}
#endif 

treeNode.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include "stackList.h"

// 树的结点
typedef struct treeNode
{
	char data;
	struct treeNode* lchild;
	struct treeNode* rchild;
}TreeNode;

// 将树拓展,给每个结点赋标记
typedef struct
{
	TreeNode* node;
	bool flag;
}Info;

#ifdef __cplusplus
extern "C" {
#endif 

	// 创建树
	TreeNode Create_Tree();

	// 创建新结点,赋标志
	Info* Create_Info(TreeNode*, bool);

	// 遍历排序二叉树
	void ForeachTree(TreeNode*);

	// 先根再左再右 
	void DLR(SeqStack*, TreeNode*);

	// 先左再根再右
	void LDR(SeqStack*, TreeNode*);

	// 先左再右在根
	void LRD(SeqStack*, TreeNode*);

#ifdef __cplusplus
}
#endif 
4、树和森林与二叉树的转换
4.1 树的存储结构

双亲表示法

使用结构体数组:

  • 数据域用来保存数据
  • 结点存储双亲的数组下标

优缺点:查找双亲和祖先容易,但查找孩子结点或兄弟结点较为繁琐。

孩子链表示法

将每个结点的孩子结点构成一个单链表;

  • 顺序表:存储该结点的数据值以及该结点第一个孩子的地址
  • 孩子结点:存放该孩子结点再顺序表的位置以及存放下一个孩子的地址

优缺点:找到某个孩子结点容易,找结点的双亲困难

孩子兄弟法

是一种二叉链表。

  • 数据域:存放结点的数据
  • 指针1:指向最左边的第一个孩子;
  • 指针2:指向下一个兄弟结点。
4.2 树和森林转换为二叉树

在实际应用中,一般先将树结构转换为二叉树,再以二叉树的方式存储。

树转换成二叉树

加线:树种所有相邻的兄弟都连上线;

抹线:对树中的每个结点,只保留它与左边第一个孩子结点之间的连线,删除它与其他孩子结点之间的连线;

旋转:以树的根结点为轴心,将整棵树时针旋转45°

例:

在这里插入图片描述

加线

在这里插入图片描述

抹线

在这里插入图片描述

4.3 森林转换为二叉树

当用树转化成的二叉树的根节点没有右子树。

方法:

  • 将森林中的每一棵树转换成相应的二叉树;
  • 第一颗二叉树保持不动,从第二课二叉树开始,依次把后一颗二叉树作为前一棵二叉树根节点的右子树,直到把最后一棵二叉树作为前一棵二叉树的右子树为止。

例:该图为森林

在这里插入图片描述

相邻兄弟相连

在这里插入图片描述

删除与双亲结点的连线

在这里插入图片描述

每棵树转换成二叉树

在这里插入图片描述

所有二叉树转化成一棵树

在这里插入图片描述

4.4 二叉树还原树

若该二叉树能还原成一棵树,则该二叉树一定满足:

  • 根节点无右子树

二叉树还原过程:

  • 加线:若某结点的左孩子有右子树,在该结点和其左孩子的右子树的右分支上个结点之间加线;
  • 抹线:抹掉各结点的右子树的右分支与上面结点的连线;
  • 旋转:将树旋转。

例:

在这里插入图片描述

连线

在这里插入图片描述

加连线

在这里插入图片描述

删除与右孩子的连线

在这里插入图片描述

还原树

在这里插入图片描述

4.5 二叉树还原森林

二叉树的还原方法,即将上面的方法还原回来即可。

5、哈夫曼树【最优树】
5.1 基本概念
  • 是一种特殊的二叉树,树的所有的叶子结点都是有权值,从而构造出带权值路径长度最短的二叉树。
    路径:树种一个结点另一个结点之间的分支构成这俩个结点之间的路径。【注】:兄弟结点之间无路径;
    路径长度:树中路径上的分支数目
    树的路径长度:根结点到树种每个结点的路径长度之和
    叶子结点的权值人为给每个叶子结点赋值
    叶子结点的带权路径长度:从树到该叶子结点之间的路径长度与该结点的权值乘积
    树的带权路径长度:树种所有叶子结点的权值乘以该结点的路径长度之和。【WPL=k=1Σ到n*Wk*Lk
    Wk:第k个的叶子结点取值;
    Lk:从根到第k个叶子结点的路径长度。
5.2 构造方法
  • 权值为一个列表,取出最小的,生成新的权值要添入。
  • 从前往后选择小的。

例:

在这里插入图片描述

5.3 哈夫曼编码

用于构造使电文的编码总长最短的编码方案。

  • 左为0,右为1,
  • 编码从上往下。

例如:上图中4的结点编码为:100

代码演示

main.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include"HuffmanTree.h"


int main()
{
	HT HT;
	int n;
	printf("\n请输入共有多少个权值:");
	scanf("%d", &n);
	CreatHFMT(HT, n);
	ShowHFMT(HT, n);
	Get_HFMTnode(HT, n);
	return 0;
}

HuffmanTree.c

#include"HuffmanTree.h"

// 初始化
void Init_HFMT(HT T, int n)
{
	int i;

	for (i = 0; i < 2 * n - 1; i++)
	{
		T[i].weight = 0;
		T[i].lchild = -1;
		T[i].rchild = -1;
		T[i].parent = -1;
	}
}

// 输入权值
void InputWight(HT T, int n)
{
	int w, i;
	for (i = 0; i < n; i++)
	{
		printf("请输入第%d个权值:", i + 1);
		scanf("%d", &w);
		getchar();
		T[i].weight = w;
	}
}

// 选择最小结点
void SelectMin(HT T, int i, int *p1, int *p2)
{
	long min1 = 888888, min2 = 888888;
	int j;
	for (j = 0; j <= i; j++)
	{
		if (T[j].parent == -1)
		{
			if (min1 > T[j].weight && j!=*p1)
			{
				min2 = T[j].weight;
				*p2 = j;
			}
		}
	}
}

// 创建哈夫曼树
void CreatHFMT(HT T, int n)
{
	int i, p1, p2;

	Init_HFMT(T, n);
	InputWight(T, n);
	for (i = n; i < 2 * n - 1; i++)
	{
		SelectMin(T, i - 1, &p1, &p2);
		T[p1].parent = T[p2].parent = i;
		T[i].lchild = T[p1].weight;
		T[i].rchild = T[p2].weight;
		T[i].weight = T[p1].weight + T[p2].weight;
	}
}

// 输出向量状态表
void ShowHFMT(HT T, int n)
{
	int i;
	printf("\n哈夫曼树的各边显示:");
	for (i = 0; i < 2 * n - 1; i++)
		while (T[i].lchild != -1)
		{
			printf("(%d, %d),(%d, %d)\n", T[i].weight, T[i].lchild, T[i].weight, T[i].rchild);
			break;
		}
}

// 哈夫曼编码
void HFnode(HT T, int i, int j)
{
	j = T[i].parent;
	if (T[j].rchild == T[i].weight)
		printf("l");
	else
	{
		printf("0");
	}

	if (T[j].parent != -1)
	{
		i = j;
		HFnode(T, i, j);
	}
}

// 获取编码
void Get_HFMTnode(HT T, int n)
{
	int i, j, a;
	printf("\n输入的权值的对应哈夫曼编码:");
	for (i = 0; i < n; i++)
	{
		j = 0;
		a = i;
		printf("\n%id编码为:", T[i].weight);
		HFnode(T, i, j);
		i = a;
	}
}

HuffmanTree.h

#pragma once

#include<stdio.h>
#include<stdlib.h>

#define MAXLEN 100

typedef struct
{
	int weight;
	int lchild, rchild, parent;
}HTnode;

typedef HTnode HT[MAXLEN];


#ifdef __cplusplus
extern "C" {
#endif 

	// 初始化
	void Init_HFMT(HT, int);

	// 输入权值
	void InputWight(HT, int);

	// 选择最小结点
	void SelectMin(HT, int, int, int);

	// 创建哈夫曼树
	void CreatHFMT(HT, int);

	// 输出向量状态表
	void ShowHFMT(HT, int n);

	// 哈夫曼编码
	void HFnode(HT, int, int);

	// 获取编码
	void Get_HFMTnode(HT, int);

#ifdef __cplusplus
}
#endif 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值