408,【2015统考真题】先序序列a,b,c,d的不同二叉树个数是()
A.13 ???????????????? B.14 ???????????????? C.15 ???????????????? D.16
有一种巧妙的方法,即以a,b,c,d为输入栈序列,对应输出栈的序列即为不同二叉树个数,这就引发了笔者的思考,为何可以这样进行解答。
要弄清楚这个问题,必须了解二叉树的先序遍历和中序遍历的关系,一个确定的先序遍历和中序遍历可以确定一颗二叉树,这是毋庸置疑的,又由于以a,b,c,d为输入栈序列的二叉树,每一颗都必定对应一个出栈序列,同时每一颗二叉树都必然对应一个中序序列,故可以推出每一个中序序列必然对应一个出栈序列也就是一颗确定的二叉树。
这么描述有点抽象,接下来以代码的形式进行解释。
首先是二叉树先序遍历的非递归算法:
viod PreOrder2(BiTree T){
InitStack(S); BiTree p=T; //初始化栈S;p是遍历指针
while(p||IsEmpty(S)){ //栈不空或者p不空时循环
if(p){ //一路向左
visit(p);Push(S,p); //访问当前节点,并入栈
p=p->lchild; //左孩子不空,一直向左走
}
else{ //出栈,并转向出栈节点的右子树
Pop(S,p); //栈顶元素出栈
p=p->rchild; //向右子树走,p赋值为当前节点的右孩子
} //返回while循环继续进入if-else语句
}
}
我们可以看到,visit(p)?语句与?Push(S,p)?语句成对出现,这就代表了先序遍历的序列就是入栈的顺序
接下来是二叉树中序遍历的非递归算法:
viod InOrder2(BiTree T){
InitStack(S); BiTree p=T; //初始化栈S;p是遍历指针
while(p||IsEmpty(S)){ //栈不空或者p不空时循环
if(p){ //一路向左
Push(S,p); //访问当前节点,并入栈
p=p->lchild; //左孩子不空,一直向左走
}
else{ //出栈,并转向出栈节点的右子树
Pop(S,p);visit(p); //栈顶元素出栈
p=p->rchild; //向右子树走,p赋值为当前节点的右孩子
} //返回while循环继续进入if-else语句
}
}
我们可以看到,visit(p)?语句与?Pop(S,p)?语句成对出现,这就代表了中序遍历的序列就是出栈的顺序
故由此我们可以知道,一颗二叉树确定先序序列的二叉树所对应的树的形态个数,可以转化为以此序列为入栈顺序,求解不同的出栈顺序个数,此时用上卡特兰数就可以迅速求解问题答案
|