树的相关笔试面试题

1. 树的创建

已知一个先序遍历数的结果用数组表示, 其中空节点用 null_node 表示, 要求创建出这棵树. 同样采用递归的思想, 先定义一个指针, 指向数组中的第一个元素, 然后给数组的第一个结点创建相应的结点, 然后指针后移, 递归创建根节点的左子树, 递归创建根节点的右子树, 最后返回这个新结点就可以了

TreeNode* TreeCreate(TreeNodeType array[], int size, TreeNodeType null_node)
{
    if(array == NULL)
    {
        return NULL;//非法输入
    }
    if(size == 0)
    {
        return NULL;//非法输入
    }

    if(array[0] == null_node)
    {
        return NULL;//空树
    }
    int index = 0;
    return _TreeCreate(array, size, &index, null_node);
}

TreeNode* TreeClone(TreeNode* root)
{
    if(root == NULL)
    {
        return NULL;//空树
    }
    TreeNode* new_root;
    TreeInit(&new_root);
    new_root = CreateTreeNode(root -> data);
    if(new_root == NULL)
    {
        return NULL;
    }
    //递归创建左子树
    new_root -> lchild = TreeClone(new_root -> lchild);
    //递归创建右子树
    new_root -> rchild = TreeClone(new_root -> rchild);
    return new_root;
}
2. 克隆一棵树

克隆一棵树也采用递归的思想, 先创建一个根节点, 然后递归创建根节点的左子树, 再递归创建根节点的右子树

TreeNode* TreeClone(TreeNode* root)
{
    if(root == NULL)
    {
        return NULL;//空树
    }
    TreeNode* new_root;
    TreeInit(&new_root);
    new_root = CreateTreeNode(root -> data);
    if(new_root == NULL)
    {
        return NULL;
    }
    //递归创建左子树
    new_root -> lchild = TreeClone(new_root -> lchild);
    //递归创建右子树
    new_root -> rchild = TreeClone(new_root -> rchild);
    return new_root;
}
3. 求二叉树的叶子结点数

求二叉树的所有结点数即就是求二叉树的左子树上的结点数加上二叉树的右子树上的结点数, 然后左右字数的结点数相加即就是二叉树的所有叶子结点数

int TreeLeafSize(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    if(root -> lchild == NULL && root -> rchild == NULL)
    {
        return 1;
    }
    return TreeLeafSize(root -> lchild) + TreeLeafSize(root -> rchild);
}
4. 求二叉树的节点数

求二叉树的节点数即就是先判断二叉树是不是只有一个结点, 如果不是, 就递归求解出二叉树的左子树的结点数, 再递归求解二叉树的有子树的结点数, 最后根节点的左右子树之和加1就是二叉树的结点总数

int TreeSize(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    return TreeSize(root -> lchild) + TreeSize(root -> rchild) + 1;
}
5. 求二叉树的高度

如果只有一个根节点, 则二叉树的高度为 1, 否则二叉树的高度就是根节点的左子树和右子树的高度的最大值 加 1

int TreeHeight(TreeNode* root)
{
    if(root == NULL)
    {
        return 0;
    }
    if(root -> lchild == NULL && root -> rchild == NULL)
    {
        return 1;
    }
    int Lhight = TreeHeight(root -> lchild);
    int Rhight = TreeHeight(root -> rchild);
    return 1 + (Lhight > Rhight ? Lhight : Rhight);
}
6. 求某个节点的父节点

如果已知结点和根节点相等, 则直接返回根节点, 否则就递归的在根节点的左子树中找, 如果没有找的就在根节点的右子树中递归的找

TreeNode* Parent(TreeNode* root, TreeNode* node)
{
    if(root == NULL || node == NULL)
    {
        return NULL;
    }
    if(root -> lchild == node || root -> rchild == node)
    {
        return root;
    }
    TreeNode* Lparent = Parent(root -> lchild, node);
    if(Lparent != NULL)
    {
        return Lparent;
    }
    TreeNode* Rparent = Parent(root -> rchild, node);
    return Rparent;
}
7. 销毁一个二叉树

先递归销毁二叉树的左子树, 再递归销毁二叉树的右子树, 最后销毁根节点

void TreeDestroy(TreeNode** root)
{
    if(root == NULL)
    {
        return;
    }
    if(*root == NULL)
    {
        return;//空树
    }
    TreeDestroy(&(*root) -> lchild);
    TreeDestroy(&(*root) -> rchild);
    free(*root);
    *root = NULL;
}
8. 在二叉树中找出给定指的结点

比较根节点的 data 和 to_find 是否相等, 相等就返回根节点, 不相等递归的和根节点的左子树的 data 比较, 最后和根节点的右子树的data比较

TreeNode* TreeFind(TreeNode* root, TreeNodeType to_find)
{
    if(root == NULL)
    {
        return NULL;//空树
    }
    if(root -> data == to_find)
    {
        return root;
    }
    TreeNode* l_node = TreeFind(root -> lchild, to_find);
    if(l_node != NULL)
    {
        return l_node;
    }
    TreeNode* r_node = TreeFind(root -> rchild, to_find);
    return r_node;
}
9. 非递归先序遍历

先定义一个栈, 将根节点入栈, 取栈顶元素到 cur 中, 同时访问当前结点, 将当前结点出栈, 如果当前结点的右子树不为空, 就将当前结点的右子树入栈, 如果当前结点的左子树不为空, 入栈当前结点的左子树, 循环取栈顶元素, 直到栈为空.

void TreePreOrderByLoop(TreeNode* root)
{
    if(root ==NULL)
    {
        return;
    }
    SeqStack stack;
    SeqStackInit(&stack);
    SeqStackPush(&stack, root);
    SeqStackType cur;
    while(SeqStackGetFront(&stack, &cur))
    {
        printf("%c ", cur -> data);
        SeqStackPop(&stack);
        if(cur -> rchild != NULL)
        {
            SeqStackPush(&stack, cur -> rchild);
        }
        if(cur -> lchild != NULL)
        {
            SeqStackPush(&stack, cur -> lchild);
        }
    }
}
10. 非递归中序遍历

先定义一个指针指向该节点, 如果当前结点不为空, 入栈当前结点, 同时让当前结点一直往左走, 直到当前结点为空. 取栈顶结点, 访问当前结点, 出栈. 让当前结点指向它的右子树

void TreeInOrderByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    SeqStack stack;
    SeqStackInit(&stack);
    TreeNode* cur = root;
    while(1)
    {
        while(cur != NULL)
        {
            SeqStackPush(&stack, cur);
            cur = cur -> lchild;
        }
        int ret = SeqStackGetFront(&stack, &cur);
        if(ret == 0)
        {
            return;
        }
        printf("%c ", cur -> data);
        SeqStackPop(&stack);
        cur = cur -> rchild;
    }
}
11. 非递归后序遍历

定义一个指针prev初始化为 NULL来表示访问的上一个结点, 同时定义一个指针 cur 指向该节点, 再定义一个指针 top 表示栈顶结点. 将 cur 入栈, 让当前结点向左走, 直到当前结点为空, 此时取栈顶元素, 如果当前结点 cur -> rchild 和 访问的上一个结点相等, 则访问当前结点, 同时将prev的值赋为访问结点的值, 然后让 cur 等于 cur -> rchild, 一直循环, 直到取栈顶元素失败

void TreePostByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;//空树
    }
    TreeNode* prev = NULL;
    TreeNode* cur = root;
    SeqStackType top;
    SeqStack stack;
    SeqStackInit(&stack);
    while(1)
    {
        while(cur != NULL)
        {
            SeqStackPush(&stack, cur);
            cur = cur -> lchild;
        }
        int ret = SeqStackGetFront(&stack, &top);
        if(ret == 0)
        {
            return;
        }
        if(top -> rchild == NULL || top -> rchild == prev)
        {
            printf("%c ", top -> data);
            prev = top;
            SeqStackPop(&stack);
        }
        else
        {
            cur = top -> rchild;
        }
    }
}
12. 树的镜像
(1)非递归版本

定义一个指针 cur 指向根节点, 定义一个队列, 将 cur 入队列, 取队首元素, 将当前队首元素左右字数进行交换, 出队列, 如果cur -> lchild != NULL, 就将 cur -> lchild 入队列, 如果 cur -> rchild != NULL, cur -> rchild 入队列, 循环上述过程, 直到取栈顶元素失败退出循环就说明当前树已经逆置

void TreeMirrorByLoop(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    SeqQue q;
    SeqQueInit(&q);
    SeqQueType top = root;
    SeqQuePush(&q, root);
    int ret = 0;
    while(SeqQueGetFront(&q, &top))
    {
        TreeNodeSwap(&(top -> lchild), &(top -> rchild));
        SeqQuePop(&q);
        if(top -> lchild != NULL)
        {
            SeqQuePush(&q, top -> lchild);
        }
        if(top -> rchild != NULL)
        {
            SeqQuePush(&q, top -> rchild);
        }
    }
    printf("\n");
}
(2)非递归版本求树的镜像

如果当前树是空树则直接返回, 如果当前树只有一个根节点, 就直接返回, 否则就逆置当前结点的左子树, 逆置当前结点的右子树

void TreeMirror(TreeNode* root)
{
    if(root == NULL)
    {
        return;//空树
    }
    if(root -> rchild == NULL && root -> rchild == NULL)
    {
        return;
    }
    TreeMirror(root -> rchild);
    TreeMirror(root -> lchild);
}
13. 判断二叉树是否为完全二叉树

分为两个阶段, 第一阶段判断当前结点是否具有左右子树, 如果具有左右字数, 就将当前结点左右子树入队列, 如果当前结点只有右子树, 没有左子树, 一定不是右子树, 如果当前结点只有左子树没有右子树, 进入阶段2, 如果当前结点左右子树都没有, 进入第二阶段, 第二阶段就是当前结点的后面结点都没有子树, 一直循环, 如果循环结束, 并且满足上述条件, 则说明这个树是完全二叉树, 否则不是

int IsComPletTree(TreeNode* root)
{
    if(root == NULL)
    {
        return;
    }
    TreeNode* cur = root;
    int start_step_two = 0;
    SeqQue q;
    SeqQueInit(&q);
    SeqQuePush(&q, cur);
    while(SeqQueGetFront(&q, &cur))
    {
        if(start_step_two == 0)
        {
            if(cur -> rchild != NULL && cur -> lchild != NULL)
            {
                SeqQuePush(&q, cur -> rchild);
                SeqQuePush(&q, cur -> lchild);
            }
            if(cur -> lchild == NULL && cur -> rchild != NULL)
            {
                return 0;
            }
            if(cur -> lchild != NULL && cur -> rchild == NULL)
            {
                start_step_two = 1;
            }
            if(cur -> lchild == NULL && cur -> rchild == NULL)
            {
                start_step_two = 1;
            }
        }
        else
        {
            if(cur -> lchild == NULL && cur -> rchild == NULL)
            {
                ;
            }
            else
            {
                return 0;
            }
        }
    }
    return 1;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值