数据结构复习(四)树与二叉树的一些习题(不定期更新)

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();
    }
}

结果长这样:
第4题结果

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;
}

结果如下:
第6题结果

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;

}

结果如下:
第7题结果

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);
}

结果如下:
第8题结果

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;
}

结果如下:
第9题结果

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);
    }
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值