数据结构-二叉树的相关面试题总结

主要操作是以下:

  • 创建二叉树
  • 克隆二叉树
  • 求二叉树的高度
  • 求二叉树中结点的个数
  • 求二叉树的叶子结点个数
  • 求二叉树中第k层结点的个数
  • 判断一个节点是否在一棵二叉树中
  • 求结点的左孩子
  • 求结点的右孩子
  • 求结点的父结点
  • 求二叉树的镜像(递归与非递归)
  • 判断一棵树是否是完全二叉树
  • 根据先序和中序序列,求出这棵树

创建二叉树

树的定义是递归创建的,所以创建树也可以递归地创建一棵树,首先需要一个序列,按什么顺序来创建,我采用了前序的遍历方式来实现,所以给一个前序的序列,为空的子树给#。

TreeNode* TreeCreate(TreeNodeType array[],size_t size ,size_t* index, TreeNodeType null_node)
{
    if(array==NULL||index==NULL)
    {
        return NULL;
    }
    if(*index>size)
    {
        return NULL;
    }
    TreeNode* root=NULL;
    if(array[*index]!=null_node)
    {
        root=CreatNode(array[*index]);
        ++(*index);
        root->lchild=TreeCreate(array,index,null_node);
        ++(*index);
        root->rchild=TreeCreate(array,index,null_node);
    }
    return root; 
}

克隆二叉树

克隆的思路比较简单,首先创建一个根节点,然后将src的所有结点值依次复制,然后递归的克隆左右子树。

TreeNode* TreeClone(TreeNode* root)
{
    if(root==NULL)
    {
        return NULL;
    }
    TreeNode* dst=CreatNode(root->data);
    dst->data=root->data;
    dst->lchild=TreeClone(root->lchild);
    dst->rchild=TreeClone(root->rchild);
    return dst;

}

求二叉树的高度

求二叉树的高度这个问题用递归来解决,其实非常容易。
要求一个树的高度,可以转换为求它左右子树中高的那棵树的高度+1。以次类推。
这里写图片描述

size_t TreeHeight(TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }
    if(TreeHeight(root->lchild)>TreeHeight(root->rchild))
    {
        return TreeHeight(root->lchild)+1;
    }
    if(TreeHeight(root->lchild)<=TreeHeight(root->rchild))
    {
        return TreeHeight(root->rchild)+1;
    }
    return 0;
}

求二叉树中结点的个数

求结点个数,其实就是求左右子树的结点个数+1。

递归下去就可以解决。
这里写图片描述

size_t TreeSize(TreeNode* root)
{
    if(root==NULL)
    {
        return 0; 
    }
    return TreeSize(root->lchild)+TreeSize(root->rchild)+1;
}

求二叉树的叶子结点个数

叶子结点:左右子树为空的结点就是叶子结点,同样也是采取递归的思路。
这里写图片描述

size_t TreeLeafSize(TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }
    if(root->lchild==NULL&&root->rchild==NULL)
    {
        return 1;
    }
    return TreeLeafSize(root->lchild)+TreeLeafSize(root->rchild);
}

求二叉树第k层结点的个数

求二叉树第k层结点的个数,可以转换为求左右子树的第k-1层结点的个数。
这里写图片描述

size_t TreeKLevelSize(TreeNode* root, int K)
{
    if(root==NULL||K<1)
    {
        return 0;
    }
    if(K==1)
    {
        return 1;
    }
    return TreeKLevelSize(root->lchild,K-1)+TreeKLevelSize(root->rchild,K-1);

}

判断一个结点是否在二叉树中

采用先序遍历的思路。
先访问该节点,再遍历左子树,再遍历右子树。
此时的访问操作:就是比较。


TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find)
{
    if(root==NULL)
    {
        return NULL;
    }
    if(to_find==root->data)
    {
        return root;
    }
    TreeNode* ret1 = TreeFind(root->lchild,to_find);
    TreeNode* ret2 = TreeFind(root->rchild,to_find);
    return ret1 != NULL ? ret1 : ret2;
}

求二叉树的父结点,左孩子,右孩子

TreeNode* LChild(TreeNode* node)
{
    if(node==NULL)
    {
        return NULL;
    }
    return node->lchild;
}
TreeNode* RChild(TreeNode* node)
{
    if(node==NULL)
    {
        return NULL;
    }
    return node->rchild;
}
TreeNode* Parent(TreeNode* root, TreeNode* node)
{
    if(root==NULL)
    {
        return NULL;
    }
    if(root->lchild==node||root->rchild==node)
    {
        return root;
    }
    TreeNode* lresult=Parent(root->lchild,node);
    TreeNode* rresult=Parent(root->rchild,node);

    return lresult!=NULL?lresult:rresult;
}

求二叉树的镜像

思路与二叉树的遍历相同,只是此时的访问动作变成了交换左右子树。
非递归的求法只需要采用层序遍历的方式即可。也可以采用非递归遍历的任何一种方法都可以。

void TreeMirror(TreeNode* root)
{
    if(root==NULL)
    {
        return;
    }
    Swap(&root->lchild,&root->rchild);
    TreeMirror(root->lchild);
    TreeMirror(root->rchild);
}
void TreeMirrorByLoop(TreeNode* root)
{
    if(root==NULL)
    {
        return;
    }
    SeqQueue q;
    SeqQueueInit(&q);
    SeqQueuePush(&q,root);
    while(1)
    {
        SeqQueType front;
        int ret=SeqQueueTop(&q,&front);
        if(ret==0)
        {
            return;
        }
        Swap(&root->lchild,&root->rchild);
        SeqQueuePop(&q);
        if(root->lchild!=NULL)
        {
            TreeMirrorByLoop(root->lchild);
        }
        if(root->rchild!=NULL)
        {
            TreeMirrorByLoop(root->rchild);
        }
    }

}

判断一个树是否是完全二叉树

首先要清楚,完全二叉树的描述思路:
这里写图片描述
遍历结束,满足以上条件的就是完全二叉树。

int IsCompleteTree(TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }
    SeqQueue q;
    SeqQueueInit(&q);
    SeqQueuePush(&q,root);
    TreeNode* front=NULL;
    int if_start_step2_flag=0;
    //层序遍历
    while(SeqQueueTop(&q,&front))
    {
        SeqQueuePop(&q);
        //阶段一:任何一个节点同时具备左右子树,一旦发现某个结点不具备该条件,进行以下判断:
        if(if_start_step2_flag==0)
        {
            if(front->lchild!=NULL&&front->rchild!=NULL)
            {
                SeqQueuePush(&q,front->lchild);
                SeqQueuePush(&q,front->rchild);
            }
            //  a)当前结点只有右子树,一定不是完全二叉树
            else if(front->rchild!=NULL&&front->lchild==NULL)
            {
                return 0;
            }
            //  b)如果当前结点只有左子树,进入阶段二
            else if(front->lchild!=NULL&&front->rchild==NULL)
            {
                if_start_step2_flag=1;
                SeqQueuePush(&q,front->lchild);
            }
            //  c)如果当前结点没有子树,进入阶段二
            else
            {
                if_start_step2_flag=1;
            }
        }
        else
        {
            //阶段二:
            //任何一个节点都必须没有子树
            if(front->lchild==NULL&&front->rchild==NULL)
            {
                ;
            }
            else
            {
                return 0;
            }
        }

    }
    return 1;
}

给出先序和中序序列,求出这棵树

思路:首先通过遍历先序序列,可以在中序序列中找到该子树的左右子树区间,然后递归地去创建左子树和右子树。

int Find(TreeNodeType in_order[],size_t in_order_left,size_t in_order_right,TreeNodeType value)
{
    size_t i=0;
    for(i=in_order_left;i<in_order_right;i++)
    {
        if(in_order[i]==value)
        {
            return i;
        }
    }
    return -1;
}
TreeNode* _TreeRebuild(TreeNodeType pre_order[],size_t size,size_t* pre_order_index,
                       TreeNodeType in_order[],size_t in_order_left,size_t in_order_right)
{
    if(in_order_left>=in_order_right)
    {
        return NULL;
    }
    if(pre_order==NULL||in_order==NULL||size==0)
    {
        return NULL;
    }
    if(pre_order_index==NULL)
    {
        return NULL;
    }
    //根据先序序列遍历结果创建结点
    TreeNode* new_node=CreatNode(pre_order[*pre_order_index]);
    (*pre_order_index)++;
    //查找当前结点在中序序列中的位置
    size_t cur_root_in_order_index=Find(in_order,in_order_left,in_order_right,new_node->data);
    assert(cur_root_in_order_index!=(size_t)-1);
    //递归地创建左子树
    new_node->lchild=_TreeRebuild(pre_order,size,pre_order_index,in_order,in_order_left,cur_root_in_order_index);
    //递归地创建右子树
    new_node->rchild=_TreeRebuild(pre_order,size,pre_order_index,in_order,cur_root_in_order_index+1,in_order_right);

    return new_node;
}
TreeNode* TreeRebuild(TreeNodeType pre_order[],TreeNodeType in_order[],size_t size)
{
    if(pre_order==NULL||in_order==NULL)
    {
        return NULL;
    }
    size_t pre_order_index=0;

    size_t in_order_left=0;
    size_t in_order_right=size;

    return _TreeRebuild(pre_order,size,&pre_order_index,in_order,in_order_left,in_order_right);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值