题目:假设二叉树采用二叉链表存储结构,设计一个算法求二叉树的高度。
递归
分析:用递归方式来实现比较抽象,有一种没有解决问题的错觉。如果要理解递归,就要理解递归。。。但是递归的代码量少,简洁。如图,要以一种抽象化的方式来理解。不能具体,一旦具体了,就跟啥都没解决似的。
算法思想:递归左子树高度和右子树的高度,取较大者+1。
代码:
int BTdepth(BiTree T){ // 求树的高度depth
if(T!=NULL) // 空树的高度为零
return 0;
ldepth=BTdepth(T->lchild); // 求左孩子的高度
rdepth=BTdepth(T->rchild); // 求右孩子的高度
if(ldepth>rdepth)
ldepth=ldepth+1;
// 树的高度为最大高度的子树加个根结点
return ldepth;
else
rdepth=rdepth+1;
return rdepth;
}
非递归
分析:非递归比较难理解,是在层次遍历的基础上进行改造,也是借助队列完成。那么如何要求出树的高度?可以让一个变量last始终指向每一层最右端的结点,指了几个结点,就有几层,即二叉树的高度。
如图,rear指向入队的结点,front指向要出队的结点,last指向当前层最右端的结点。last是一个普通的变量,值为0,rear和front是队列的,指向-1。
根结点A入队,rear指向A
然后front前进一步,front指向A,A出队,访问,A有BC两个左右孩子,BC入队,front等于last,所以将last指向rear。注意只要front等于last了,就将last指向rear。
然后front前进一步,front指向B,B出队,访问,B有DE两个左右孩子,DE入队。
front前进一步,指向C,C没有左右孩子,C直接出队。
rear指向最后入队结点E。
此时front等于last,所以将last指向rear。
front往前走一步,指向D,D没有左右孩子,直接出队。
front向前走一步,指向E,E出队,访问,发现E有FG两个左右孩子,将FG入队,rear指向G,此时front=last,所以将last指向rear指向的结点。
front前进一步,指向F,没有左右孩子,直接出队;
front再前进一步,指向G,没有左右孩子,直接出队;
此时front=rear,结束循环,最终rear分别指向过ACEG,恰好是每层最右端的结点,结点个数为4,所以此二叉树的高度为4。
总结:rear指向每次入队的最后结点,front每次向前走一步,当fronreat时lastrear。这就是核❤思想。然后层数level加1,最后level的值就是二叉树的高度。
算法思想:采用层次遍历的算法,设置变量level记录当前结点所在的层数,设置变量last指向当前层的最右结点,每次层次遍历出队时与last指针比较,若两者相等,则层数加1,并让last指向下一层最右端的结点,直到遍历完成。level的值即为二叉树的高度。核❤问题在于如何让last指向每层最右端的结点。
代码:
int BTdepth(BiTree T){
if(T==NULL) // 空树的高度为0
return 0;
int front=-1,rear=-1; // 初始化一个空的队列
int last=0,level=0;
// last指向当前层的最右结点,level记录树的层数
BiTree Q[MaxSize]; // 假设队列足够大
Q[++rear]=T; // 根结点入队
BiTree p; // 初始化指针p
while(front<rear){
// 队列不空,则循环
// fornt<rear说明有入队的操作,队列不空
p=Q[++front];
// front指向要出队的结点
// 当前front指向的队列元素出队并访问
if(p->lchild) // 如果有左孩子
Q[++rear]=p->lchild; // 左孩子入队
if(p->rchild) // 如果有右孩子
Q[++rear]=p->rchild; // 右孩子入队
if(front==rear){ // ❤
level++; // 层数加1
last=rear; // ❤
}
}
return level;
}