算法和数据结构之树

一、介绍

面试造火箭,开始造树。那么什么是树(Tree)呢?马路边儿上的大树,森林里的大树?是的。就是那玩意。数据结构的树之所以叫树就是因为和马路边儿上的大树长得差不多。做为一种抽象的数据类型(ADT)——树,就是因为他的组织结构类似于树的形状(不过要倒过来看,也就是根在最上,树叶在下面),树是由有限个节点(Node)组成的。下面看一个普通的树的图:

在这里插入图片描述

在自然世界中,两根树枝是不能连接生长在一起的,所以数据结构中的树也一样,不能在两个子树之间有直接的连接,否则,就不是树了。这个需要引起注意。

二、树的形态

树在计算机世界中的应用是非常广泛的,从基础的排序到数据编码,再到查找搜索保存等。树的各种衍生形态非常多,但核心基本就两类:二叉树、多叉树。而在这其中,最常用的就是二叉树,二叉树是如何定义的呢?
二叉树的任意一个节点最多只有两棵子树,二叉树的子树分为左子树和右子树,次序不能颠倒。二叉树的第n层至多有2(n-1)个结点;深度为k的二叉树至多有2(k-1)个结点;对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n^2,则n0=n2+1。
在这里插入图片描述

二叉树主要有以下几种形态:

1、完全二叉树
完全二叉树是指除最后一层外,其它各层节点数目均达到最大值,而最后一层的所有节点自左向右连续的紧密排列。听起来可能有点不好理解,看图:

在这里插入图片描述

完全二叉树可以这样理解,假如一个完美二叉树缺少的节点是最下层的自右向左的顺序节点时,就是一个完全二叉树。

2、完美二叉树(满二叉树)

完美二叉树就好理解了,就是一个标准的二叉树帅哥。不过这里有一个注意的是,国内和国外对其定义略有不同:
如果一个二叉树的每层的结点数都达到最大值,则这个二叉树就是完美(满)二叉树。即如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是完美(满)二叉树。
这个定义是国内的教科书常见的定义方法,也是大家一般认为的情况。

在这里插入图片描述

国外的定义方法为:
a binary tree T is full if each node is either a leaf or possesses exactly two childnodes.
在这里插入图片描述

说的比较麻烦,一看图就清楚了。

3、完满二叉树
完满二叉树,一听就是完全和满二叉树的结合啊?有那个意思,但还是有不同(其实如果以国外的定义满二叉树,就好理解了,用国内定义的满二叉树就得动下脑筋)。完满二叉树就是一个二叉树,如果一个节点有孩子,那么这个节点一定有两个孩子。
在这里插入图片描述

三、树的遍历

先定义一个基准的遍历树,如下:

在这里插入图片描述

树的遍历分为三种:

1、先(前)序(根)遍历:
先序遍历,就是先访问根,再访问左子树,然后再访问右子树。在图上,你可以看做是以根为起点,对整个树进行环形遍历。先看一下上图的先序遍历的结果:
A-> B->D-> H ->I-> E-> J-> C-> F-> K-> G

先序遍历先走根从A起,ABDHI,这个好理解,下来又走BEJ,但B已经访问过,所以去除,即ABDHIEJ,同样,到ACFKGCA,其中A已经遍历,去除。第二个C也去除。最后形成ABDHIEJCFKG。

2、中序(根)遍历:
中序遍历就是先访问左子树再访问根结点,再访问右子树。在图上,可以看做一个投影过程,把树投影到一个数轴上,得到的就是中序遍历,这个在后面的红黑树中还会讲,先看一下结果:
H->D->I->B->E->J->A->F->K->C->G
投影很简单,如果不想画图,把树拉扁,自左向右挨个拉取即可。

3、后序(根)遍历
后序遍历就是先访问右子树,再访问右子树,最后再访问根结点,它也有简单的记忆方法,即从根的最下方最左起,按照左右上的方式裁剪单个结点,如果没有单个结点就从其子树中重自左到右向上的方式裁剪子结点。裁剪节点的顺序即为遍历的顺序。先看结果:
H->I->D->J->E->B->K->F->G->C->A
以上面的图为例,最左侧为H,然后是I(H->I),这时候儿D结点只没有子节点了,裁剪(H->I->D)。继续向上,B结点有子节点,所以进入其右子树,J,J剪掉后,E形成一个单个节点,剪掉(H->I->D->J->E),B也成了一个单个节点,剪掉(H->I->D->J->E->B)。此时发现A节点有右子树,进入,从最左开始,F结点没有左子节点,但是有右子结点K,所以从K删除(H->I->D->J->E->B->K),再删除F,此时c节点有右子节点G,所以先删除单节点G,再删除C节点,再删除根节点A(H->I->D->J->E->B->K->F->G->C->A)。

有时候也会用层次遍历,这个就比较简单好理解了,这里就不再赘述。
经常遇到的问题是,如何把树转变成链表,其实就是基于上述的遍历思想,最简单的就是利用上面的中序遍历,实现一个双向链表。既可以使用递归,也可以使用非递归。

四、常见的应用

树的应用非常广泛。这里需要引起注意的是,B树和B-树,实际上,是没有B-树(就是B树)这一说法的,不过是在最初的翻译和应用过程中,导致的一些错误的说法。明白什么意思即可,不用为这个再加入口水大战。
常见的应用分为以下几类:
1、二叉查找树(有序二叉查找树)
二叉查找树就是通过二叉树进行查找,大家知道,查找前一般要排序,所以二叉查找树叫有序二叉树就正常了。其性质如下:
如果(根)节点的左子树不空,那么左子树的值小于(根)节点的值;假如右子树不为空,则右子树的值均大于于(根)节点的值;其任意节点的左右子树均符合前面两条性质。
在这里插入图片描述

这个树的缺点比较明显,就是如果数据排列在一定情况下会退化成链表,没有了树的意义。

2、AVL树(平衡二叉树-Self-balancing binary search tree):
平衡二叉树又叫AVL树(Adelson-Velsky-Landis Tree ),注意,还有一个AVL算法,不要混淆。AVL树就是左右子树的深度不超过1.并且其左右子树也符合这个性质。这个树的特别适合于查找数据,但在插入删除比较多的情况下,为保持树的平衡,会不断的进行旋转,耗费大量的时间。
在这里插入图片描述
3、红黑树
红黑树也是一种平衡树,它有如下特点:
每个节点要么是红的要么是黑的;根节点是黑的; 每个叶子节点都是黑的; 假如一个节点是红的,那其两个儿子都是黑的;红黑树中任意节点,其到叶节点的简单路径都包含相同数目的黑节点。
在这里插入图片描述
在后面会详细分析红黑树,这里不展开。

4、B树系列
B树同样是平衡树,它是一种多路搜索树,也就是多叉的,同样也是有序的。它的性质如下:
设定任意非叶子结点最大只有M个儿子;
且M>2;根结点的儿子数为[2, M];
除根结点以外的非叶子结点的儿子数为[M/2, M];
每个结点存放至少M/2-1(取上整)和至多M-1个KEY;(至少2个关键字);
非叶子结点的KEY个数等于指向儿子的指针个数-1;
非叶子结点的KEY:K[1], K[2], …, K[M-1];且K[i] 小于 K[i+1];
非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向KEY属于(K[i-1], K[i])的子树;
所有叶子结点位于同一层;
在这里插入图片描述

B+树的性质:
其定义基本与B-树同,同时:
非叶子结点的子树指针与KEY个数相同;
非叶子结点的子树指针P[i],指向KEY值属于[K[i], K[i+1])的子树(B-树是开区间);
为所有叶子结点增加一个链指针;
所有KEY都在叶子结点出现;

在这里插入图片描述

B树:
B
树是B+树的某个方面的优化,在B+树的非根和非叶子结点再增加指向兄弟的指针,这样就减少了KEY的数量,将结点的最低利用率从1/2提高到2/3。

在这里插入图片描述

从B树到B+到B* ,其实是一个牺牲空间不断的简单化的过程,B树可以自由存储数据,只要符合其性质,到了B+就要求叶子节点和非叶节点的KEY相同,并且增加了叶子节点间互相指向的指针。到了B*树,就又对非叶子节点间又增加了指针互相指向。
5、R树
R树是用来做空间数据存储的树状数据结构。例如给地理位置,矩形和多边形这类多维数据建立索引。这个在面试中遇到的比较少,一般是专业的才会问,这里就不再展开了,如果有兴趣,可以在网上查找相关资料。

6、Trie树
Tire树即字典树,又称单词查找树,它是一种哈希树的变种。在区块链中应用就比较多。经常用于统计,比如词频的统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少相关的字符串比较。
它的三个性质如下:
根节点不包含字符,除根节点外每一个节点仅包含一个字符;
从根节点到任一节点,路径上经过的字符连接起来,即为该节点对应的字符串;
任意节点的所有子节点包含的字符均不同。
在这里插入图片描述
其实,在树的应用中,就是要找出一种更好更优(时间空间等)的方法,让树始终保持在一个相对平衡状态,或者说一种稳定状态。这样,在后续的查找和增删改的过程中,付出代价最小。在现实的情况中,由于还没有找到一种方法能够兼顾各种的应用情况,所以只能衍生出不同的树的形态来适应一种或者多种应用的场景。从这个角度来理解为什么树有这么多种的形态,就好理解了。

五、总结

树的种类和形态很多,在后面会根据实际面试用到的多少进行分析。不过,不会像教材上讲的那样基础,重点是针对实际工程中遇到的问题和难点重点进行分析。如果有一些名词不太明白,比如度、深度等,可以看一下相关的教材。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值