1. 程式人生 > >二叉樹中節點的最大距離

二叉樹中節點的最大距離

問題定義

如果我們把二叉樹看成一個圖,父子節點之間的連線看成是雙向的,我們姑且定義"距離"為兩節點之間邊的個數。寫一個程式求一棵二叉樹中相距最遠的兩個節點之間的距離。

《程式設計之美》的解法

書中對這個問題的分析是很清楚的,我嘗試用自己的方式簡短覆述。

計算一個二叉樹的最大距離有兩個情況:

  • 情況A: 路徑經過左子樹的最深節點,通過根節點,再到右子樹的最深節點。
  • 情況B: 路徑不穿過根節點,而是左子樹或右子樹的最大距離路徑,取其大者。

只需要計算這兩個情況的路徑距離,並取其大者,就是該二叉樹的最大距離。

// 資料結構定義
struct NODE
{
    NODE* pLeft;        // 左子樹
    NODE* pRight;       // 右子樹
    int nMaxLeft;       // 左子樹中的最長距離
    int nMaxRight;      // 右子樹中的最長距離
    char chValue;       // 該節點的值
};
int nMaxLen = 0;
// 尋找樹中最長的兩段距離
void FindMaxLen(NODE* pRoot)
{
    // 遍歷到葉子節點,返回
    if(pRoot == NULL)
    {
        return;
    }
    // 如果左子樹為空,那麼該節點的左邊最長距離為0
    if(pRoot -> pLeft == NULL)
    {
        pRoot -> nMaxLeft = 0; 
    }
    // 如果右子樹為空,那麼該節點的右邊最長距離為0
    if(pRoot -> pRight == NULL)
    {
        pRoot -> nMaxRight = 0;
    }
    // 如果左子樹不為空,遞迴尋找左子樹最長距離
    if(pRoot -> pLeft != NULL)
    {
        FindMaxLen(pRoot -> pLeft);
    }
    // 如果右子樹不為空,遞迴尋找右子樹最長距離
    if(pRoot -> pRight != NULL)
    {
        FindMaxLen(pRoot -> pRight);
    }
    // 計算左子樹最長節點距離
    if(pRoot -> pLeft != NULL)
    {
        int nTempMax = 0;
        if(pRoot -> pLeft -> nMaxLeft > pRoot -> pLeft -> nMaxRight)
        {
            nTempMax = pRoot -> pLeft -> nMaxLeft;
        }
        else
        {
            nTempMax = pRoot -> pLeft -> nMaxRight;
        }
        pRoot -> nMaxLeft = nTempMax + 1;
    }
    // 計算右子樹最長節點距離
    if(pRoot -> pRight != NULL)
    {
        int nTempMax = 0;
        if(pRoot -> pRight -> nMaxLeft > pRoot -> pRight -> nMaxRight)
        {
            nTempMax = pRoot -> pRight -> nMaxLeft;
        }
        else
        {
            nTempMax = pRoot -> pRight -> nMaxRight;
        }
        pRoot -> nMaxRight = nTempMax + 1;
    }
    // 更新最長距離
    if(pRoot -> nMaxLeft + pRoot -> nMaxRight > nMaxLen)
    {
        nMaxLen = pRoot -> nMaxLeft + pRoot -> nMaxRight;
    }
}

這段程式碼有幾個缺點:

1、演算法在二叉樹結構體中加入了侵入式(intrusive)的變數nMaxLeft, nMaxRight

2、使用了全域性變數 nMaxLen。每次使用要額外初始化

3、邏輯比較複雜,也有許多 NULL 相關的條件測試

我的解法:根據最大距離的定義,遞迴求解

//return MaxDistance of t
int MaxDistance(Tree * t)
{
    if (t == 0) return 0;
    int lheight = height(t->left)-1;//-1:邊的數目=節點數目-1
    int rheight = height(t->right)-1;
    int lDis = MaxDistance(t->left);
    int rDis = MaxDistance(t->right);
    return max(lheight + rheight + 2,max(lDis,rDis));//+2:根節點到左右孩子的邊
} 
//returns height of tree with root t
int height(Tree * t){
     if (t == 0)
          return 0;
    return 1 + max(height(t->left),height(t->right));
}
參考資料: