劍指offer面試題:求二叉樹的映象(遞迴、迴圈解法及測試用例)
題目:給定二叉樹,將其變換為源二叉樹的映象。
二叉樹的定義如下:
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
};
輸入描述:
二叉樹的映象定義:
源二叉樹
8
/ \
6 10
/ \ / \
5 7 9 11
映象二叉樹
8
/ \
10 6
/ \ / \
11 9 7 5
思路:
觀察上面兩個二叉樹,很容易就可以得出下面求一棵樹映象的過程:
先序遍歷這棵樹的每個結點,如果遍歷到的結點有子結點,則交換它的兩個子結點。當交換完所有非葉子結點的左右子結點之後,就得到了樹的映象。
圖製作的有點醜,但是基本可以表達清楚原理了,咳咳,若噴,請輕噴。
方法一:遞迴遍歷法:
//遞迴實現二叉樹的映象,按照先序遍歷,如果遇到空的節點或者葉子節點就返回,否則交換兩個子樹後再改變左右子樹 void MirrorBinaryTree1(BinaryTreeNode* root) { if (root == NULL || (root->leftchild == NULL && root->rightchild == NULL)) { return; } BinaryTreeNode * tmp = root->leftchild; root->leftchild = root->rightchild; root->rightchild = tmp; if (root->leftchild) { MirrorBinaryTree1(root->leftchild); } if (root->rightchild) { MirrorBinaryTree1(root->rightchild); } }
方法二:迴圈壓棧實現二叉樹映象
迴圈壓棧示意圖:
//迴圈實現二叉樹的映象,利用棧的“後進先出”特性列印 void MirrorBinaryTree2(BinaryTreeNode* root) { if (root == NULL) { return; } stack<BinaryTreeNode*> stackTreeNode; stackTreeNode.push(root); while (stackTreeNode.size() > 0) { BinaryTreeNode *parent = stackTreeNode.top(); stackTreeNode.pop(); BinaryTreeNode *Temp = parent->leftchild; parent->leftchild = parent->rightchild; parent->rightchild = Temp; if (parent->leftchild) { stackTreeNode.push(parent->leftchild); } if (parent->rightchild) { stackTreeNode.push(parent->rightchild); } } }
進行功能測試的時候分五種情況:
(1)測試完全二叉樹:除了葉子節點,其他節點都有兩個子節點
8
/ \
6 10
/ \ / \
5 7 9 11
(2) 測試二叉樹:出葉子結點之外,左右的結點都有且只有一個左子結點
8
/
7
/
6
/
5
/
4
(3) 測試二叉樹:出葉子結點之外,左右的結點都有且只有一個右子結點
8
\
7
\
6
\
5
\
4
(4) 測試空二叉樹:根結點為空指標
(5) 測試只有一個結點的二叉樹
完整程式碼及五種測試用例:
#include<iostream>
#include<stack>
using namespace std;
struct BinaryTreeNode
{
int data;
BinaryTreeNode* leftchild;
BinaryTreeNode* rightchild;
BinaryTreeNode(int t)
{
data = t;
leftchild = NULL;
rightchild = NULL;
}
};
void PreorderTravel(BinaryTreeNode* root)
{
if (root == NULL)
{
return;
}
cout <<root->data << " ";
PreorderTravel(root->leftchild);
PreorderTravel(root->rightchild);
}
//遞迴實現二叉樹的映象,按照先序遍歷,如果遇到空的節點或者葉子節點就返回,否則交換兩個子樹後再改變左右子樹
void MirrorBinaryTree1(BinaryTreeNode* root)
{
if (root == NULL || (root->leftchild == NULL && root->rightchild == NULL))
{
return;
}
BinaryTreeNode * tmp = root->leftchild;
root->leftchild = root->rightchild;
root->rightchild = tmp;
if (root->leftchild)
{
MirrorBinaryTree1(root->leftchild);
}
if (root->rightchild)
{
MirrorBinaryTree1(root->rightchild);
}
}
//迴圈實現二叉樹的映象,利用棧的“後進先出”特性列印
void MirrorBinaryTree2(BinaryTreeNode* root)
{
if (root == NULL)
{
return;
}
stack<BinaryTreeNode*> stackTreeNode;
stackTreeNode.push(root);
while (stackTreeNode.size() > 0)
{
BinaryTreeNode *parent = stackTreeNode.top();
stackTreeNode.pop();
BinaryTreeNode *Temp = parent->leftchild;
parent->leftchild = parent->rightchild;
parent->rightchild = Temp;
if (parent->leftchild)
{
stackTreeNode.push(parent->leftchild);
}
if (parent->rightchild)
{
stackTreeNode.push(parent->rightchild);
}
}
}
// ====================測試程式碼====================
// 測試完全二叉樹:除了葉子節點,其他節點都有兩個子節點
// 8
// 6 10
// 5 7 9 11
BinaryTreeNode* root;
void Test1()
{
root = new BinaryTreeNode(8);
root->leftchild = new BinaryTreeNode(6);
root->rightchild = new BinaryTreeNode(10);
BinaryTreeNode* tmp = root->leftchild;
tmp->leftchild = new BinaryTreeNode(5);
tmp->rightchild = new BinaryTreeNode(7);
tmp = root->rightchild;
tmp->leftchild = new BinaryTreeNode(9);
tmp->rightchild = new BinaryTreeNode(11);
cout << "Test1:測試完全二叉樹,除了葉子節點,其他節點都有兩個子節點" << endl;
cout << "原二叉樹的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
MirrorBinaryTree1(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
/*MirrorBinaryTree2(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;*/
}
// 測試二叉樹:出葉子結點之外,左右的結點都有且只有一個左子結點
// 8
// 7
// 6
// 5
// 4
void Test2()
{
root = new BinaryTreeNode(8);
root->leftchild = new BinaryTreeNode(7);
root->rightchild = NULL;
BinaryTreeNode* tmp = root->leftchild;
tmp->leftchild = new BinaryTreeNode(6);
tmp->rightchild = NULL;
tmp = tmp->leftchild;
tmp->leftchild = new BinaryTreeNode(5);
tmp->rightchild = NULL;
tmp = tmp->leftchild;
tmp->leftchild = new BinaryTreeNode(4);
tmp->rightchild = NULL;
cout << "Test2: 測試二叉樹,出葉子結點之外,左右的結點都有且只有一個左子結點" << endl;
cout << "原二叉樹的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
MirrorBinaryTree1(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
/*MirrorBinaryTree2(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;*/
}
// 測試二叉樹:出葉子結點之外,左右的結點都有且只有一個右子結點
// 8
// 7
// 6
// 5
// 4
void Test3()
{
root = new BinaryTreeNode(8);
root->leftchild = NULL;
root->rightchild = new BinaryTreeNode(7);
BinaryTreeNode* tmp = root->rightchild;
tmp->leftchild = NULL;
tmp->rightchild = new BinaryTreeNode(6);
tmp = tmp->rightchild;
tmp->leftchild = NULL;
tmp->rightchild = new BinaryTreeNode(5);
tmp = tmp->rightchild;
tmp->leftchild = NULL;
tmp->rightchild = new BinaryTreeNode(4);
cout << "Test3:測試二叉樹出葉子結點之外,左右的結點都有且只有一個右子結點" << endl;
cout << "原二叉樹的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
MirrorBinaryTree1(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
/*MirrorBinaryTree2(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;*/
}
// 測試空二叉樹:根結點為空指標
void Test4()
{
root = NULL;
cout << "Test4:測試空二叉樹,根結點為空指標" << endl;
cout << "原二叉樹的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
MirrorBinaryTree1(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
/*MirrorBinaryTree2(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;*/
}
// 測試只有一個結點的二叉樹
void Test5()
{
root = new BinaryTreeNode(8);
root->leftchild = NULL;
root->rightchild = NULL;
cout << "Test5:測試只有一個結點8的二叉樹" << endl;
cout << "原二叉樹的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
MirrorBinaryTree1(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;
/*MirrorBinaryTree2(root);
cout << "二叉樹映象後的先序遍歷" << endl;
PreorderTravel(root);
cout << endl;*/
}
int main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
system("pause");
return 0;
}
執行結果:
Test1:測試完全二叉樹,除了葉子節點,其他節點都有兩個子節點
原二叉樹的先序遍歷
8 6 5 7 10 9 11
二叉樹映象後的先序遍歷
8 10 11 9 6 7 5
Test2: 測試二叉樹,出葉子結點之外,左右的結點都有且只有一個左子結點
原二叉樹的先序遍歷
8 7 6 5 4
二叉樹映象後的先序遍歷
8 7 6 5 4
Test3:測試二叉樹出葉子結點之外,左右的結點都有且只有一個右子結點
原二叉樹的先序遍歷
8 7 6 5 4
二叉樹映象後的先序遍歷
8 7 6 5 4
Test4:測試空二叉樹,根結點為空指標
原二叉樹的先序遍歷
二叉樹映象後的先序遍歷
Test5:測試只有一個結點8的二叉樹
原二叉樹的先序遍歷
8
二叉樹映象後的先序遍歷
8
請按任意鍵繼續. . .