王道书P149-150习题
4.试给出二叉树的自下而上、从右到左的层次遍历算法
思考:就是把层次遍历倒过来,我用了queue+stack,先层次遍历把结果压入栈,而后把栈pop出来就ok~(水题还是要刷的哈哈哈)
代码如下:
void ReverseLevelOrder(BiTree T)
{
queue<BiTree> Q;
stack<BiTree> S;
BiTree p=T;
Q.push(p);//头结点入队
while(!Q.empty())
{
p=Q.front();
S.push(p);
Q.pop();
if(p->lchild)
Q.push(p->lchild);
if(p->rchild)
Q.push(p->rchild);
}
while(!S.empty())
{
p=S.top();
cout<<p->data<<" ";
S.pop();
}
}
结果长这样:
5.非递归实现求二叉树高度
思考:用层次遍历来求。用一个指针last指向遍历的该层的最右元素,出队时与last比较,如果相等,层数level加一,并让last指向下一层的最右结点。
(这题我是看的答案,还是有点糊)
代码如下:
//非递归找二叉树的高度
int FindBiTreeHeight(BiTree T)
{
int start=-1,rear=-1;
int last=0,level=0; //last指向当前层的最右结点
BiTree Q[7];
Q[++rear]=T;//根入队
BiTree p;
while(start<rear) //队不空,循环
{
p=Q[++start];//出队并访问
if(p->lchild) //层次遍历
Q[++rear]=p->lchild;
if(p->rchild)
Q[++rear]=p->rchild;
if(start==last) //如果此时遍历到该层最右一个结点
{
level++; //高度加1
last=rear; //last指向下一层
}
}
return level;
}
6.用先序遍历序列和中序遍历序列构造一个二叉树
思考:先序的第一个元素就是根节点,找到中序遍历序列里该根节点的位置,而后中序遍历序列中左边的元素就是根的左子树,右边的就是右子树,会手画就会写。
代码如下:
//已知先序遍历和中序遍历求二叉树
BiTree PreInCreate(int A[],int B[],int l1,int h1,int l2,int h2)
{ //l1,h1为先序第一和最后一个结点的下标,l2,h2为中序的第一和最后一个结点下标
//一开始l1==l2==1,h1==h2==n
BTNode* root = (BTNode*)malloc(sizeof(BTNode)); //建立根结点
root->data=A[l1]; //根节点为先序遍历第一个结点
int i;
for(i=l2;B[i]!=root->data;i++);//一直找到中序遍历中的根节点下标
int llen=i-l2;//左子树长度
int rlen=h2-i;//右子树长度
//递归建立左子树
if(llen)
{
root->lchild=PreInCreate(A,B,l1+1,l1+llen,l2,l2+llen-1);
}
else
{
root->lchild=NULL;
}
//递归建立右子树
if(rlen)
{
root->rchild=PreInCreate(A,B,l1+llen+1,h1,h2-rlen+1,h2);
}
else
{
root->rchild=NULL;
}
return root;
}
结果如下:
7.判断是否为完全二叉树
思考:就是看空结点后面是否还有非空结点,用层次遍历就行
代码如下:
//判定是否为完全二叉树
bool IsComTree(BiTree T) //用层次遍历的方式,遇到空节点后看后面是否还有结点
{
queue<BiTree> Q;
BiTree p=T;
Q.push(p);
while(!Q.empty())
{
p=Q.front();
Q.pop();
if(p!=NULL)
{
Q.push(p->lchild);
Q.push(p->rchild);
}
else //找到空的
{
while(!Q.empty())
{
p=Q.front();
Q.pop();
if(p) //其后面的结点不为空
return false;
}
}
}
return true;
}
结果如下:
8.计算所有双分支结点个数
思考:我用的层次遍历,判断若有左右子树,计数器就加1,并入队,否则仅仅入队。王道书上给的答案是递归,看起来代码没我这么繁。但是我递归学的不太好,老是忘记出口…emm,还得加油!
我的代码如下:
//计算给定二叉树的所有双分支结点个数
int DoNodes(BiTree T)
{
queue<BiTree> Q;
BiTree p=T;
Q.push(p);
int num=0;
while(!Q.empty())
{
p=Q.front();
Q.pop();
if(p->lchild&&p->rchild)
{
Q.push(p->lchild);
Q.push(p->rchild);
num++;
}
else if(p->lchild&&!p->rchild)
Q.push(p->lchild);
else if(p->rchild&&!p->lchild)
Q.push(p->rchild);
}
return num;
}
王道的代码如下:
//用递归算给定二叉树的所有双分支结点个数
int DsonNodes(BiTree T)
{
if(T==NULL)
return 0;
else if(T->lchild&&T->rchild)
return DsonNodes(T->lchild)+DsonNodes(T->rchild)+1;
else
return DsonNodes(T->lchild)+DsonNodes(T->rchild);
}
结果如下:
9.交换所有结点的左右子树
思考:先交换T结点的左孩子的左右子树,再交换右孩子的左右子树,最后交换T结点(根)的左右子树,出口是节点为空
代码如下:
//所有结点的左右子树交换
void swapBiTree(BiTree T)
{
if(T->lchild)
swapBiTree(T->lchild);
if(T->rchild)
swapBiTree(T->rchild);
BiTree temp;
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
}
结果如下:
2020.04.01
愚人节快乐~!
————————————我是分割线————————————————
13.找两个结点最近公共祖先
思考:这题我看王道上的答案觉得有点繁,后来去LeetCode上看了一个大佬的解法,嗯没错,递归。
先看看代码:
//获得最近公共祖先
BTNode* Nearestcommonancestor(BTNode *root,BTNode *p,BTNode *q)
{
if(root==NULL||root==p||root==q)
return root;
BTNode *ltree=Nearestcommonancestor(root->lchild,p,q);
BTNode *rtree=Nearestcommonancestor(root->rchild,p,q);
if(ltree&&rtree)
return root;
return ltree ? ltree:rtree;
}
从根节点开始递归遍历左右子树,现在有两种情况:
①p,q在同一子树上
②p,q在不同子树里。
如果ltree和rtree中有一个为空,就返回不空的那一个结点,如果两个都不为空,就返回它们的root。
举个栗子:
root=6开始,root!=p或者q,所以找ltree,此时再次进入函数,参数root就为4,root==p,返回4这个结点给上一层的ltree,再执行BTNode *rtree=Nearestcommonancestor(root->rchild,p,q);
这行代码去寻找6这个root的rtree,此时参数root为10,不是要找的p或者q,于是找10的ltree,发现为空,于是10的ltree为NULL,再寻找10的rtree,为12,是我们要找的q,于是10的rtree为12,此时返回给上一层6的rtree为12,也就是找到了rtree,说明p或者q在6的右子树内,所以ltree和rtree同时存在,返回6,也就是最后答案。
14.求非空二叉树的宽度
思考:非递归层次遍历加一个计数器就vans!
ps:这题就是第5题的改版
代码如下:
int GetMaxWeight(BiTree T)
{
int Max=0; //计数器
BiTree p=T;
BiTree Q[6];
int start=-1,rear=-1,last=0; //last总指向该层最右的元素
Q[++rear]=p;
int levelnum=0;
while(start<rear)
{
p=Q[++start];
levelnum++;
if(p->lchild)
Q[++rear]=p->lchild;
if(p->rchild)
Q[++rear]=p->rchild;
if(start==last)
{
Max=Max>=levelnum?Max:levelnum;
last=rear;
levelnum=0;
}
}
return Max;
}
我的答案和王道上的不太一样,我看了一下思路是一样的,但它的看起来严谨一些,代码就不附上了,我觉得能解决问题就行。
15.满二叉树的先序转后序
思考:一般的二叉树只知道先序是不能得到后序,必须知二求一,但是满二叉树就行,它任意一个结点的左右子树的结点数相等,并且先序序列的第一个结点是后序序列的最后一个结点
所以,递归来了!
代码如下:
//满二叉树的先序转后序
void PreToPost(int pre[],int l1,int h1,int post[],int l2,int h2)
{//先序序列第一个结点是后序序列的最后一个结点
int half;
if(h1>=l1)
{
post[h2]=pre[l1];
half=(h1-l2)/2;
PreToPost(pre,l1+1,l1+half,post,l2,l2+half-1);
PreToPost(pre,l1+half+1,h1,post,l2+half,h2-1);
}
}