二叉樹系列——二叉樹的最大距離(即相距最遠的兩個葉子節點,程式設計之美,百度面試題)
阿新 • • 發佈:2019-02-04
來自於程式設計之美3.8。
題目:如果我們把二叉樹看做圖,父子節點之間的連線看成是雙向的,我們姑且定義“距離”為兩個節點之間邊的個數。寫一個程式求一棵二叉樹中相距最遠的兩個節點之間的距離。
如下圖所示,樹中相距最遠的兩個節點為A,B,最大距離為6。
書上對這個問題的分析是很清楚的,計算一個二叉樹的最大距離有兩個情況:
情況A: 路徑經過左子樹的最深節點,通過根節點,再到右子樹的最深節點。
情況B: 路徑不穿過根節點,而是左子樹或右子樹的最大距離路徑,取其大者
對於情況A來說,只需要知道左右子樹的深度,然後加起來即可。
對於情況B來說,需要知道左子樹的最遠距離,右子樹的最遠距離。
只需要計算這兩種情況的路徑距離,並取其最大值,就是該二叉樹的最大距離。
情況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) { pRoot->nMaxLeft = ((pRoot->pLeft->nMaxLeft > pRoot->pLeft->nMaxRight) ? pRoot->pLeft->nMaxLeft : pRoot->pLeft->nMaxRight) + 1; } // 計算右子樹最長節點距離 if (pRoot->pRight != NULL) { pRoot->nMaxRight = ((pRoot->pRight->nMaxLeft > pRoot->pRight->nMaxRight) ? pRoot->pRight->nMaxLeft : pRoot->pRight->nMaxRight)+1; } // 更新最長距離 if (pRoot->nMaxLeft + pRoot->nMaxRight > nMaxLen) { nMaxLen = pRoot->nMaxLeft + pRoot->nMaxRight; } }
以上程式碼得新定義一個Node型別,且程式碼比較複雜!
下面是精簡版:
首先我們知道求二叉樹的深度的程式碼是比較簡單的,程式碼如下:
int DepthOfBinaryTree(BinaryTreeNode*pNode){ if (pNode==NULL) { return 0; } else{ //遞迴 return DepthOfBinaryTree(pNode->m_pLeft) > DepthOfBinaryTree(pNode->m_pRight) ? DepthOfBinaryTree(pNode->m_pLeft) + 1 : DepthOfBinaryTree(pNode->m_pRight) + 1; } }
而我們要求的二叉樹的最大距離其實就是求:肯定是某個節點左子樹的高度加上右子樹的高度加2,所以求出每個節點左子樹和右子樹的高度,取左右子樹高度之和加2的最大值即可,假設空節點的高度為-1
程式碼如下:
//改進的版本
int HeightOfBinaryTree(BinaryTreeNode*pNode, int&nMaxDistance){
if (pNode == NULL)
return -1; //空節點的高度為-1
//遞迴
int nHeightOfLeftTree = HeightOfBinaryTree(pNode->m_pLeft, nMaxDistance) + 1; //左子樹的的高度加1
int nHeightOfRightTree = HeightOfBinaryTree(pNode->m_pRight, nMaxDistance) + 1; //右子樹的高度加1
int nDistance = nHeightOfLeftTree + nHeightOfRightTree; //距離等於左子樹的高度加上右子樹的高度+2
nMaxDistance = nMaxDistance > nDistance ? nMaxDistance : nDistance; //得到距離的最大值
return nHeightOfLeftTree > nHeightOfRightTree ? nHeightOfLeftTree : nHeightOfRightTree;
}
上面的函式的引數nMaxDistance返回的就是最大的距離,以下圖作為測試。
輸出如下:
注意:在資料結構與演算法分析這本書上面,樹的深度是不包括根節點的,樹的深度就等於樹的高度,所以上面的函式的返回值是能夠代表樹的深度,也就是高度的!所以在判斷pNode==NULL的時候返回-1。
但是在劍指offer:面試題39,樹的深度包括了根節點,所以在判斷pNode==NULL的時候返回0。
如上圖所示:按劍指offer上面的,深度為4,但是按資料結構與演算法分析,深度則為3!這個需要特別注意。