1. 程式人生 > >劍指offer面試題:求二叉樹的映象(遞迴、迴圈解法及測試用例)

劍指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

請按任意鍵繼續. . .