【面试题】二叉树相关面试题

  • 判断二叉树是否是平衡二叉树

    可以分两步实现。第一步先遍历二叉树中的每一个结点node,调用height()求出该结点的左子树高度height(node.left) 和 右子树高度 height(node.right)。根据左右子树的高度差是否满足其绝对值不超过1,第二步看左子树和右子树是否平衡(子问题),判断该树是否为平衡二叉树。

int IsBalanceTree(BTreeNode *pRoot)
{
    if (pRoot == NULL)
        return 1;
    int left = IsBalanceTree(pRoot->pLeft);
    if (left == 0)
        return 0;
    int right = IsBalanceTree(pRoot->pRight);
    if (right == 0)
        return 0;
    int leftH = TreeHeightR(pRoot->pLeft);
    int rightH = TreeHeightR(pRoot->pRight);
    if ((leftH - rightH) <= 1 && (leftH - rightH) >= -1)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}
  • 求二叉树中最远的两个结点间的距离

计算一个二叉树的最大距离有两个情况:

情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。
情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者

对于情况A来说,只需要知道左右子树的深度,然后加起来即可。

对于情况B来说,需要知道左子树的最远距离,或者右子树的最远距离。

只需要计算这两种情况的路径距离,并取其最大值,就是该二叉树的最大距离。

//求二叉树的高度
int TreeHeightR(BTreeNode *pRoot)
{
    if (pRoot == NULL)
        return 0;
    int leftH = TreeHeightR(pRoot->pLeft);
    int rightH = TreeHeightR(pRoot->pRight);
    return leftH > rightH ? (leftH + 1) : (rightH + 1);
}
int Max(int a, int b, int c)
{
    if (a > b&&a > c)
        return a;
    if (b > a&&b > c)
        return b;
    return c;
}
int FarDistance(BTreeNode *pRoot)
{
    if (pRoot == NULL)
        return 0;
    int leftHeight = TreeHeightR(pRoot->pLeft);
    int rightHeight = TreeHeightR(pRoot->pRight);
    int rootPath = leftHeight + rightHeight;
    int leftPath = FarDistance(pRoot->pLeft);
    int rightPath = FarDistance(pRoot->pRight);
    return Max(rootPath, leftPath, rightPath);

}
//优化
int FarDistance2(BTreeNode *pRoot, int *pHeight)
{
    if (pRoot == NULL)
    {
        *pHeight = 0;
        return 0;
    }
    int leftHeight, rightHeight;
    int leftPath = FarDistance2(pRoot->pLeft, &leftHeight);
    int rightPath = FarDistance2(pRoot->pRight, &rightHeight);
    int rootPath = leftHeight + rightHeight;
    *pHeight = leftHeight > rightHeight ? (leftHeight + 1) : (rightHeight + 1);
    return Max(rootPath, leftPath, rightPath);
}
  • 有前序遍历和中序遍历重建二叉树

    一般,前序遍历的第一个数字就是根节点,由根节点的值我们在中序遍历的序列中可以根据根节点的值区分出左子树还有右子树,以及每个子树的结点的数目,然后我们由此在前序遍历的序列中划分出相应的左右子树,进行递归进行。
    构造该二叉树的过程如下:

    1. 根据前序序列的第一个元素建立根结点;
    2. 在中序序列中找到该元素,确定根结点的左右子树的中序序列;
    3. 在前序序列中确定左右子树的前序序列;
    4. 由左子树的前序序列和中序序列建立左子树;
    5. 由右子树的前序序列和中序序列建立右子树。

    这里写图片描述

BTreeNode *CreatTreeByPreAndIn(char preOrder[], int preSize, char inOrder[], int inSize)
{
    if (preSize <= 0)
        return NULL;
    char root = preOrder[0];//在前序中找到根节点
    int i = 0;
    for (i = 0; i < inSize; i++)//在中序中找到根
    {
        if (inOrder[i] == preOrder[0])
        {
            break;
        }
    }
    if (i == inSize)
    {
        assert(0);

    }

    BTreeNode *pRoot = CreateNode(root);
    pRoot->pLeft = CreatTreeByPreAndIn(preOrder + 1, i, inOrder, i);
    pRoot->pRight = CreatTreeByPreAndIn(preOrder + 1 + i, preSize - 1 - i, inOrder + i + 1, inSize - 1 - i);
    return pRoot;
}
  • 二叉树的镜像

从根结点开始,先交换根结点的左右孩子, 然后再依次交换根结点的左右孩子的孩子……

void Mirror(BTreeNode *pRoot)
{
    BTreeNode *pLeft;
    if (pRoot == NULL)
        return NULL;
    if (pRoot->pLeft == NULL&&pRoot->pRight == NULL)
        return NULL;
    pLeft = pRoot->pLeft;
    pRoot->pLeft = pRoot->pRight;
    pRoot->pRight = pLeft;

    Mirror(pRoot->pLeft);
    Mirror(pRoot->pRight);
}
  • 求二叉树中两个结点的最近公共祖先结点

从根节点开始遍历,如果node1和node2中的任一个和root匹配,那么root就是最低公共祖先。 如果都不匹配,则分别递归左、右子树,如果有一个 节点出现在左子树,并且另一个节点出现在右子树,则root就是最低公共祖先. 如果两个节点都出现在左子树,则说明最低公共祖先在左子树中,否则在右子树。

BTreeNode *FindLCA(BTreeNode *pRoot, BTreeNode *n1, BTreeNode *n2)
{
    BTreeNode *left;
    BTreeNode *right;
    if (pRoot == NULL)
        return NULL;
    if (n1 == pRoot || n2== pRoot)
        return pRoot;
    left = FindLCA(pRoot->pLeft, n1, n2);
    right = FindLCA(pRoot->pRight, n1, n2);
    if (left == NULL)
        return right;
    else if (right == NULL)
        return left;
    else
        return pRoot;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值