剑指offer面试题19

来源:互联网 发布:域名交易平台源码 编辑:程序博客网 时间:2024/05/16 00:37

面试题19: 二叉树的镜像

题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。二叉树结点定义如下:

/*******二叉树结点定义*******/struct BinaryTreeNode{int  m_nValue;BinaryTreeNode*   m_pLeft;BinaryTreeNode*   m_pRight;};

预备知识:

二叉树:它的特点是每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点),并且二叉树的子树有左右之分,其次序不能任意颠倒。二叉树可以有5中基本形态,(a)空二叉树;(b)仅有根结点的二叉树;(c)右子树为空的二叉树;(d)左右子树均非空的二叉树;(e)左子树为空的二叉树。

二叉树的性质:

性质1:在二叉树的第i层至多有2^(i-1)个结点(i>=1)

性质2:深度为k的二叉树至多有2^k -1个结点(k>=1)

性质3:对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2 + 1

满二叉树:一棵深度为k且有2^k -1个结点的二叉树称为满二叉树。

完全二叉树:深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。

结点度:结点拥有的子树数称为结点的度。

性质4:具有n个结点的完全二叉树的深度为[ log2(n)] + 1


结点的层次:从根开始定义起,根为第一层,根的孩子为第二层。如果某结点在第L层,那么它的子树的根就在L+1层。

树的深度:树中结点的最大层次,称为树的深度或高度。

森林:m棵互不相交的树的结合。


二叉树的基本操作:

#include "stdafx.h"#include "BinaryTree.h"//创建树结点BinaryTreeNode* CreateBinaryTreeNode(int value){BinaryTreeNode* pNode = new BinaryTreeNode();  //分配内存,返回头指针pNode->m_nValue  = value;  //结点值pNode->m_pLeft = NULL;   //指向左子结点pNode->m_pRight = NULL;  //指向右子结点return pNode;}//链接结点void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight){if(pParent != NULL){pParent->m_pLeft = pLeft;     //左子结点pParent->m_pRight = pRight;   //右子结点}}//输出树的单个结点,同时也输出它的子结点void PrintTreeNode(BinaryTreeNode* pNode){if(pNode != NULL){printf("value of this node is: %d\n", pNode->m_nValue);if(pNode->m_pLeft != NULL)printf("value of its left child is: %d.\n", pNode->m_pLeft->m_nValue);elseprintf("Left child is null.\n");if(pNode->m_pRight !=NULL)printf("value is its right child is: %d.\n", pNode->m_pRight->m_nValue);elseprintf("right child is null.\n");}else{printf("this node is null.\n");}printf("\n");}//遍历树的所有结点,并输出(这里使用了前序遍历:先根结点-左子结点-右子结点)void PrintTree(BinaryTreeNode* pRoot){PrintTreeNode(pRoot);  //先输出根结点if(pRoot !=NULL){if(pRoot->m_pLeft != NULL)PrintTree(pRoot->m_pLeft);if(pRoot->m_pRight != NULL)PrintTree(pRoot->m_pRight);}}//销毁树的所有结点(这里使用了前序遍历,销毁所有的结点)void DestroyTree(BinaryTreeNode* pRoot){if(pRoot != NULL){BinaryTreeNode* pLeft = pRoot->m_pLeft;BinaryTreeNode* pRight = pRoot->m_pRight;delete pRoot;  //根结点pRoot = NULL;DestroyTree(pLeft);  //左子结点DestroyTree(pRight); //右子结点}}



思路:首先绘制图,寻找其中的规律:首先我们先前序遍历这个树的每个结点,如果遍历到的结点有子结点,叫交换它的两个子结点(注意可能结点是NULL的情况)。当交换完所有的非叶子结点的左右子结点后,就得到了树的镜像了。


算法实现:

// 面试题19.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "..\BinaryTree.h"void MirrorRecursively (BinaryTreeNode *pNode){if(pNode == NULL)return;if(pNode->m_pLeft == NULL && pNode->m_pRight == NULL)return;//交换左右结点BinaryTreeNode *pTemp = pNode->m_pLeft;pNode->m_pLeft = pNode->m_pRight;pNode->m_pRight = pTemp;//递归调用if(pNode->m_pLeft)MirrorRecursively(pNode->m_pLeft);if(pNode->m_pRight)MirrorRecursively(pNode->m_pRight);}//**********测试代码*************void Test1(){//创建结点BinaryTreeNode *pNode1 = CreateBinaryTreeNode(8);BinaryTreeNode *pNode2 = CreateBinaryTreeNode(6);BinaryTreeNode *pNode3 = CreateBinaryTreeNode(10);BinaryTreeNode *pNode4 = CreateBinaryTreeNode(5);BinaryTreeNode *pNode5 = CreateBinaryTreeNode(7);BinaryTreeNode *pNode6 = CreateBinaryTreeNode(9);BinaryTreeNode *pNode7 = CreateBinaryTreeNode(11);//链接结点,构造二叉树ConnectTreeNodes(pNode1, pNode2, pNode3);ConnectTreeNodes(pNode2, pNode4, pNode5);ConnectTreeNodes(pNode3, pNode6, pNode7);//前序遍历输出PrintTree(pNode1);//二叉树的镜像MirrorRecursively(pNode1);//处理后输出 printf("*******镜像处理后*******\n");PrintTree(pNode1);}void Test2(){//创建结点BinaryTreeNode *pNode1 = CreateBinaryTreeNode(8);BinaryTreeNode *pNode2 = CreateBinaryTreeNode(6);BinaryTreeNode *pNode3 = CreateBinaryTreeNode(10);//链接结点,构造没有右子树的二叉树ConnectTreeNodes(pNode1, pNode2, NULL);ConnectTreeNodes(pNode2, pNode3, NULL);//前序遍历输出PrintTree(pNode1);//二叉树的镜像MirrorRecursively(pNode1);//处理后输出 printf("*******镜像处理后*******\n");PrintTree(pNode1);}void Test3(){//创建结点BinaryTreeNode *pNode1 = CreateBinaryTreeNode(8);BinaryTreeNode *pNode2 = CreateBinaryTreeNode(6);BinaryTreeNode *pNode3 = CreateBinaryTreeNode(10);//链接结点,构造没有右子树的二叉树ConnectTreeNodes(pNode1, NULL, pNode2);ConnectTreeNodes(pNode2, NULL, pNode3);//前序遍历输出PrintTree(pNode1);//二叉树的镜像MirrorRecursively(pNode1);//处理后输出 printf("*******镜像处理后*******\n");PrintTree(pNode1);}void Test4(){//创建结点BinaryTreeNode *pNode1 = NULL;//前序遍历输出PrintTree(pNode1);//二叉树的镜像MirrorRecursively(pNode1);//处理后输出 printf("*******镜像处理后*******\n");PrintTree(pNode1);}int _tmain(int argc, _TCHAR* argv[]){Test1();Test2();Test3();Test4();return 0;}

注意实现:

在进行编程的时候,一定要注意一些特殊的二叉树,如二叉树为空,二叉树只有一个结点,二叉树没有左子树或二叉树没有右子树的情况。在写代码的之前一定要多花些时间好好的分析,不要急于动手写。可以通过绘图的形式进行分析,找出其中的规律,从而找到解决方案。

0 0
原创粉丝点击