此题选B,举出反例如下图:
这里节点6可以没有右子树(详见完全二叉树定义)但不能没有左子树,因此也可推断出D项是对的,因为只可能是根节点的右子树缺一个节点,所以中位数在根节点或根节点的左子树。
树习题选讲一
对于已知前序遍历和中序遍历,要求其后序遍历的问题,可以采用程序实现,如下图。
具体流程其实和手动推导的过程一样,首先在中序中搜索前序的第一个值,找到后将该值放到后序的最后一个位置。接下来对中序的左右两边不断递归。
值得注意的是程序里对于N=0,N=1,也就是搜索到一侧没元素了或者一侧只有一个元素两种情况,进行单独规定。否则递归到最后就会出现问题。
树习题选讲二 完全二叉搜索树
首先回顾定义:
注:二叉搜索树不一定是平衡树。完全二叉树如果对节点进行标号(从上到下从左到右),那么中间的标号顺序一个都不能少
题目要求
输入一串数,将这组数填入完全二叉树中,同时他应该满足二叉搜索树的性质(即左边比根节点小右边大)。最后输出该完全二叉树的层序遍历结果。
首先考虑用什么数据结构表示?链表 OR 数组?
如果用数组的话,在存储普通的树时,可能会有很多空的节点,浪费空间。这里要存储的本身是完全二叉树,是没有节点被浪费的,所以用数组不存在浪费问题。其次最后要求用层序遍历输出,如果用链表,最后还得构建队列进行输出,但是对于数组,层序遍历就是按照下标顺序直接输出,非常简便。所以这里采用数组
算法流程:
比如这列数为:0 1 2 3 4 5 6 7 8 9 ,首先考虑构建完全二叉树,一旦知道了有多少个数,就知道了有多少个节点,就可以得到唯一的,完全二叉树的结构,也就可以得出根节点是这列数按顺序排列后的第几个值是该树的根节点。
在这里的例子中,十个数字,那么完全二叉树结构确定了。同时可以得到根节点左侧必定有6个节点,右侧有三个,如下图。那么根节点就是这列数中从小到大排第七位的那个数字。同时该数字的前六位都在根节点的左子树中,右边三位在右子树中。所以得到这里的根节点应该是数字 6 。之后递归的解决左子树和右子树(因为根节点的左子树和右子树也都是完全二叉树)。
左边是6个节点的完全二叉树,那么这里的根节点左侧就有三个节点,右侧有两个,根节点就是6左侧排序后第四位数字3.以此类推。这也是典型的先序遍历的应用
伪码如下
函数传入三个参数,Aleft是当前这段序列A的最左端,Aright是A的最右端。Troot是这里选出的数字放在结果树T的位置。该算法的目的如图所示,就是从A中选出正确的树放进T[TRoot]中
首先算出这个序列的尺寸n,再根据n算出这棵树的左子树情况,以此得到T[TRoot]是A的什么位置。也就是A[ALeft+L].然后根据求出的根节点位置,算出其左右子树的根节点的位置LeftRoot和RightRoot。最后继续递归。
这里**GetLeftLength()**函数,也就是计算左子树规模的函数,算法如下:
因为完全二叉树除了最后一行可能不完整,上面的所有行都是一棵完整的二叉树。所以按顺序用下面1 2 3 三个公式计算。首先算出深度H,这里H是向下取整的,再用公式2计算,比较X和2^H-1哪个更小,让X取这两者中的最小值(理由是如下图,这种情况下就是取X,但是如果最底下一行元素比较多,可能右子树也有一部分X,但是因为这里是算左子树规模,左子树最下面一行最多只有2的H-1次方个元素,所以这里进行比较取值 )。
得到X后用公式3算出左子树的元素个数。