面試中的二叉樹題目

樹是一種比較重要的數據結構,尤其是二叉樹。二叉樹是一種特殊的樹,在二叉樹中每個節點最多有兩個子節點,一般稱爲左子節點和右子節點(或左孩子和右孩子),並且二叉樹的子樹有左右之分,其次序不能任意顛倒。二叉樹是遞歸定義的,因此,與二叉樹有關的題目基本都可以用遞歸思想解決,當然有些題目非遞歸解法也應該掌握,如非遞歸遍歷節點等等。本文努力對二叉樹相關題目做一個較全的整理總結,希望對找工作的同學有所幫助。

二叉樹節點定義如下:
struct BinaryTreeNode
{
    int m_nValue;
    BinaryTreeNode* m_pLeft;
    BinaryTreeNode* m_pRight;

};


詳細解答

1. 求二叉樹中的節點個數
遞歸解法:
(1)如果二叉樹爲空,節點個數爲0
(2)如果二叉樹不爲空,二叉樹節點個數 = 左子樹節點個數 + 右子樹節點個數 + 1
參考代碼如下:

  1. int GetNodeNum(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL) // 遞歸出口  
  4.         return 0;  
  5.     return GetNodeNum(pRoot->m_pLeft) + GetNodeNum(pRoot->m_pRight) + 1;  
  6. }  
2. 求二叉樹的深度
遞歸解法:
(1)如果二叉樹爲空,二叉樹的深度爲0
(2)如果二叉樹不爲空,二叉樹的深度 = max(左子樹深度, 右子樹深度) + 1
參考代碼如下:
  1. int GetDepth(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL) // 遞歸出口  
  4.         return 0;  
  5.     int depthLeft = GetDepth(pRoot->m_pLeft);  
  6.     int depthRight = GetDepth(pRoot->m_pRight);  
  7.     return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1);   
  8. }  
3. 前序遍歷,中序遍歷,後序遍歷
前序遍歷遞歸解法:
(1)如果二叉樹爲空,空操作
(2)如果二叉樹不爲空,訪問根節點,前序遍歷左子樹,前序遍歷右子樹
參考代碼如下:
  1. void PreOrderTraverse(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL)  
  4.         return;  
  5.     Visit(pRoot); // 訪問根節點  
  6.     PreOrderTraverse(pRoot->m_pLeft); // 前序遍歷左子樹  
  7.     PreOrderTraverse(pRoot->m_pRight); // 前序遍歷右子樹  
  8. }  
中序遍歷遞歸解法
(1)如果二叉樹爲空,空操作。
(2)如果二叉樹不爲空,中序遍歷左子樹,訪問根節點,中序遍歷右子樹
參考代碼如下:
  1. void InOrderTraverse(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL)  
  4.         return;  
  5.     InOrderTraverse(pRoot->m_pLeft); // 中序遍歷左子樹  
  6.     Visit(pRoot); // 訪問根節點  
  7.     InOrderTraverse(pRoot->m_pRight); // 中序遍歷右子樹  
  8. }  
後序遍歷遞歸解法
(1)如果二叉樹爲空,空操作
(2)如果二叉樹不爲空,後序遍歷左子樹,後序遍歷右子樹,訪問根節點
參考代碼如下:
  1. void PostOrderTraverse(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL)  
  4.         return;  
  5.     PostOrderTraverse(pRoot->m_pLeft); // 後序遍歷左子樹  
  6.     PostOrderTraverse(pRoot->m_pRight); // 後序遍歷右子樹  
  7.     Visit(pRoot); // 訪問根節點  
  8. }  

4.分層遍歷二叉樹(按層次從上往下,從左往右)

相當於廣度優先搜索,使用隊列實現。隊列初始化,將根節點壓入隊列。當隊列不爲空,進行如下操作:彈出一個節點,訪問,若左子節點或右子節點不爲空,將其壓入隊列。

  1. void LevelTraverse(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL)  
  4.         return;  
  5.     queue<BinaryTreeNode *> q;  
  6.     q.push(pRoot);  
  7.     while(!q.empty())  
  8.     {  
  9.         BinaryTreeNode * pNode = q.front();  
  10.         q.pop();  
  11.         Visit(pNode); // 訪問節點  
  12.         if(pNode->m_pLeft != NULL)  
  13.             q.push(pNode->m_pLeft);  
  14.         if(pNode->m_pRight != NULL)  
  15.             q.push(pNode->m_pRight);  
  16.     }  
  17.     return;  
  18. }  

6. 求二叉樹第K層的節點個數
遞歸解法:
(1)如果二叉樹爲空或者k<1返回0
(2)如果二叉樹不爲空並且k==1,返回1
(3)如果二叉樹不爲空且k>1,返回左子樹中k-1層的節點個數與右子樹k-1層節點個數之和
參考代碼如下:

  1. int GetNodeNumKthLevel(BinaryTreeNode * pRoot, int k)  
  2. {  
  3.     if(pRoot == NULL || k < 1)  
  4.         return 0;  
  5.     if(k == 1)  
  6.         return 1;  
  7.     int numLeft = GetNodeNumKthLevel(pRoot->m_pLeft, k-1); // 左子樹中k-1層的節點個數  
  8.     int numRight = GetNodeNumKthLevel(pRoot->m_pRight, k-1); // 右子樹中k-1層的節點個數  
  9.     return (numLeft + numRight);  
  10. }  
7. 求二叉樹中葉子節點的個數
遞歸解法:
(1)如果二叉樹爲空,返回0
(2)如果二叉樹不爲空且左右子樹爲空,返回1
(3)如果二叉樹不爲空,且左右子樹不同時爲空,返回左子樹中葉子節點個數加上右子樹中葉子節點個數
參考代碼如下:
  1. int GetLeafNodeNum(BinaryTreeNode * pRoot)  
  2. {  
  3.     if(pRoot == NULL)  
  4.         return 0;  
  5.     if(pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL)  
  6.         return 1;  
  7.     int numLeft = GetLeafNodeNum(pRoot->m_pLeft); // 左子樹中葉節點的個數  
  8.     int numRight = GetLeafNodeNum(pRoot->m_pRight); // 右子樹中葉節點的個數  
  9.     return (numLeft + numRight);  
  10. }  

9. 判斷二叉樹是不是平衡二叉樹
遞歸解法:
(1)如果二叉樹爲空,返回真
(2)如果二叉樹不爲空,如果左子樹和右子樹都是AVL樹並且左子樹和右子樹高度相差不大於1,返回真,其他返回假
參考代碼:

  1. bool IsAVL(BinaryTreeNode * pRoot, int & height)  
  2. {  
  3.     if(pRoot == NULL) // 空樹,返回真  
  4.     {  
  5.         height = 0;  
  6.         return true;  
  7.     }  
  8.     int heightLeft;  
  9.     bool resultLeft = IsAVL(pRoot->m_pLeft, heightLeft);  
  10.     int heightRight;  
  11.     bool resultRight = IsAVL(pRoot->m_pRight, heightRight);  
  12.     if(resultLeft && resultRight && abs(heightLeft - heightRight) <= 1) // 左子樹和右子樹都是AVL,並且高度相差不大於1,返回真  
  13.     {  
  14.         height = max(heightLeft, heightRight) + 1;  
  15.         return true;  
  16.     }  
  17.     else  
  18.     {  
  19.         height = max(heightLeft, heightRight) + 1;  
  20.         return false;  
  21.     }  
  22. }  


13. 由前序遍歷序列和中序遍歷序列重建二叉樹
二叉樹前序遍歷序列中,第一個元素總是樹的根節點的值。中序遍歷序列中,左子樹的節點的值位於根節點的值的左邊,右子樹的節點的值位
於根節點的值的右邊。
遞歸解法:
(1)如果前序遍歷爲空或中序遍歷爲空或節點個數小於等於0,返回NULL。
(2)創建根節點。前序遍歷的第一個數據就是根節點的數據,在中序遍歷中找到根節點的位置,可分別得知左子樹和右子樹的前序和中序遍
歷序列,重建左右子樹。

  1. BinaryTreeNode * RebuildBinaryTree(int* pPreOrder, int* pInOrder, int nodeNum)  
  2. {  
  3.     if(pPreOrder == NULL || pInOrder == NULL || nodeNum <= 0)  
  4.         return NULL;  
  5.     BinaryTreeNode * pRoot = new BinaryTreeNode;  
  6.     // 前序遍歷的第一個數據就是根節點數據  
  7.     pRoot->m_nValue = pPreOrder[0];  
  8.     pRoot->m_pLeft = NULL;  
  9.     pRoot->m_pRight = NULL;  
  10.     // 查找根節點在中序遍歷中的位置,中序遍歷中,根節點左邊爲左子樹,右邊爲右子樹  
  11.     int rootPositionInOrder = -1;  
  12.     for(int i = 0; i < nodeNum; i++)  
  13.         if(pInOrder[i] == pRoot->m_nValue)  
  14.         {  
  15.             rootPositionInOrder = i;  
  16.             break;  
  17.         }  
  18.     if(rootPositionInOrder == -1)  
  19.     {  
  20.         throw std::exception("Invalid input.");  
  21.     }  
  22.     // 重建左子樹  
  23.     int nodeNumLeft = rootPositionInOrder;  
  24.     int * pPreOrderLeft = pPreOrder + 1;  
  25.     int * pInOrderLeft = pInOrder;  
  26.     pRoot->m_pLeft = RebuildBinaryTree(pPreOrderLeft, pInOrderLeft, nodeNumLeft);  
  27.     // 重建右子樹  
  28.     int nodeNumRight = nodeNum - nodeNumLeft - 1;  
  29.     int * pPreOrderRight = pPreOrder + 1 + nodeNumLeft;  
  30.     int * pInOrderRight = pInOrder + nodeNumLeft + 1;  
  31.     pRoot->m_pRight = RebuildBinaryTree(pPreOrderRight, pInOrderRight, nodeNumRight);  
  32.     return pRoot;  
  33. }  
同樣,有中序遍歷序列和後序遍歷序列,類似的方法可重建二叉樹,但前序遍歷序列和後序遍歷序列不同恢復一棵二叉樹,證明略。


點擊打開鏈接

發佈了38 篇原創文章 · 獲贊 11 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章