關於二叉樹
二叉樹是一種在面試中也會涉及的到數據結構。
一棵二叉樹是結點的一個有限集合,該集合或者為空,或者是由一個根結點加上兩棵分別稱為左子樹和右子樹的、互不相交的二叉樹組成。二叉樹的物種不同的形態如下:
二叉樹的結構定義有三個部分組成,分別是值域val和指向左右孩子的指針*left和*right。
1 struct TreeNode { 2 int val; 3 struct TreeNode *left; 4 struct TreeNode *right; 5 TreeNode(int x) : 6 val(x), left(NULL), right(NULL) { 7 } 8 };
面試題:二叉樹的鏡像
輸入二叉樹,輸出它的鏡像。
分析:
樹的鏡像不是我們所熟知的內容,通常在課本上所熟悉的就是樹的遍歷等基本的操作。但是我們可以通過圖像來把鏡像的過程給描述出來。比如像下面的兩個二叉樹就是互為鏡像。
下面我們來分析,鏡像發生的過程是怎么樣的。
這兩個樹根結點都是1,那么先交換根結點的左右結點,得到圖2。交換后,我們發現,對於結點2和3來說,它們的子結點的左右順序沒有發生變化。因此還要交換對應的結點。對於根結點的左子樹,將其視為一棵新的二叉樹,同樣的交換其子結點。得到圖3。同樣的作用於右子樹,那么最后的交換就完成了。
總結上面的幾個步驟:我們先先序遍歷這個樹的子結點,如果子結點有子結點,那么就交換,當交換完成所有的非葉子結點,那么就是我們所要求的鏡像。
遞歸方法
從上面的分析可以看出,遞歸是解決該問題比較明晰的思路,思考起來也比較能夠想到。下面是遞歸的解決方案。
1 void MirrorRecursively(TreeNode *pRoot) 2 { 3 if((pRoot == NULL) || (pRoot->left == NULL && pRoot->right)) 4 return; 5 6 TreeNode *pTemp = pRoot->left; 7 pRoot->left = pRoot->right; 8 pRoot->right = pTemp; 9 10 if(pRoot->left) 11 MirrorRecursively(pRoot->left); 12 13 if(pRoot->right) 14 MirrorRecursively(pRoot->right); 15 }
非遞歸方法
擴展一下如果,采用循環,如何實現?遞歸的實現借助於棧,那么循環,利用棧即可。下面給出代碼。
void MirrorIteratively(TreeNode* pRoot) { if(pRoot == NULL) return; std::stack<TreeNode*> stackTreeNode; stackTreeNode.push(pRoot); while(stackTreeNode.size() > 0) { TreeNode *pNode = stackTreeNode.top(); stackTreeNode.pop(); TreeNode *pTemp = pNode->left; pNode->left = pNode->right; pNode->right = pTemp; if(pNode->left) stackTreeNode.push(pNode->left); if(pNode->right) stackTreeNode.push(pNode->right); } }
測試用例
寫代碼的時候要考慮到各種情況。包括NULL,只有一個結點,普通二叉樹,二叉樹所有結點只有左結點/右結點等。針對下面幾種情況都要滿足需求。