数据结构 (四) -- 树

本文详细介绍了二叉树的重要性质、完全二叉树的定义,并重点探讨了哈夫曼树(最优树)的概念、哈夫曼编码的原理及应用。通过举例说明了哈夫曼编码如何实现数据的最小冗余编码,同时讨论了构建哈夫曼树的过程,以及在通信电文编码中的应用。

根据luofang师姐还有网上做的笔记


半原创,侵删


二叉树极其重要的性质

度0结点数 = 度2结点数 +1


树的度


二叉树的性质



国际完全二叉树的定义:

1.叶子节点都在最后一层或者倒数第二层
2.如果有叶子节点,就必然有两个叶子节点


1.顺序存储

2.链式存储

Typedef struct BiTNode
{
	TElemType data;
	struct BiTNode *lchild,*rchild;	
}BiTNode,*BiTree;

中序遍历的递归算法

void InOrderTraverse(BiTree T)
{
	if(T)
	{
		InOrderTraverse(T->lchild);
		cout<<T->data;
		InOrderTraverse(T->rchild);
	}
}

至于先序和后序遍历只是调换顺序

中序遍历的非递归实现

void InOrderTraverse(BiTree &T)
{
	InitStack(S);
	p=T;
	q=new BiTNode;
	while(p||!StackEmpty(S))
	{
		if(p)
		{
			push(S,p);
			p=p->lchild;
		}
		else
		{
			Pop(S,q);
			cout<<q->data;
			p=p->rchild;
		}
	}
}

先序遍历的顺序建立二叉链表

void CreatBiTree(BiTree &T)
{
	ci>>ch;
	if(ch=='#') T=NULL;
	else
	{
		T=new BiTNode;
		T->data=ch;
		CreatBiTree(T->lchild);
		CreatBiTree(T->rchild);
	}
}

复制二叉树

void Copy(BiTree &T,BiTree &NewT)
{
	if(T==NULL)
	{
		NewT=NULL;
		return;
	}
	else
	{
		NewT=new BiTNode;
		NewT->data=T->data;
		Copy(T->lchild,NewT->lchild);
		Copy(T->rchild,NewT->rchild);
	}
}

计算二叉树的深度
二叉树的深度为树中节点的最大层数,二叉树的深度为左右子树深度的较大者+1

int Depth(BiTree &T)
{
	if(T==NULL) return 0;
	else
	{
		m=Depth(T->lchild);
		n=Depth(T->rchild);
		if(m>n)
			return m+1;
		else
			return n+1;
	}
}

统计二叉树中的节点个数

int NodeCount(BiTree &T)
{
	if(T==NULL) return 0;
	else
		return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}

哈弗曼树及其应用


感觉是全网对哈夫曼树讲解最透彻的一个

从原因再到过程,再到应用 很全面!!!强推!!!

可以点击此处跳转到时空隧道哦!!!

哈夫曼树:又称最优树,是指带权路径长度最短的树


哈夫曼编码:

对一颗具有n个节点的哈夫曼树,若对树中的每个左分支赋予0,右分支赋予1,则从根到每个叶子节点的路径上,各分支的赋值分别构成一个二进制串,这个二进制串就称为哈夫曼编码


前缀编码:

在一个编码方案中,任一编码都不是其他任何编码的前缀(最左子串),则称编码是前缀编码。

(这里看着很懵逼)


哈夫曼编码满足两个特征:

(1)哈夫曼编码前缀编码(也就是说,哈夫曼编码不会产生前缀的现象)也就是说,任一哈夫曼码都不会与任一其他的哈夫曼码的前缀完全发生重叠。
(2)哈夫曼编码是最优的前缀编码


例子:

例:如果需传送的电文为 ‘ABACCDA’,

它只用到四种字符,用两位二进制编码便可分辨。

假设 A, B, C, D 的编码分别为 00, 01,10, 11,则上述电文便为 ‘00010010101100’(共 14 位),译码员按两位进行分组译码,便可恢复原来的电文。


能否使编码总长度更短呢?

实际应用中各字符的出现频度不相同,用短(长)编码表示频率大(小)的字符,使得编码序列的总长度最小,使所需总空间量最少


数据的最小冗余编码问题

在上例中,若假设 A, B, C, D 的编码分别为 0,00,1,01,则电文 ‘ABACCDA’ 便为 ‘000011010’(共 9 位),但此编码存在多义性:可译为: ‘BBCCDA’、‘ABACCDA’、‘AAAACCACA’ 等。


译码的惟一性问题

要求任一字符的编码都不能是另一字符编码的前缀,这种编码称为前缀编码(其实是非前缀码)。 在编码过程要考虑两个问题,数据的最小冗余编码问题,译码的惟一性问题,利用最优二叉树可以很好地解决上述两个问题


用二叉树设计二进制前缀编码

以电文中的字符作为叶子结点构造二叉树。然后将二叉树中结点引向其左孩子的分支标 ‘0’,引向其右孩子的分支标 ‘1’; 每个字符的编码即为从根到每个叶子的路径上得到的 0, 1 序列。如此得到的即为二进制前缀编码。



例:如果需传送的电文为 ‘ABACCDA’,即:A, B, C, D 的频率(即权值)分别为 0.43, 0.14, 0.29, 0.14,试构造哈夫曼编码


例:如果需传送的电文为 ‘ABCACCDAEAE’,即:A, B, C, D, E 的频率(即权值)分别为0.36, 0.1, 0.27, 0.1, 0.18,试构造哈夫曼编码。


假设用于通信的电文仅由8个字母组成,字母在电文中出现的频率分别为0.07,0.19,0.02,0.06,0.32,0.03,0.21,0.10。

① 试为这8个字母设计赫夫曼编码。
② 试设计另一种由二进制表示的等长编码方案。
③ 对于上述实例,比较两种方案的优缺点。


线索二叉树

通过考察各种二叉链表,不管儿叉树的形态如何,空链域的个数总是多过非空链域的个数。准确的说,n各结点的二叉链表共有2n个链域,非空链域为n-1个,但其中的空链域却有n+1个。

因此,提出了一种方法,利用原来的空链域存放指针,指向树中其他结点。这种指针称为线索。

记ptr指向二叉链表中的一个结点,以下是建立线索的规则:

(1)如果ptr->lchild为空,则存放指向中序遍历序列中该结点的前驱结点。这个结点称为ptr的中序前驱;

(2)如果ptr->rchild为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为ptr的中序后继;

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值