1. 程式人生 > >【面試題】二叉樹相關面試題

【面試題】二叉樹相關面試題

  • 判斷二叉樹是否是平衡二叉樹

    可以分兩步實現。第一步先遍歷二叉樹中的每一個結點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;
}