剑指Offer面试题:18.二叉树的镜像
一、题目:二叉树的镜像
题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。例如下图所示,左图是原二叉树,而右图则是该二叉树的镜像。
该二叉树节点的定义如下,采用C#语言描述:
public class BinaryTreeNode
{
public int Data { get; set; }
public BinaryTreeNode leftChild { get; set; }
public BinaryTreeNode rightChild { get; set; } public BinaryTreeNode(int data)
{
this.Data = data;
} public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right)
{
this.Data = data;
this.leftChild = left;
this.rightChild = right;
}
}
二、解题思路
2.1 核心步骤
Step1.先序遍历原二叉树的每个节点,如果遍历到的结点有子结点,就交换它的两个子结点。
Step2.递归遍历每个节点的子节点,同样,如果遍历到的子节点有子节点,就交换它的两个子节点。
当交换完所有非叶子结点的左右子结点之后,就得到了树的镜像。下图展示了求二叉树的镜像的过程:

2.2 代码实现
(1)递归版实现
public static void SetMirrorRecursively(BinaryTreeNode root)
{
if (root == null || (root.leftChild == null && root.rightChild == null))
{
return;
} BinaryTreeNode tempNode = root.leftChild;
root.leftChild = root.rightChild;
root.rightChild = tempNode; if (root.leftChild != null)
{
// 递归调整左子树为镜像
SetMirrorRecursively(root.leftChild);
} if (root.rightChild != null)
{
// 递归调整右子树为镜像
SetMirrorRecursively(root.rightChild);
}
}
(2)循环版实现
public static void SetMirrorIteratively(BinaryTreeNode root)
{
if (root == null)
{
return;
} Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
stack.Push(root); while (stack.Count > )
{
BinaryTreeNode node = stack.Pop(); BinaryTreeNode temp = node.leftChild;
node.leftChild = node.rightChild;
node.rightChild = temp; if (node.leftChild != null)
{
stack.Push(node.leftChild);
} if (node.rightChild != null)
{
stack.Push(node.rightChild);
}
}
}
三、单元测试
为了便于测试,封装了两个辅助方法,设置孩子节点和生成层次遍历的字符串:
/// <summary>
/// 辅助方法:设置root的lChild与rChild
/// </summary>
public void SetSubTreeNode(BinaryTreeNode root, BinaryTreeNode lChild, BinaryTreeNode rChild)
{
if (root == null)
{
return;
} root.leftChild = lChild;
root.rightChild = rChild;
} /// <summary>
/// 辅助方法:生成二叉树元素的字符串用于对比
/// </summary>
public string GetNodeString(BinaryTreeNode root)
{
if (root == null)
{
return null;
} StringBuilder sbResult = new StringBuilder(); Queue<BinaryTreeNode> queueNodes = new Queue<BinaryTreeNode>();
queueNodes.Enqueue(root);
BinaryTreeNode tempNode = null;
// 利用队列先进先出的特性存储节点并输出
while (queueNodes.Count > )
{
tempNode = queueNodes.Dequeue();
sbResult.Append(tempNode.Data); if (tempNode.leftChild != null)
{
queueNodes.Enqueue(tempNode.leftChild);
} if (tempNode.rightChild != null)
{
queueNodes.Enqueue(tempNode.rightChild);
}
} return sbResult.ToString();
}
3.1 功能测试
// 01.测试完全二叉树:除了叶子节点,其他节点都有两个子节点
// 8
// 6 10
// 5 7 9 11
[TestMethod]
public void MirrorTest1()
{
BinaryTreeNode node1 = new BinaryTreeNode();
BinaryTreeNode node2 = new BinaryTreeNode();
BinaryTreeNode node3 = new BinaryTreeNode();
BinaryTreeNode node4 = new BinaryTreeNode();
BinaryTreeNode node5 = new BinaryTreeNode();
BinaryTreeNode node6 = new BinaryTreeNode();
BinaryTreeNode node7 = new BinaryTreeNode(); SetSubTreeNode(node1, node2, node3);
SetSubTreeNode(node2, node4, node5);
SetSubTreeNode(node3, node6, node7); BinaryTreeHelper.SetMirrorIteratively(node1);
string completed = GetNodeString(node1);
Assert.AreEqual(completed,"");
} // 02.测试二叉树:出叶子结点之外,左右的结点都有且只有一个左子结点
// 8
// 7
// 6
// 5
//
[TestMethod]
public void MirrorTest2()
{
BinaryTreeNode node1 = new BinaryTreeNode();
BinaryTreeNode node2 = new BinaryTreeNode();
BinaryTreeNode node3 = new BinaryTreeNode();
BinaryTreeNode node4 = new BinaryTreeNode();
BinaryTreeNode node5 = new BinaryTreeNode(); node1.leftChild = node2;
node2.leftChild = node3;
node3.leftChild = node4;
node4.leftChild = node5; BinaryTreeHelper.SetMirrorIteratively(node1);
string completed = GetNodeString(node1);
Assert.AreEqual(completed, "");
} // 03.测试二叉树:出叶子结点之外,左右的结点都有且只有一个右子结点
// 8
// 7
// 6
// 5
// 4
[TestMethod]
public void MirrorTest3()
{
BinaryTreeNode node1 = new BinaryTreeNode();
BinaryTreeNode node2 = new BinaryTreeNode();
BinaryTreeNode node3 = new BinaryTreeNode();
BinaryTreeNode node4 = new BinaryTreeNode();
BinaryTreeNode node5 = new BinaryTreeNode(); node1.rightChild = node2;
node2.rightChild = node3;
node3.rightChild = node4;
node4.rightChild = node5; BinaryTreeHelper.SetMirrorIteratively(node1);
string completed = GetNodeString(node1);
Assert.AreEqual(completed, "");
}
3.2 特殊输入测试
// 04.测试只有一个结点的二叉树
//
[TestMethod]
public void MirrorTest4()
{
BinaryTreeNode node1 = new BinaryTreeNode(); BinaryTreeHelper.SetMirrorIteratively(node1);
string completed = GetNodeString(node1);
Assert.AreEqual(completed, "");
} // 05.测试空二叉树:根结点为空指针
[TestMethod]
public void MirrorTest5()
{
BinaryTreeNode node1 = null;
BinaryTreeHelper.SetMirrorIteratively(node1);
string completed = GetNodeString(node1);
Assert.AreEqual(completed, null);
}
3.3 测试结果
(1)测试通过情况

(2)代码覆盖率

剑指Offer面试题:18.二叉树的镜像的更多相关文章
- 剑指Offer:面试题19——二叉树的镜像(java实现)
问题描述: 操作给定的二叉树,将其变换为源二叉树的镜像. 二叉树结点定义为: public class TreeNode { int val = 0; TreeNode left = null; Tr ...
- 剑指offer面试题19 二叉树的镜像
题目描述 操作给定的二叉树,将其变换为源二叉树的镜像. 输入描述 二叉树的镜像定义:源二叉树 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树 8 / \ 10 6 / \ / \ ...
- 剑指Offer - 九度1521 - 二叉树的镜像
剑指Offer - 九度1521 - 二叉树的镜像2013-11-30 23:32 题目描述: 输入一个二叉树,输出其镜像. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入 ...
- 剑指offer——面试题18.1:删除链表中重复的节点
// 面试题18(二):删除链表中重复的结点 // 题目:在一个排序的链表中,如何删除重复的结点?例如,在图3.4(a)中重复 // 结点被删除之后,链表如图3.4(b)所示. #include &l ...
- 剑指offer:对称的二叉树(镜像,递归,非递归DFS栈+BFS队列)
1. 题目描述 /** 请实现一个函数,用来判断一颗二叉树是不是对称的. 注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的 */ 2. 递归 思路: /** 1.只要pRoot.left和 ...
- 剑指offer十八之二叉树的镜像
一.题目 操作给定的二叉树,将其变换为源二叉树的镜像.二叉树的镜像定义: 源二叉树 : 8 / \ 6 10 / \ / \ 5 7 9 11 镜像二叉树: 8 / \ 10 6 / \ ...
- 剑指Offer:面试题25——二叉树中和为某一值的路径(java实现)
问题描述: 输入一棵二叉树和一个整数,打印出二叉树中结点指的和为输入整数的所有路径.从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.二叉树结点的定义如下: public class Tree ...
- 剑指Offer:面试题18——树的子结构(java实现)
问题描述: 输入两棵二叉树A和B,判断B是不是A的子结构.二叉树结点的定义如下: public class TreeNode { int val = 0; TreeNode left = null; ...
- [刷题] 剑指offer 面试题18:删除链表节点
要求 给定单向链表的头指针和一个节点指针,在O(1)时间内删除该节点 常规思路:从头节点a开始顺序遍历,发现p指向要删除的节点i,然后把p的m_pNext指向i的下一个节点j,时间复杂度O(n) O( ...
- 剑指offer——面试题18:删除链表的节点
#include"List.h" void DeleteNode(ListNode** pHead,ListNode* pToBeDeleted) { if(*pHead==nul ...
随机推荐
- C 标准库系列之概述
基本上很多编程语言都会提供针对语言本身的一系列的标准库或者包,当然C语言同样也有提供标准库,C语言的标准库是一系列的头文件的集合:如assert.h.ctype.h.errno.h.float.h.l ...
- MySQL和Lucene索引对比分析
MySQL和Lucene都可以对数据构建索引并通过索引查询数据,一个是关系型数据库,一个是构建搜索引擎(Solr.ElasticSearch)的核心类库.两者的索引(index)有什么区别呢?以前写过 ...
- Java源码之 java.util.concurrent 学习笔记01
准备花点时间看看 java.util.concurrent这个包的源代码,来提高自己对Java的认识,努力~~~ 参阅了@梧留柒的博客!边看源码,边通过前辈的博客学习! 包下的代码结构分类: 1.ja ...
- 清理SYSAUX表空间
1.查看SYSAUX表空间中数据分布情况 col SEGMENT_NAME for a30 set lines 999 select * from (select segment_name,PARTI ...
- Beginning Scala study note(8) Scala Type System
1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...
- linux中redis安装
一.登录redis官网下载redis-3.0.7.tar.gz 二.通过ftp工具上传至自己的服务器中 三.tar -zxvf redis-3.0.7.tar.gz解压 四.cd redis-3.0. ...
- react native AsyncStorage的使用
如果现在有一个需求,是要把用户的账号密码保存到本地,大家会怎么做的呢?如果在android中,我相信一大部分人会想到SharedPreferences,这是一个以键值对的形式进行存储的.那如果在rea ...
- Java内存模型及性能优化
最近在做一个项目的性能优化,遇到好多以前没有关注过的性能问题,一头雾水,今天做个笔记,简单记录下JVM相关的参数设置. 一.JVM内存模型 首先介绍下Java程序具体执行的过程: Java源代码文件( ...
- Tsinsen A1493 城市规划(DP + CDQ分治 + NTT)
题目 Source http://www.tsinsen.com/A1493 Description 刚刚解决完电力网络的问题, 阿狸又被领导的任务给难住了. 刚才说过, 阿狸的国家有n个城市, 现在 ...
- 在树霉派上配置LAMP
apache2 配置文件: /etc/apache2/sites-enabled下的000-default.conf <VirtualHost *:> # The ServerName d ...
