解决的问题:
编写递归算法,计算二叉树中叶子结点的数目。
输入和输出数据的形式:
输入:
ABD…EH…CF.I…G…
输出:
若为空二叉树,则输出:THIS IS A EMPTY BINARY TREE。若二叉树不空,输出叶子结点的个数
简述存储结构和算法的基本思想。
存储结构:
链表存储
算法的基本思想:
采用递归方法建立和遍历二叉树。首先建立二叉树的根结点,然后建立其左右子树,直到空子树为止。遍历二叉树,若某一结点的左右孩子均为 NULL,则该结点为叶子结点。
#include<bits\stdc++.h>
using namespace std;
typedef char TElemType;
typedef struct BiTNode { //结点结构
TElemType data;
struct BiTNode *lchild, *rchild; //左右孩子指针
}BiTNode, *BiTree;
int ans=0;
void Leaf1(BiTree &T)//后序遍历统计叶子节点数目
{
if(T!=NULL)
{
Leaf1(T->lchild);
Leaf1(T->rchild);
if(T->lchild==NULL&&T->rchild==NULL)
ans++;
}
}
int (* Visit)(TElemType);
//按先序序列建立二叉树
int CreateBiTree(BiTree &T){
TElemType ch;
scanf("%c", &ch);
if (ch=='.'){
T = NULL;
}else {
if (!(T = (BiTNode *)malloc(sizeof(BiTNode)))){
exit(OVERFLOW);
}
T->data = ch; // 生成根结点
CreateBiTree(T->lchild); // 构造左子树
CreateBiTree(T->rchild); // 构造右子树
}
return 1;
}//CreateBiTree
//后序遍历二叉树(递归)
void PostOrderTraverse(BiTree &T, int (* Visit)(TElemType e)){
if (T) {
PostOrderTraverse(T->lchild, Visit); //后序遍历左子树
PostOrderTraverse(T->rchild, Visit); //后序遍历右子树
Visit(T->data); //访问根结点
}
}//PostOrderTraverse
int main(int argc, char* argv[]){
system("color f0");
BiTree T; //declaration
printf("\nInput a tree : \n");
//用例:ABD..EH...CF.I..G..\n
CreateBiTree(T); //创建
Leaf1(T);
printf("叶子节点的数目是:%d\n",ans);
system("pause");
return 0;
}
分析
优缺点:
优点:代码简洁清晰,可读性好
缺点:递归的话函数调用是有开销的,而且递归的次数受堆栈大小的限制。递归坏处:由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多。而且,如果递归深度太大,可能系统撑不住。
时空性能:
时间复杂度:O(n)
空间复杂度:O(h),h 是树的高度
改进思想:
实验采用二叉链表存储结构,方便了树的构造,遍历等等操作的递归实现,使程序的可执行性增强,但实验的时间性能和空间性能还有待提高。
心得:
二叉树的遍历分为先序遍历、中序遍历和后序遍历。遍历的顺序不同,则结果不同。而遍历方法也分递归和非递归。而二者的复杂度相同:时间复杂度为O(nlgn),空间复杂度为O(n) 。
用栈来实现二叉树的非递归遍历,我们现在可以得出一个结论,所谓的先序遍历、中序遍历、后序遍历不过是对一个节点以及它的左右子节点的遍历顺序罢了。那么我们把每三个节点:根、左、右当做一个整体,根据弹出栈的顺序,在循环遍历的时候将三个节点入栈,就能得到我们想要的遍历顺序。