第五章 树与二叉树
1.若某非空二叉树的先序序列和后序序列正好相反,则该二叉树的形态是什么?
二叉树的先序序列为NLR(根左右),后序序列是LRN(左右根)。要使得NLR=LRN(后序序列反序)则成立。L或R应该为空,这样的二叉树每层只有一个节点,即二叉树的形态是其高度等于节点个数。例如:
2.若某非空二叉树的先序序列和后序序列正好相同,则该二叉树的形态是什么?
二叉树的先序序列是NLR(根左右),后序序列是LRN(左右根)。要使得NLR=LRN成立。所以满足条件的二叉树只有一个根结点。
3.编写后序遍历二叉树的非递归算法
算法思想:后续非递归遍历二叉树是先访问左子树,再访问右子树,最后访问根节点。
①沿着根节点的左孩子,依次入栈,直到左孩子为空。(此时栈内元素依次为A、B、D)
②读栈顶元素:若其右孩子不空且未被访问过,将右孩子转向执行①;否则,栈顶元素出栈并访问。
(必须分清楚返回时是从左子树返回的还是右子树返回的,因此要设置一个辅助指针r,指向最近访问过的结点。也可在结点中增加一个标志域,记录是否已被访问)
栈顶D的右孩子为空,出栈并访问,它是后序序列的第一个结点;栈顶B的右孩子不空且未被访问过,E入栈,栈顶A的右孩子不空且未被访问过,C入栈,栈顶C的左右孩子均为空,出栈并访问;栈顶A的右孩子不空但已被访问,A出栈并访问。由此得到后序序列D E B C A。
void PostOrder(BiTree T){
InitSatck(S);
p = T;
r = NULL;
while(p || !IsEmpty(S)){
if(p){ //走到最左边
push(S,p);
p = p->lchild;
}else{ //向右
GetTop(S,p); //读栈顶元素
if(p->rchild && p->rchild != r) //若右子树存在,且未被访问过,则向右
else{
pop(S,p); //将结点弹出
visit(p->data); //访问该结点
r = p; //记录最近访问过的结点
p = null; //结点访问完后,重置p指针
}
}//else
}//while
}
注:每次出栈访问完一个结点就相当于遍历完以该结点为根结点的子树,需将p置null。
4.试给出二叉树的自下而上,从右到左的层次遍历。
解:一般的二叉树层次遍历是自上而下、从左到右,这里的遍历顺序恰好相反。
算法思想:
利用原有的层次遍历算法,出对的同时将各个结点指针入栈,在所有结点入栈后再从栈顶开始依次访问,即为所求的算法。
①把根结点入队列
②把一个元素出队列,遍历这个元素
③依次把这个元素的左孩子、右孩子入队列
④若队列不空,则跳②,否则结束
void InvertLevel(BiTree bt){
Stack s; Queue Q;
if(bt != null){
InitStack(s); //栈初始化,栈中存放二叉树结点的指针
InitQueue(Q); //队列初始化,队列中存放二叉树结点的指针
EnQueue(Q,bt);
while(IsEmpty(Q) == false){
DeQueue(Q,p);
Push(s,p); //出队,入栈
if(p->lchild) EnQueue(Q,p->lchild); //若左子女不空,则入队列
if(p->rchild) EnQueue(Q,p->rchild); //若右子女不空,则入队列
}
while(IsEmpty(s) == false){
Pop(s,p);
visit(p->data);
}
}
}