二叉樹中常見的面試題


1 用一個函數判斷一棵樹是否平衡

題目:實現一個函數檢查一棵樹是否平衡。對於這個問題而言, 平衡指的是這棵樹任意兩個葉子結點到根結點的距離之差不大於1。

注意,對於這道題,要審清題意。它並不是讓你判斷一棵樹是否為平衡二叉樹。平衡二叉樹的定義為:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1, 並且左右兩個子樹都是一棵平衡二叉樹。 而本題的平衡指的是這棵樹任意兩個葉子結點到根結點的距離之差不大於1。(程序員面試金典)

思路:

對於本題,只需要求出離根結點最近和最遠的葉子結點, 然后看它們到根結點的距離之差是否大於1即可。

C++實現代碼:

復制代碼
//求最大高度 int maxDepth(TreeNode root) { if (root == null) { return 0; } return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); } //求最小高度 int minDepth(TreeNode root) { if (root == null) { return 0; } return 1 + Math.min( minDepth(root.left), minDepth(root.right)); } public static boolean isBalanced(TreeNode root){ return (maxDepth(root) - minDepth(root) <= 1); }
復制代碼

2 求二叉樹的深度(劍指offer)

1)遞歸版本

復制代碼
int TreeDepth(BinaryTreeNode* pRoot) { if(pRoot==NULL) return; int nLeft=TreeDepth(pRoot->m_pLeft); int nRight=TreeDepth(pRoot->m_pRight); return (nLeft>nRight)?(nLeft+1):(nRight+1); }
復制代碼

2)非遞歸版本

 

復制代碼
    int maxDepth(TreeNode *root) { if(root==NULL) return 0; queue<TreeNode*> q; q.push(root); int cur=1; int node=0; int level=0; while(!q.empty()) { while(cur) { TreeNode* tmp=q.front(); cur--; q.pop(); if(tmp->left) { node++; q.push(tmp->left); } if(tmp->right) { node++; q.push(tmp->right); } } level++; //每次遍歷完一層之后,層數加1 cur=node; node=0; } return level; }
復制代碼

 

求二叉樹的葉子節點到根的最小高度

復制代碼
int minDepth(BinaryTreeNode *root) { if(root==NULL) return 0; int left=minDepth(root->left); int right=minDepth(root->right); if(left==0&&right==0) return 1; else if(left==0) return right+1; else if(right==0) return left+1; else return min(left,right)+1; }
復制代碼

3 判斷一棵樹是否為平衡二叉樹。(劍指offer)

 方法一:

復制代碼
bool IsBalanced(BinaryTreeNode* root) { if(root==NULL) return true; int left=TreeDepth(root->left); int right=TreeDepth(root->right); int diff=left-right; if(diff>1||diff<-1) return false; return IsBalanced(root->left)&&IsBalanced(root->right); }
復制代碼

方法二:

如果我們用后序遍歷的方式遍歷二叉樹的每一個節點,在遍歷到一個結點之前我們就已經遍歷了它的左右子樹。只要在遍歷每個結點的時候記錄它的深度(某一結點的深度等於它到葉節點的路徑的長度),我們就可以一邊遍歷一邊判斷每個結點是不是平衡的。下面是參考代碼:

復制代碼
bool IsBalanced(BinaryTreeNode* root,int *pDepth) { if(root==NULL) { *pDepth=0; return true; } int left,right; if(IsBalanced(root->left,&left)&&IsBalanced(root->right,&right) { int diff=left-right; if(diff<=1&&diff>=-1) { *pDepth=1+(left>right?left:right); return true; } } return false; }
復制代碼

方法三:

從根節點遞歸向下檢查每顆子樹的高度,我們會通過checkHeight方法,以遞歸方式獲取每個結點左右子樹的高度。若子樹是平衡的,則返回孩子樹的實際高度,若子樹不平衡,則返回-1.

復制代碼
int checkHeight(TreeNode *root) { if(root==NULL) return 0; int leftHeight=checkHeight(root->left); if(leftHeight==-1) return -1; int rightHeight=checkHeight(root->right); if(rightHeight==-1) return -1; int diff=abs(leftHeight-rightHeight); if(diff>1) return -1; else return max(leftHeight,rightHeight)+1; } bool isAVL(TreeNode* root) { if(checkHeight(root)==-1) return false; else return true; }
復制代碼

4 將一顆二叉樹按照先序遍歷順序展開成一個單鏈表。(leetcode)

思路一:

將所有的樹節點按照先序遍歷,並將結果存放在vector中,然后將vector中的結點使用right指針鏈接起來。

C++實現代碼:

 

復制代碼
#include<iostream> #include<new> #include<vector> #include<stack> using namespace std; //Definition for binary tree struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: void flatten(TreeNode *root) { if(root==NULL) return; vector<TreeNode*> vec; preorder(root,vec); TreeNode *tmp=root; size_t i; for(i=1; i<vec.size(); i++) { //一定要記得將左指針置為NULL tmp->left=NULL; tmp->right=vec[i]; tmp=tmp->right; } tmp->left=tmp->right=NULL; } void preorder(TreeNode *root,vector<TreeNode*> &vec) { stack<TreeNode*> s; while(root||!s.empty()) { while(root) { vec.push_back(root); s.push(root); root=root->left; } if(!s.empty()) { root=s.top(); s.pop(); root=root->right; } } } void createTree(TreeNode *&root) { int i; cin>>i; if(i!=0) { root=new TreeNode(i); if(root==NULL) return; createTree(root->left); createTree(root->right); } } }; int main() { Solution s; TreeNode *root; s.createTree(root); s.flatten(root); while(root) { cout<<root->val<<" "; root=root->right; } }
復制代碼

思路二:

將root的右子樹中的鏈接到左子樹的最后一個結點,然后將整個左子樹作為根的右子樹,此時,根只有一顆右子樹,root->left=NULL。然后將root移到右子樹第一個節點,此時是以右子樹為根節點的子樹,重復上面的過程。直到為NULL。

C++實現代碼:

復制代碼
 void flatten(TreeNode *root) { if(root==NULL) return; while(root) { if(root->left) { TreeNode* pre=root->left; while(pre->right) pre=pre->right; pre->right=root->right; root->right=root->left; root->left=NULL; } root=root->right; } }
復制代碼

5 將二叉搜索樹轉換成雙向鏈表。(劍指offer)

思路:

我們可以中序遍歷整棵樹。按照這個方式遍歷,比較小的結點先訪問。如果我們沒訪問一個結點,假設之前訪問過的結點已經調整成一個排序雙向鏈表,我們再把調整當前結點的指針將其連接到鏈表的末尾。當所有結點都訪問過之后,整棵樹也就轉換成一個排序雙向鏈表了。

復制代碼
BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree) { BinaryTreeNode* pLastNodeInList=NULL; ConvertNode(pRootOfTree,&pLastNodeInList); BinaryTreeNode* pHeadOfList=pLastNodeInList; while(pHeadOfList!=NULL&&pHeadOfList->left) pHeadOfList=pHeadOfList->left; return pHeadOfList; } void ConvertNode(BinaryTreeNode* pNode,BinaryTreeNode*&pLastNodeInList) { if(pNode==NULL) return; BinaryTreeNode *pCurrent=pNode; if(pCurrent->left) ConvertNode(pNode->left,pLastNodeInList); pCurrent->left=pLastNodeInList;; if(pLastNodeInList!=NULL) pLastNodeInList->right=pCurrent;
  //pLastNodeInList始終指向鏈表中存在的最后一個元素。 pLastNodeInList=pCurrent; if(pCurrent->right) ConvertNode(pCurrent->right,pLastNodeInList); }
復制代碼

 6 普通二叉樹的創建和排序二叉樹的創建

復制代碼
//一般二叉樹 void createTree(TreeNode *&root) { int i; cin>>i; if(i==0) return; TreeNode *tmp=new TreeNode(i); if(root==NULL) root=tmp; createTree(root->left); createTree(root->right); } //插入 void Insert(TreeNode *&root,int val) { TreeNode* tmp=new TreeNode(val); if(root==NULL) root=tmp; else if(val<root->val) Insert(root->left,val); else if(val>root->val) Insert(root->right,val); else return; } //二叉排序樹 void createSort(TreeNode *&root) { int arr[10]= {8,3,5,1,9,2,6,7,10,4}; for(auto a:arr) Insert(root,a); }
復制代碼

7 二叉樹的遞歸遍歷(前序、中序和后序)

復制代碼
//二叉樹的遍歷(遞歸) void recursivePreorder(TreeNode *root) { if(root) { cout<<root->val<<' '; recursivePreorder(root->left); recursivePreorder(root->right); } } void recursiveInorder(TreeNode *root) { if(root) { recursiveInorder(root->left); cout<<root->val<<' '; recursiveInorder(root->right); } } void recursivePostorder(TreeNode *root) { if(root) { recursivePostorder(root->left); recursivePostorder(root->right); cout<<root->val<<' '; } }
復制代碼

8 二叉樹的非遞歸遍歷(前序、中序、后序和層次遍歷)

復制代碼
//二叉樹遍歷(非遞歸) void preOrder(TreeNode *root) { stack<TreeNode*> st; while(root||!st.empty()) { if(root) { st.push(root); cout<<root->val<<' '; root=root->left; } else { root=st.top(); st.pop(); if(root) root=root->right; } } } void inOrder(TreeNode *root) { stack<TreeNode*> st; while(root||!st.empty()) { while(root) { st.push(root); root=root->left; } if(!st.empty()) { root=st.top(); cout<<root->val<<' '; st.pop(); if(root) root=root->right; } } } void postOrder(TreeNode *root) { TreeNode *cur; TreeNode *pre=NULL; stack<TreeNode*> st; if(root) st.push(root); while(!st.empty()) { cur=st.top(); if(cur->left==NULL&&cur->right==NULL||pre&&(cur->left==pre||cur->right==pre)) { cout<<cur->val<<' '; pre=cur; st.pop(); } else { if(cur->right) { st.push(cur->right); } if(cur->left) { st.push(cur->left); } } } } //層次遍歷 void levelOrder(TreeNode *root) { queue<TreeNode*> q; if(root) q.push(root); int cur=1; while(!q.empty()) { int count=0; while(cur) { TreeNode* tmp=q.front(); cout<<tmp->val<<' '; cur--; q.pop(); if(tmp->left) { q.push(tmp->left); count++; } if(tmp->right) { q.push(tmp->right); count++; } } cout<<endl; cur=count; } }
復制代碼

9 二叉樹葉子節點的數目

復制代碼
//葉子節點的個數 int leafCounts(TreeNode *root) { if(root==NULL) return 0; if(root->left==NULL&&root->right==NULL) return 1; return leafCounts(root->left)+leafCounts(root->right); }
復制代碼

直接求所有節點的總數

 

復制代碼
//節點總數 int counts(TreeNode* root) { if(root==NULL) return 0; int leftCounts=counts(root->left); int rightCounts=counts(root->right); return leftCounts+rightCounts+1; }
復制代碼

10 判斷是否為二叉樹的子結構(劍指offer)

復制代碼
bool isSub(TreeNode* root,TreeNode *sroot) { if(sroot==NULL) return true; if(root==NULL) return false; if(root->val!=sroot->val) return false; return isSub(root->left,sroot->left)&&isSub(root->right,sroot->right); } //二叉樹的子結構 bool isSubStruct(TreeNode *root,TreeNode *sroot) { if(root==NULL||sroot==NULL) return false; bool result=false; if(root->val==sroot->val) result=isSub(root,sroot); if(!result) result=isSubStruct(root->left,sroot); if(!result) result=isSubStruct(root->right,sroot); return result; }
復制代碼

11 判斷是否為鏡像

復制代碼
//二叉樹的鏡像 bool isMirror(TreeNode *rootA,TreeNode *rootB) { if(rootA==NULL&&rootB==NULL) return true; if(rootA==NULL||rootB==NULL) return false; if(rootA->val!=rootB->val) return false; return isMirror(rootA->left,rootB->right)&&isMirror(rootA->right,rootB->left); }
復制代碼

12 判斷是否為完全二叉樹

復制代碼
//判斷是否為完全二叉樹 bool isCompleteTree(TreeNode* root) { if(root==NULL) return true; //tag=0表示還有節點,否則tag=1表示后面不能有節點了 int tag=0; queue<TreeNode*> q; q.push(root); while(!q.empty()) { TreeNode *tmp=q.front(); q.pop(); if(tmp->left&&!tag) q.push(tmp->left); else if(tmp->left&&tag) return false; else if(!tmp->left) tag=1; if(tmp->right&&!tag) q.push(tmp->right); else if(tmp->right&&tag) return false; else if(!tmp->right) tag=1; } return true; }
復制代碼

13 重建二叉樹(劍指offer)

復制代碼
//重建二叉樹 TreeNode* rebulidTree(int *pre,int *in,int len) { if(pre==NULL||in==NULL||len<=0) return NULL; int i; int val=*pre; TreeNode *root=new TreeNode(val); i=0; while(i<len&&in[i]!=val) i++; if(i==len) return NULL; root->left=rebulidTree(pre+1,in,i); root->right=rebulidTree(pre+1+i,in+i+1,len-i-1); return root; }
復制代碼

14 判斷是否為后序遍歷(劍指offer)

復制代碼
//判斷是否為后序遍歷 bool isPostOrder(int *post,int len) { if(post==NULL||len<=0) return false; int val=post[len-1]; int i=0,j; while(i<len-1&&post[i]<val) i++; j=i; while(i<len-1) { if(post[i]<val) return false; i++; } bool left=true; if(j>0) left=isPostOrder(post,j); bool right=true; if(j<len-1) right=isPostOrder(post+j,len-j-1); return left&&right; }
復制代碼

15 二叉樹結點間的最大距離(只是算路徑的長度)參考:http://blog.csdn.net/lalor/article/details/7626678

復制代碼
//二叉樹結點間的最大距離 int maxdistance(TreeNode *root,int &ans) { if(root==NULL) return 0; int left=0; int right=0; //左子樹不為空,返回當前結點到左子樹的最大深度 if(root->left) left=maxdistance(root->left,ans)+1; //右子樹不為空,返回當前結點到右子樹的最大深度 if(root->right) right=maxdistance(root->right,ans)+1; int ret=max(left,right); ans=max(ans,left+right); return ret; } int maxNodeDistance(TreeNode *root) { int ans=0; maxdistance(root,ans); return ans; }
復制代碼

16 二叉樹的最大路徑和(leetcode)

復制代碼
//二叉樹的最大路徑和 int maxPath(TreeNode *root,int &sum) { if(root==NULL) return 0; int ret; int left=maxPath(root->left,sum); int right=maxPath(root->right,sum); ret=max(root->val,max(left,right)+root->val); sum=max(sum,max(ret,left+right+root->val)); return ret; } int maxPathSum(TreeNode* root) { int sum=0; maxPath(root,sum); return sum; }
復制代碼

17 所有路徑和為給定值(leetcode)

復制代碼
//二叉樹路徑和為給定值的所有路徑 void findPath(TreeNode *root,vector<vector<int>> &res,vector<int> &path,int target) { if(root==NULL) return; path.push_back(root->val); if(root->left==NULL&&root->right==NULL&&target==root->val) { res.push_back(path); return; } if(root->left) { findPath(root->left,res,path,target-root->val); } if(root->right) { findPath(root->right,res,path,target-root->val); } path.pop_back(); } vector<vector<int> > pathSum(TreeNode *root,int target) { vector<vector<int> > res; vector<int> path; findParent(root,res,path,target); return res; }
復制代碼

18 二叉樹的最低公共父節點(cc)

復制代碼
bool father(TreeNode* n1,TreeNode* n2) { if(n1==NULL) return false; if(n1==n2) return true; return father(n1->left,n2)||father(n1->right,n2); } //二叉樹的最低公共祖先 TreeNode* findParent(TreeNode *root,TreeNode *n1,TreeNode *n2,TreeNode *&parent) { if(root==NULL) return NULL; if(father(root,n1)&&father(root,n2)) { parent=root; findParent(root->left,n1,n2,parent); findParent(root->right,n1,n2,parent); } return parent; }
復制代碼

 19 判斷一棵樹是否為二叉搜索樹 

復制代碼
int isBST2(struct node* node) { return(isBSTUtil(node, INT_MIN, INT_MAX)); } /* 給定的二叉樹是BST則返回true,且它的值 >min 以及 < max. */ int isBSTUtil(struct node* node, int min, int max) { if (node==NULL) return(true); // 如果不滿足min和max約束,返回false if (node->data<=min || node->data>=max) return(false); // 遞歸判斷左右子樹是否滿足min和max約束條件 return isBSTUtil(node->left, min, node->data) && isBSTUtil(node->right, node->data, max) ); }
復制代碼

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

復制代碼
int getNode(TreeNode *root,int k) { if(root==NULL||k<1) return 0; if(k==1) return 1; int leftNum=getNode(root->left,k-1); int rightNum=getNode(root->right,k-1); return leftNum+rightNum; }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM