数据结构:树与二叉树(三) 特殊二叉树

这片博客讲一下二叉树中的几种特殊二叉树。

 

一、二叉排序树

1.定义

2.递归定义

3.特点

4.二叉排序树的构建(创造)

二、堆

1.定义

2.特点

3.堆的用途

4.堆的构造(创建)

三、最优二叉树

1.基本概念

2.最优二叉树(哈弗曼树,Huffman树)定义

3.最优二叉树的创造(构建)

4.最优二叉树的应用——Huffman编码

 

 

一、二叉排序树(Binary Sort Tree,BST)

1.定义:二叉树中,任何结点均满足条件:“大于其左子树上的所有结点,小于其右子树上的所有结点(若存在的话)”。又称为二叉查找树,或二叉搜索树。

2.递归定义:若二叉树是空,则是二叉排序树,否则:若左子树不空,它的结点均小于根结点;若右子树不空,它的结点均大于根结点;左右子树又都是二叉排序树。

3.特点:

(1)可以实现类似折半思想的查找,有较高的查找性能;

(2)中序遍历二叉排序树,可以得到一个有序序列。

4.二叉排序树的构建(创造)

因为二叉排序树的特殊性质,所以其创建方法比较简单(左小右大)。

(1)基本思想:只需将数据元素链到合适的位置(满足其特殊性质)。

(2)创建方法:

开始二叉树为空,然后重复在二叉树中插入元素,即:

读入数据结点;

①若二叉树为空,则该结点为树的根结点;显然是二叉排序树;

②若二叉树不是空,则与根做比较,若比根大则在右子树中插入,否则在左子树中插入。

重复②中步骤,直到所插入结点成为树的叶子结点。

二叉排序树,最主要的操作就是创建和删除,对于创建,给定一个数据序列,要根据该序列创建二叉树,例如:

至于操作的具体实现,这里就不写了,很简单,有兴趣的童鞋可以问一下度娘。

 

二、堆(Heap)

在许多应用中(例如优先队列),需要从数据集中挑选具有最小或最大关键码的元素。找最小或最大元素的常用算法的思想就是“打擂台”(就是将数据元素排队一个一个来,如果当前元素比擂台上的元素更大或更小,则将该元素扶上擂台,原先在擂台上的元素则舍弃),其时间复杂性为O(n)。那么有没有更好的算法呢?

“堆”是一种特殊的二叉树数据结构,在它上面可以有高效的求最小(或最大)值操作。

1.定义:n个数据元素的序列a1,a2,a3,...,an,当且仅当满足下列关系是为堆。又称为二叉堆,Binary Heap

ai<a(2*i)        ai<=a(2*i+1) ——最小堆   或者   ai>a(2*i)        ai>=a(2*i+1) ) ——最大堆

堆可以用一棵完全二叉树来表示,更直观。即以n个数据元素的序列a1,a2,a3,...,an按照从第一层开始,每层从左向右构造出完全二叉树,如果任一结点的元素值都不大于(或不小于)它的左右孩子的元素值,则该完全二叉树就是最小堆(最大堆)。

 

2.特点:

(1)在最小堆中,最小的元素一定是根结点元素,最大元素可能在最右结点元素;

(2)在最大堆中,最大的元素也一定是根结点元素,最小元素咋不一定在哪里。


3.堆的用途:

(1)高效求最小(最大)值(在堆顶)。如果一个序列(完全二叉树)不是堆,则通过调整把它变成堆,于是就得到了最小(或最大)元素。

(2)不断地重复求最小(或最大)值,可以实现排序。——堆排序

 

4.堆的构造(创建)

(1)假设a(k+1)...a(m)满足堆的性质,即它是堆,而a(k)a(k+1)...a(m)不是堆,那么如何将其调整为堆?

(2)具体的调整步骤为,按“自上而下”的顺序调整:

堆顶元素a(k)与左右子树的根结点(a(2*k),a(2*k+1))比较(即只要与小根比较即可):

①若a(k)比小根小,则是堆(最小堆),结束;

②否则,即a(k)比小根大,则与小根交换。但可能会导致小根所在的子树的堆性质被破坏,如果被破坏,就用同样的方式进行调整,知道调整的子树已经是堆或为叶子为止。

即循环执行①②步骤(一个while循环)。

(3)假设a1...a(n)是任意一个序列,如何调整为堆呢?

老师PPT里讲的调整方法我反复看了,感觉有点问题,而且有点啰嗦,不过也可能是我没看明白,我就说一下自己的看法吧。

如果一个任意序列(任意一棵完全二叉树)要调整为堆,那么可以自下而上逐步调整,假设要调整为最小堆:

从叶子结点开始,将每个结点与其根结点作比较,如果值比根结点小,则将该结点与根结点互换,由此重复,直到换到根结点。然后再重复上述过程(即再从叶子结点开始比较),如果所有结点均与其根结点比较过后并未发生任何换位,则此堆调整完成。

放一组图,大家看了就明白了。

(4)堆的插入删除,与二叉排序树的思想大致相同,这里就不说了。当然,插入过后还是需要调整的。因为插入元素后,可能会破坏堆,调整的方法,与(3)中相同,不过只需要调整插入的那个节点即可。给大家放一组图。

删除堆顶元素,一般是用最后一个元素来替换堆顶元素。当然,替换过后,也可能会破坏堆,只需要按照(3)中的方法调整即可。

 

三、最优二叉树

1.基本概念

(1)路径:结点序列n1,n2,....nk满足n(i)是n(i+1)的双亲。

(2)路径长度:路径上的分支数。

(3)扩充二叉树:在一般二叉树中,将原来的每个空指针都指向一个特殊的结点——外结点(原来二叉树中的结点称为内结点),这样的二叉树称为扩充二叉树(真二叉树)。

特点:在扩充二叉树中没有度为1的结点。

外结点个数=内结点个数+1

(4)树的内路径长度:从根结点到各个内结点的路径长度之和。

树的外路径长度:从根结点到各个外结点的路径长度之和。

E = I + 2*n

举例:

(5)结点的权:有时为了表示某种含义,赋予结点一个数值。

(6)结点加权路径长度:从根结点到该结点的路径长度与权值之积,即w(i)*l(i)。

(7)扩充二叉树的加权路径长度(Weighted Path Length, WPL):假设给扩充二叉树的外结点(扩充后的叶子)赋予权值, 则二叉树中所有加权结点的加权路径长度之和称为扩充二 叉树的加权路径长度。

2.最优二叉树(哈弗曼树,Huffman树)定义:假设有n个数据元素,他们的全是分别为w1,w2,...,w(n),以它们为叶子构造具有n个叶子的(真)二叉树(可以构造很多棵)。加权路径最小的二叉树称为最优二叉树(哈弗曼树)。

特点:权值大的应该尽可能靠近根。

举例:

3.最优二叉树的创造(构建)

(1)基本思想:选择权值小的叶子,让它离根的距离尽可能远(贪心算法)。

(2)算法描述:

①由给定 n 个权值 {w0, w1, w2, …, w(n-1)},构造具有 n 棵扩 充二叉树的森林 F = { T0, T1, T2, …, Tn-1 },其中每棵扩 充二叉树 Ti 只有一个带权值 wi 的根结点, 其左、右子树 均为空;

②重复以下步骤,直到F中仅剩一棵树为止:

在 F 中选取两棵根结点的权值最小的扩充二叉树,    做 为左、右子树构造一棵新的二叉树。置新的二叉树的根结点的权值为其左、右子树上根结点的权值之和。 

·在F中删去这两棵二叉树。

·把新的二叉树加入F。

说实话,这上面的描述是在太绕口了,我读了好几遍才明白,说白了,这个算法就是先将权值最小的两个结点作为叶子结点,其根结点的权值是这两个结点的权值相加,如果等待的结点中有与这个相加后的权值相等的结点,就作为这个根结点的兄弟结点,然后依次累加上去,知道最终的root结点。

举个例子:

当然, 这种方法构造的最优二叉树不一定是唯一的,因为左右子树可以互换。

4.最优二叉树的应用——Huffman编码

早期,电报是进行快速、远距离通讯的重要手段。

实现电报通讯的两个要素:

①一套编码,可以将电文编码为待发送的电文,还可以把收到的电文译码为原电文。

②发送的电文应尽可能短,节省占用线路费用。

编码的原则:

首先,译码要唯一,即对字符进行编码后,能够唯一地翻译成原来的字符;其次,各个字符的编码要尽可能短,只有这样才能使编码后最短。

编码的方法:

定长编码方法——特点:易达到译码唯一,但长度较大;ASCII编码是定长编码;

不定长编码方法——特点:长度较短,但达到译码唯一较难。

(1)哈夫曼编码的方法——不定长编码方式

前缀码:任何一个字符的编码都不是另外字符编码的前缀。

构造方法:用被编码的字符作为叶子,构造二叉树,然后在二叉树的做分支上标“0”,右分支标“1”(或反过来),每个字符的编码就是从根到该字符叶子所经过路径上的0、1序列。

这样构造出来的一套编码一定是前缀码,译码唯一。

(2)举例:

(3)使编码最短的方法——哈夫曼树

要是电文的编码长度最短,应该使用频率高的字符,编码应该短,可以使用频率作为权值,构造编码字符为叶子的哈夫曼树(二叉树),使用频率高的字符,离根近,编码短。从而,电文编码达到最短(而且是前缀码)。

因此,一棵最优二叉树就同时解决了译码唯一和编码长度最短 的问题,由Huffman树得到的这套编码称为Huffman编码。

举例:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值