【数据结构】树、二叉树和森林互相转换、哈夫曼树、二叉树遍历强化

补充知识点:线索二叉树

一、树、二叉树和森林互相转换

1.1 树转二叉树

树中每个结点最多只有一个最左边的孩子(长子)和一个右邻的兄弟。按照这种关系很自然地就能将树转换成相应的二叉树:1.在所有兄弟结点之间加一连线2.对每个结点,除了保留与其长子的连线外,去掉该结点与其它孩子的连线。

也就是说,在转换成二叉树之后,除了根结点的每一个结点的右孩子时该结点的兄弟,左孩子是该结点的长子。

如下图所示:
树兄弟加线
给除长子外的孩子去线层次调整

1.2 二叉树转树

是树转换为二叉树的逆过程。
1.加线。若某结点X的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的右孩子结点、右孩子的右孩子的右孩子结点…,都作为结点X的孩子。将结点X与这些右孩子结点用线连接起来。
2.去线。删除原二叉树中所有结点与其右孩子结点的连线。

如下图所示:
二叉树加线去线在这里插入图片描述

1.3 森林转二叉树

具体的方法是:
1.将森林中的每棵树变为二叉树;
2.因为转换所得的二叉树的根结点的右子树均为空,故可将各二叉树的根结点视为兄弟从左至右连在一起,就形成了一棵二叉树。

也就是说,根结点的右孩子是一棵树,左孩子是长子,长子的右孩子是兄弟,长子的左孩子是孩子。

如下图所示:
拥有三颗树的森林在这里插入图片描述在这里插入图片描述

1.4 森林转二叉树

具体的方法是:
1.将森林中的每棵树变为二叉树;
2.因为转换所得的二叉树的根结点的右子树均为空,故可将各二叉树的根结点视为兄弟从左至右连在一起,就形成了一棵二叉树。

如下图所示:

拥有三棵树的森林森林中每颗树转换为二叉树在这里插入图片描述

二、 哈夫曼树

哈夫曼树是一种带权(W)路径(P)长度(L)最短的二叉树,也称为最优二叉树。

2.1 创建哈夫曼树

1,将所有左,右子树都为空的作为根节点。
2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。
3,从森林中删除这两棵树,同时把新树加入到森林中。
4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。

如下图所示:
初始森林第一次合并二次合并哈夫曼树

2.3 哈夫曼编码

利用哈夫曼树求得的用于通信的二进制编码称为哈夫曼编码。树中从根到每个叶子节点都有一条路径,对路径上的各分支约定指向左子树的分支表示”0”码,指向右子树的分支表示“1”码,取每条路径上的“0”或“1”的序列作为各个叶子节点对应的字符编码,即是哈夫曼编码。

哈夫曼编树(带哈夫曼编码)
上图A,B,C,D的哈夫曼编码为:111,10,110,0

注意:设计电文总长度最短的二进制前缀编码,就是以n个字符出现的频率
作为权构造一颗哈夫曼树,由哈夫曼树求得的编码就是哈夫曼编码。

参考博客(里面有C#代码实现):数据结构和算法系列16 哈夫曼树

三、二叉树遍历上机任务

#include <stdio.h>
#include <stdlib.h>
typedef struct BiTNode{
  char data;
  struct BiTNode *lchild,*rchild;
}BiTNode,*BinTree;
int n0,n1,n2; //用全局变量分别统计叶子结点、单孩子结点、双孩子结点个数

void CreateBiTree(BinTree *T);   //构造二叉链表
void InOrder(BinTree T);         //中序遍历
void PostOrder(BinTree T);       //后序遍历
int Leafnum(BinTree p);         //统计叶子结点数目
int Onechildnum(BinTree p);	 //统计单孩子结点数目
int Twochildnum(BinTree p);	 //统计双孩子结点数目
void main()   //主函数
{
	BinTree T;
	char ch;

	while(1)
	{
		system("cls");
		printf("\n\t二叉树的基本操作:\n");
		printf("\n\tA -----二叉树建立-------");
		printf("\n\tB -----中序遍历---------");
	    printf("\n\tc -----后序遍历---------");
		printf("\n\td -----求叶子节点个数---------");
		printf("\n\te -----求单孩子节点个数---------");
		printf("\n\tf -----求双孩子节点个数---------");
		printf("\n\n\t请选择:");
		scanf("\n%c",&ch);

		switch(ch)
		{
			case 'a':
			case 'A':printf("\t请按先序输入二叉树存储的结点序列:");
					 CreateBiTree(&T);
					 break;

			case 'b':
			case 'B':printf("\t该二叉树的中序遍历序列为:");  //调用中序遍历函数
					 InOrder(T);
					 break;

			case 'C':
			case 'c':printf("\t该二叉树的后序遍历序列为:");  
					 PostOrder(T);
					 break;

			case 'd':
			case 'D':printf("\t该二叉树的叶子节点数为:%d",Leafnum(T));  
					 break;

			case 'e':
			case 'E':printf("\t该二叉树的单孩子节点数为:%d",Onechildnum(T));  
					 break;

			case 'f':
			case 'F':printf("\t该二叉树的双孩子节点数为:%d",Twochildnum(T));  
					 break;
		
			default:printf("\n\t输入错误,重新选择");
		}
		printf("\n\t");
		system("pause");
	}
}
void CreateBiTree(BinTree *T)  //建立二叉链表
{ 
	char c;
	scanf("\n%c",&c);
	if(c=='0')
      *T=NULL;
	else
	{

	*T=new BiTNode; 
	(*T)->data =c;
	CreateBiTree(&(*T)->lchild);//构造左子树
	CreateBiTree(&(*T)->rchild);//构造右子树    


	}
}
void InOrder(BinTree T) //中序遍历
{
if(T== NULL)
return;
  PostOrder(T->lchild);
 printf("%c",T->data);
 PostOrder(T->rchild);

 
}
void PostOrder(BinTree T) //后序遍历
{
 if(T== NULL)
 return;

 PostOrder(T->lchild);
 PostOrder(T->rchild);
 printf("%c",T->data);
 
}



int Leafnum(BinTree p)  //计算二叉树叶子结点数目
{ 
 
	if(p==NULL)
		return 0;
	if(p->lchild==NULL&&p->rchild==NULL)
		return 1;
	return (Leafnum(p->lchild)+Leafnum(p->rchild));
}

int Onechildnum(BinTree p)  //计算单孩子结点数目
{ 
  if(p==NULL)
  return 0;
   if((p->lchild !=NULL && p->rchild==NULL) || (p->lchild ==NULL && p->rchild!=NULL))
  return 1;
  return  (Onechildnum(p->lchild)+Onechildnum(p->rchild));

}
int Twochildnum(BinTree p)  //计算双孩子结点数目
{ 

  if(p==NULL)
  return 0;
   if(p->lchild !=NULL && p->rchild!=NULL )
   return 1;
   return (Twochildnum(p->lchild)+Twochildnum(p->rchild));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值