求二叉樹中兩個節點最遠的距離
阿新 • • 發佈:2019-02-07
一說到二叉樹,就有很多題目,今天在程式設計之美中看到了二叉樹中兩個節點最遠的距離。所以給想借機寫一篇部落格。
在開始之前,我們先想想,兩個最常節點的最遠距離是怎麼樣的?
情況一:最大距離可能一個在左子樹,一個在右子樹中,通過根節點;
情況二:也可能出現在左/右子樹中,不經過根節點。
大體就是這樣,我們要如何來解決呢?
給大家看看《程式設計之美》中它是如何決解的:
<span style="font-size:24px;">// 資料結構定義 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; } }</span>
這段程式碼有幾個缺點:
1.演算法加入了侵入式(intrusive)的資料nMaxLeft, nMaxRight
2.使用了全域性變數 nMaxLen。每次使用要額外初始化。而且就算是不同的獨立資料,也不能在多個執行緒使用這個函式
3.邏輯比較複雜,也有許多 NULL 相關的條件測試。
<span style="font-size:24px;">void _FindMaxDis(BSTreeNode *pNode, int &deepth, int &maxdis) //這裡的兩個數,我都用的是引用,讀者知道為什麼? { if (pNode==NULL) { deepth=0;maxdis=0; return; } </span>
<span style="font-size:24px;"> int l_deepth=0,r_deepth=0; int l_maxdis=0,r_maxdis=0; if (pNode->m_pleft) FindMaxDis(pNode->m_pleft,l_deepth,l_maxdis); if (pNode->m_pright) FindMaxDis(pNode->m_pright,r_deepth,r_maxdis); deepth = (l_deepth > r_deepth ? l_deepth : r_deepth) + 1; maxdis = l_maxdis > r_maxdis ? l_maxdis : r_maxdis ; maxdis = (l_deepth+r_deepth) > maxdis ? (l_deepth+r_deepth) : maxdis; }</span>
<span style="font-size:24px;">
int FindMaxDis(BSTreeNode *pNode)
{
int deepth, maxdis;
_FindMaxDis(pNode,deepth,maxdis);
return maxdis;
} </span>
其實做做這個題,大體思路都是一致的。但是,我們要考慮很多。在這個方面,推薦讀者去看看《程式碼大全》。
我來說一說這個程式碼的好處吧。
提高了可讀性,另一個優點是減少了 O(節點數目) 大小的侵入式資料,而改為使用 O(樹的最大深度) 大小的棧空間。
本博文只是對二叉樹中兩個節點最遠的距離的解法,做了粗略的概述,如有更好的解法或者不同的看法,請留言。