二叉树相关资料

转载自http://blog.csdn.net/yi_zz/article/details/7396987

你应该掌握的——树和二叉树


我在上课的时候,由于各种原因,上课老师讲的自己总不爱听,现在到火烧眉毛了,才知道这些基础知识的重要性,现在想想,也没有那么的困难。重在理解这些底层的概念,然后考试考的都是一些很简单的概念和计算,在这里我来阐述一下树和二叉树的一些考点。

基础知识一点也不能马虎。所以我们从最基础的开始说起。

以这棵树来说几个基本的概念。


结点的度:一个结点的子树数目称为该结点的度。(例如结点1的结点的度为3,结点2的结点的度为3,结点3的结点的度为0)。

树的度:所有结点度当中,度最高的一个。(上图树的度是3)。

叶子结点:上图应该是:3、5、6、7、9、10

分之结点:除了叶子结点,其他的都称为分之结点,和叶子结点构成互补的关系。(1、2、4、8)

内部结点:分之结点除了根结点以外的。(2、4、8)

父结点:如5号结点就是2号结点的子结点。

子结点:2号结点是5号结点的父结点。

兄弟结点:5、6、7称为兄弟结点,出自同一个父亲2号结点。

这三个概念是一个相对的概念。

层次:0层、1层、2层、3层。

还有一个公式就能做题了:总结点=所有度结点的和+1(应该是父结点)


树的遍历


我们还是根据这图来看看树的三种遍历。

前序遍历先从根部出发,然后由左向右,一颗一颗树来完成遍历。先访问根再访问叶子结点,这就是我画出来的前序遍历图,箭头的方向表示遍历的顺序。a为起点。


结果是:1、2、5、6、7、3、4、8、9、10


后序遍历顾名思义,就是从叶子结点出发,先遍历叶子结点再到根结点,最后到父结点。我画出顺序可能会更直观点。


结果是:5、6、7、2、3、9、10、8、4、1


层次遍历按0层、1层、2层、3层,从左到右来遍历


结果是:1、2、3、4、5、6、7、8、9、10


我们接着就可以来理解二叉树的重要的特性:

我们找五颗二叉树来进行分析:这样分析就简单多了,我都觉得不用分析了,但是还是说说吧。

1、二叉树中,第i层上最多有2的i次方个结点(i>=0)。这个很基本,这也是二叉树和树的区别。

2、深度为K的二叉树至多有2的(k+1)次方 -1个结点(k>=0)。(深度为二叉树中层数最大的叶节点的层数),满二叉树的深度为2,则共有7个结点。

3、对任何一颗二叉树,如果其叶子结点数为n0,度为2的结点数为n2,则n0=n2+1;(一定不要忘了根结点的度也是2)。


二叉树的遍历


前序遍历应该是怎么个流程呢:我们看图。


遍历的结果是:1、2、4、5、7、8、3、6。从根结点分两部分,先把左边的遍历完,都是从左到右的。


中序遍历:

结果是:4,2,7,8,5,1,3,6。


后序遍历:


结果是:4、8、7、5、2、6、3、1


层次遍历:


结果是:1、2、3、4、5、6、7、8

那么树和二叉树就说这么多,我相信掌握这么多,也差不多够用了哦,对于上面的基础知识,要是我有不对的地方,希望大家指出哈。

把学习由复杂变简单(二叉树和树)

分类: 软考 8130人阅读 评论(81) 收藏 举报

现在发现二叉树和树讲起来真的是没完没了,刚发表博客之后发现,那还不足以表述这颗大树。我们继续完善。

树与二叉树遍历确实很重要,但是还有一些你也许忘记的重要知识点,我们再来看一下还有什么好玩的:我不太喜欢太深奥的东西,所以我一般以我能理解的简单的方法去说说这些知识点。


树与二叉树的转换

我们都知道二叉树与树不同,因为二叉树是有讲究的,比如:二叉树第i层最多只有2的i次方个结点,所以当把树转换成二叉树的时候。我们是有窍门的,还是用图来说话,我们接下来也来看这么一张图,看看到底是怎么个转换的:


这一看就知道是树,因为不符合我们二叉树的特点,比如结点3带的叶子结点就不符合我们二叉树的要求了,所以我们要想办法去转换成二叉树。

很简单,就一句话:树的左孩子结点作为二叉树的左子树结点,兄弟结点作为二叉树的右子节点。我们看图是怎么转换的:

在这个图里边,2是根结点的左子树结点,与2并列的3、4是2的兄弟结点,故转换成二叉树时,作为2的右子节点,类似的,5是3的左子树结点,故也是二叉树里3的左结点,6、7与5并列,就作为5的右子节点,类似的,4号结点也是一样,我们看图:

我们按照这句话,就能轻而易举的画出个大概了,然后我们把黑色的线抹去就行了。抹去之后,就成这样了:


这就验证了我的那句话一点问题都没有。千万不能着急,那么事情就没有想象的那么复杂了。


查找二叉树:

我们边看图边分析:

分析查找二叉树的一些递归条件:

a.查找树的左、右子树各是一颗查找树。这个很明了,无可厚非。

b.若查找树的左子树非空,则其左子树上的各节点均小于根结点的值。如图:2和4都小于5。

c.若查找树的右子树非空,则其右子树上的各节点值均大于根节点的值。如图:6和8都大于5。

所以结合图来分析问题,一切的理论都是浮云。记是记不住的。必须要理解。

我们有了这些对查找二叉树的认识之后,后面分析起来就简单了。

查找二叉树的一些基本操作:查找、插入结点、删除结点:

查找:

比如我们要查找56,那么我们就能马上找到,因为左结点的都比根节点要小,右结点都比根结点要大。所以我们很easy的找到了。

插入结点:

插入结点就有意思了,但是还是很简单,一样的规则,左小右大。继续前行:举个例子,插入29:从上面的图,我们一眼就看的出来,29必须要跟着20了,因为56的右结点要比56要大,所以不可能,那么112的左结点呢?更不可能了,因为112的所有子结点都要比根节点89要大,所以非常easy吧。只能作为20的右子结点了。

删除结点:

要是叶子结点就直接删除,要是带一个叶子结点的就直接吧叶子结点接到待删除的父结点上,要是带两个子节点的,就用中序遍历查找最大的结点,直接删除最大结点。


哈夫曼树:

我们看图理解:


树的路径长度:树到达每一个结点都有一个路径,把所有的路径的值加起来,路径长度之和,就是树的路径长度了。

就第一棵树来说:看图:

结点8的路径长度是3;2的路径长度是2,4的路径长度:3。兄弟结点的路径长度是一样的。

和结点数是息息相关的,同样结点的树,完全二叉树的路径长度是最短的。

:对某个结点赋予一个有意义的值,其实就是我们看到的这些值,如叶子结点的权值是:2、4、8、1。

带权路径长度:权值乘以路径长度,比如叶子结点8的带权路径长度为:8*3=24。

树的带权路径长度:所有带权路径长度的值相加。哈夫曼树是一种带权路径长度最短的。比如第二颗树:

结果为:1*8+2*4+3*3=25

左边的是:

结果是:1*1+2*2+(4+8)*3=41,同样结构,同样结点数,机器运算所要花费的时间就不同,哈夫曼树是最优的。

如何构造哈夫曼树:

比如我们有一组权值{5,29,7,8,14,23,3,11}:

我们从最小的开始,最小的作为叶子结点,至于为什么,因为权值代表遍历的次数,所以我们考虑效率的问题,把权值最小的作为叶子结点,一颗颗树来拼接起来就OK了。

第一步我们就得到了:


哈夫曼树也是二叉树,所以也是按照二叉树的规则,左小右大。

继续一个一个把这些权值添加到这两颗树上面,从小到大的“堆积”起来,最后形成的大树。看图:


 哈夫曼编码:左边为1,右边为1;把权标志了,比如23的编码是:00。11的编码是:010。看图:


就这么简单,所有结点的编码都出来了。


线索二叉树:

线索二叉树我们来讲讲怎么把二叉树装换成线索二叉树。

我们看这颗二叉树:

前序线索二叉树:

我们应该是怎么个步骤呢?我们先写出这颗二叉树的前序遍历:ABDEHCFGI,然后我们把结点的指针给填满,主要是找到叶子结点的前驱和后继。

我们从前序遍历ABDEHFCGI就能看出D结点的前驱结点是B结点,后继结点是E结点,类似的,把这些结点的空指针填满。,应该是这么个图:


中序线索二叉树,我们把中序二叉树遍历写出来:DBHEAFCGI;那么我们的中序线索二叉树就轻而易举的画出来了,看图:


后序线索二叉树,我们把后序二叉树遍历写出来:DHEBFIGCA;那么我们的后序线索二叉树就轻而易举的画出来了,看图:


线索二叉树的其他内容还有很多,用到的时候再说吧,线索二叉树与二叉树的转换,应该是大家需要的吧。


平衡二叉树:

1、或者是一颗空树;

2、或者是一颗:书中的任一结点的左、右子树的深度相差不超过1。我们分析一棵树:


我们凭感觉就知道这棵树不是平衡二叉树,一边倒,聪明:我们分析看看符合平衡二叉树的条件不:


在分析的过程中,我们把每一个结点当做是一棵树,如结点1当做空一棵树的时候,就是一颗空子树;结点5没有右子树,所以相差为1。,还有我们分析到结点39的时候,我们一看就知道它没有右子树,而左子树是3,可以把1、5、7作为左子树来判断。

所以这棵树是不符合我们的平衡二叉树的要求的。

我们来分析一颗符合要求的,看看符合要求的二叉树是什么样的:

其实我们用肉眼就能大概辨别的出来,但是要是信心不够的话,可以分析分析。


平衡树的调整:你懂了几个旋转就搞定了。看看这个旋转是什么个情况:

LL型平衡旋转:右旋平衡处理,其实就是想办法把这些二叉树弄平衡,看图:

RR型平衡旋转:左旋处理。


从上面的两个旋转来看,主要是把中间的那个节点作为根结点,然后另外两个结点分别作为左、右子树,就能达到目的。

接下来我们看有点点复杂的,其实也很简单:


LR型平衡旋转:我们有了上面两个基础,再来看这个也就easy了:看图说话:

不要被这个图吓着,其实我当时一看也懵了半天,但是经过我们一分析,都是纸老虎:我们看

1、我们把左边这个图分解来看:

左子树是添加了一个新的结点,一看很熟悉,我们把这颗左子树去掉BL和CL,那么就跟RR型旋转是一样的道理了,把C结点作为根结点,就成了:那么这边这棵树就没问题了,接下来我们看整棵树:

整棵树还是不平衡的,所以我们还是老办法,看成是LL型的:就能得到结果了:

还有一种旋转LR旋转,一样的,我们就不说了。呵呵,希望能帮到大家。

http://blog.jrj.com.cn/4044569723,7793454a.html转载自http://blog.jrj.com.cn/4044569723,7793454a.htmlhttp://blog.jrj.com.cn/4044569723,7793454a.htmlhttp://blog.jrj.com.cn/4044569723,7793454a.htmlhttp://blog.jrj.com.cn/4044569723,7793454a.htmlhttp://blog.jrj.com.cn/4044569723,7793454a.htmlhttp://blog.jrj.com.cn/4044569723,7793454a.htmlhttp://blog.jrj.com.cn/4044569723,7793454a.html blog[精华]]]二叉树的应用详解

[精华]二叉树的应用详解

概述:

平衡树——特点:所有结点左右子树深度差≤1

排序树——特点:所有结点“左小右大
字典树——由字符串构成的二叉排序树
判定树——特点:分支查找树(例如12个球如何只称3次便分出轻重)
带权树——特点:路径带权值(例如长度)

最优树——是带权路径长度最短的树,又称 Huffman树,用途之一是通信中的压缩编码。

1. 二叉排序树(二叉查找树 Binary Search Tree):

1.1 二叉排序树:

或是一棵空树;或者是具有如下性质的非空二叉树:

 (1)若左子树不为空,左子树的所有结点的值均小于根的值;

 (2)若右子树不为空,右子树的所有结点均大于根的值;

 (3)它的左右子树也分别为二叉排序树。

例:二叉排序树 如图9.7:

                 



     二叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构。中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,期望O(logn),最坏O(n)(数列有序,树退化成线性表).
虽然二叉排序树的最坏效率是O(n),但它支持动态查询,且有很多改进版的二叉排序树可以使树高为O(logn),如T,AVL,红黑树等.故不失为一种好的动态排序方法.

2.2 二叉排序树b中查找

在二叉排序树b中查找x的过程为:

  1. 若b是空树,则搜索失败,否则:
  2. 若x等于b的根节点的数据域之值,则查找成功;否则:
  3. 若x小于b的根节点的数据域之值,则搜索左子树;否则:
  4. 查找右子树。

2.3 在二叉排序树插入结点的算法

向一个二叉排序树b中插入一个结点s的算法,过程为:

  1. 若b是空树,则将s所指结点作为根结点插入,否则:
  2. 若s->data等于b的根结点的数据域之值,则返回,否则:
  3. 若s->data小于b的根结点的数据域之值,则把s所指结点插入到左子树中,否则:
  4. 把s所指结点插入到右子树中。
2.4 在二叉排序树删除结点的算法

在二叉排序树删去一个结点,分三种情况讨论:

  1. 若*p结点为叶子结点,即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
  2. 若*p结点只有左子树PL或右子树PR,此时只要令PL或PR直接成为其双亲结点*f的左子树即可,作此修改也不破坏二叉排序树的特性。
  3. 若*p结点的左子树和右子树均不空。在删去*p之后,为保持其它元素之间的相对位置不变,可按中序遍历保持有序进行调整,可以有两种做法:其一是令*p的左子树为*f的左子树,*s为*f左子树的最右下的结点,而*p的右子树为*s的右子树;其二是令*p的直接前驱(或直接后继)替代*p,然后再从二叉排序树中删去它的直接前驱(或直接后继)。在二叉排序树上删除一个结点的算法如下:

2. 5二叉排序树性能分析
每个结点的Ci为该结点的层次数。最坏情况下,当先后插入的关键字有序时,构成的二叉排序树蜕变为单支树,树的深度为n,其平均查找长度为 (和顺序查找相同),最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和log2(n)成正比 (O(log2(n)))。


2.6 二叉排序树的优化
    Size Balanced Tree(T)
    AVL树
    红黑树
    Treap(Tree+Heap)
这些均可以使查找树的高度为O(logn)

2. 平衡树二叉树(又AVL 树)

1. 1 平衡二叉树(Balanced Binary Tree)

性质:  左右子树都是平衡二叉树且所有结点左、右子树深度之差的绝对值 ≤ 1。

若定义结点的平衡因子  BF(Balance Factor) = 左子树深度–右子树深度 则:平衡二叉树中所有结点的BF ∈[ -1, 0, 1 ]

例:判断下列二叉树是否AVL树?




常用算法有红黑树、AVL、Treap、伸展树等。在平衡二叉搜索树中,我们可以看到,其高度一般都良好地维持在O(log2n),大大降低了操作的时间复杂度。

平衡二叉树是二叉排序树的另一种形式。

我们希望由任何初始序列构成的二叉排序树都是平衡二叉树。因为平衡二叉树上任何结点的左右子树的深度之差都不超过1,则可以证明它的深度和logN是同数量级的(其中N是结点的个数)。由此,它的平均查找长度也和logN同数量级。

C语言描述:


构造二叉平衡(查找)树的方法是:在插入过程中,采用平衡旋转技术

插入算法 :

算法思想:

在平衡二叉排序树BBST上插入一个新的数据元素e的递归算法可描述如下:

1.若BBST为空树,则插入一个数据元素为e的新结点作为BBST的根结      点,树的深度增1; 

2.若e的关键字和BBST的根结点的关键字相等,则不进行插入; 

3.若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加(+1)时,分别就下列不同情况处理之:

    iBBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度):则将根结点的平衡因子更改为0BBST的深度不变;

    ii.BBST的根结点的平衡因子为0(左、右子树的深度相等):则将根结点的平衡因子更改为1,BBST的深度增1; 

    iiiBBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):

         a. BBST的左子树根结点的平衡因子为1,则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子更改为0,树的深度不变;

         b. BBST的左子树根结点的平衡因子为-1,则需进行先向左、后向右的双向旋转平衡处理,并且在旋转处理之后,修改根结点和其左、右子树根结点的平衡因子,树的               深度不变。

4.若e的关键字大于BBST的根结点的关键字http://www.shareapk.net/,而且在BBST的右子树中不存在和e有相同关键字的结点,则将e插入在BBST的右子树上,并且当插入之后的右子树深度增加(+1)时,分别就不同情况处理之。其处理操作和上述3.中描述相对称。


3. 判定树:

      二分查找过程可用二叉树来描述:把当前查找区间的中间位置上的结点作为根,Answers左子表和右子表中的结点分别作为根的左子树和右子树。由此得到的二叉树,称为描述二分查找的判定树(Decision Tree)或比较树(ComparisonTree)

注意:
     判定树的形态只与表结点个数n相关,而与输入实例中R[1..n].keys的取值无关。
【例】具有11个结点的有序表可用下图所示的判定树来表示。


举例:12个球如何用天平只称3次便分出轻重?

分析:12个球中必有一个非轻即重,即共有24种“次品”的可能性。每次天平称重的结果有3种,连称3次应该得到的结果有33=27种。说明仅用3次就能找出次品的可能性是存在的。

思路:首先,将12个球分三组,每组4个,任意取两组称。会有两种情况:平衡,或不平衡。其次,一定要利用已经称过的那些结论;即充分利用“旧球”的标准性作为参考。



二分查找判定树的查找
二分查找就是将给定值K与二分查找判定树的根结点的关键字进行比较。若相等,成功。否则若小于根结点的关键字,到左子树中查找。若大于根结点的关键字,则到右子树中查找。
  【例】对于有11个结点的表,若查找的结点是表中第6个结点,则只需进行一次比较;若查找的结点是表中第3或第9个结点,则需进行二次比较;找第1,4,7,10个结点需要比较三次;找到第2,5,8,11个结点需要比较四次。
    由此可见,成功的二分查找过程恰好是走了一条从判定树的根到被查结点的路径,经历比较的关键字次数恰为该结点在树中的层数。若查找失败,则其比较过程是经历了一条从判定树根到某个外部结点的路径,所需的关键字比较次数是该路径上内部结点的总数。
   【例】待查表的关键字序列为:(05,13,19,21,37,56,64,75,80,88,92),若要查找K=85的记录,所经过的内部结点为6、9、10,最后到达方形结点"9-10",其比较次数为3。
     实际上方形结点中"i-i+1"的含意为被查找值K是介于R[i].key和R[i+1].key之间的,即R[i].key<K<R[i+1].key。
二分查找的平均查找长度
      设内部结点的总数为n=2h-1,则判定树是深度为h=lg(n+1)的满二叉树(深度h不计外部结点)。树中第k层上的结点个数为2k-1,查找它们所需的比较次数是k。因此在等概率假设下,二分查找成功时的平均查找长度为:
           ASLbn≈lg(n+1)-1
  二分查找在查找失败时所需比较的关键字个数不超过判定树的深度,在最坏情况下查找成功的比较次数也不超过判定树的深度。即为:
           
  二分查找的最坏性能和平均性能相当接近。

二分查找的优点和缺点
  虽然二分查找的效率高,但是要将表按关键字排序。而排序本身是一种很费时的运算。既使采用高效率的排序方法也要花费O(nlgn)的时间。
  二分查找只适用顺序存储结构。为保持表的有序性,在顺序结构里插入和删除都必须移动大量的结点。因此,二分查找特别适用于那种一经建立就很少改动、而又经常需要查找的线性表。
  对那些查找少而又经常需要改动的线性表,可采用链表作存储结构,进行顺序查找。链表上无法实现二分查找。

5. 带权树:

即路径带有权值。例如:



6. 最优树(赫夫曼树):

赫夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为赫夫曼树(Huffmantree)。即带权路径长度最短的树。
赫夫曼树构造算法:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为{w1、w2、…、wn},则哈夫曼树的构造规则为:  (1) 将{w1、w2、…,wn}看成是有n 棵树的森林(每棵树仅有一个结点);  (2)在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树,且新树的根结点权值为其左、右子树根结点权值之和;  (3)从森林中删除选取的两棵树,并将新树加入森林;  (4)重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树。
赫夫曼编码:是通信中最经典的压缩编码.
其算法:
stdafx.h文件:
test.cpp文件:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值