重建二叉树(Java)

重建二叉树(Java)题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值。链表的结点定义如下:structListNode{ intm_nKey; ListNode*m_pNext;}第一思路:我的第一思路是从头到尾输出类比数组那样,于是乎想把链表中的链表结点的指针反转过来,改变链表的方向,然后实现从头到尾输出(结果为从尾到头输出),可是发现修改链表的指针,反转链表的结构比较麻烦。于是乎放弃。最优…

大家好,又见面了,我是你们的朋友全栈君。

题目:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不包含重复的数字。例如输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1,5, 3, 8, 6},则重建出二叉树并输出它的头结点。二叉树结点的定义如下:

struct BinaryTreeNode{
	int m_nValue;
	BinaryTreeNode* m_pLeft;
	BinaryTreeNode* m_pRight;
}

知识点:

树:除了根结点之外每个结点只有一个父结点,根结点没有父结点;除了叶结点之外所有结点都有一个或多个子结点,叶结点没有子结点。父结点和子结点之间用指针链接。

二叉树:二叉树是树的一种特殊结构,在二叉树中每个结点最多只能有两个子结点。在二叉树中最重要的操作是遍历,即按照某一顺序访问树中的所有结点。树的遍历方式:

前序遍历:先访问根节点,再访问左子结点,最后访问右子结点;(根左右)

中序遍历:先访问左子结点,再访问根结点,最后访问右子结点;(左根右)

后序遍历:先访问左子结点,再访问右子结点,最后访问根结点;(左右根)

前序遍历、中序遍历、后序遍历都可以用递归和循环进行实现。故树的遍历有3种方式6种实现。

宽度优先遍历:先访问树的第一层结点,再访问树的第二层结点……一直到访问到最下面的一层结点。在同一层结点中,以从左到右的顺序依次访问。

二叉搜索树:左子结点总是小于或等于根结点,而右子结点总是大于或等于根结点。(二叉搜索树的搜索时间可以平均在O(logn)的时间内)。

二叉树的特例是红黑树。堆分为最大堆和最小堆。在最大堆中根节点的值最大,在最小堆中根节点的值最小。红黑树是把树中的结点定义为红、黑两种颜色,并通过规则确保从根结点到叶结点的最长路径的长度不超过最短路径的两倍。

解题思路:

题目中给了我们先序遍历和中序遍历;在二叉树的前序遍历中,第一个数字总是树的根结点的值。但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。因此我们需要扫描中序遍历序列,才能找到根结点的值。

题目给出的前序遍历序列的第一个数字1就是根结点的值。扫描中序遍历序列,就能确定根结点的值的位置。根据中序遍历的特点,在根结点的值1前面的3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。

由于在中序遍历序列中,有3个数字是左子树结点的值,因此左子树总共有3个左子结点。同样,在前序遍历的序列中,根结点后面的3个数字就是3个左子树结点的值,再后面的所有数字都是右子树结点的值。这样就在前序和中序遍历的两个序列中,分别找到了左右子树对应的子序列。

我们已经分别找到了左右子树的前序和中序遍历,我们可以用同样的方法分别去构建左右子树,即递归实现。

定义二叉树结构:

public class TreeNode {
        //数据域
	public int data; 
	//左指针域
	public TreeNode left;
	//右指针域
	public TreeNode right;
        //构造带有参数的构造方法
	public TreeNode(int data) {
		this.data = data;
	}
        //重写toString方法
	public String toString() {
		return "TreeNode [data=" + data + ", left=" + left + ", right=" + right
				+ "]";
	}
}

前序和中序重建二叉树的代码:

public TreeNode rebuildBinaryTree(int preorder[], int inorder[]) {
	if (preorder == null || inorder == null) { //如果前序或者中序有一个是空直接返回
		return null;
	}
               // 定义构建二叉树的核心算法
	TreeNode root = rebuildBinaryTreeCore(preorder, 0, preorder.length - 1,
			inorder, 0, inorder.length - 1);
	return root;
}
// 构建二叉树的核心算法
public TreeNode rebuildBinaryTreeCore(int preorder[], int startPreorder,
		int endPreorder, int inorder[], int startInorder, int endInorder) {
	if (startPreorder > endPreorder || startInorder > endInorder) { //停止递归的条件
		return null;
	}
	TreeNode root = new TreeNode(preorder[startPreorder]);
	for (int i = startInorder; i <= endInorder; i++) {
		if (preorder[startPreorder] == inorder[i]) {
			// 其中(i - startInorder)为中序排序中左子树结点的个数
			//左子树
			root.left = rebuildBinaryTreeCore(preorder, startPreorder + 1,
					startPreorder + (i - startInorder), inorder,
					startInorder, i - 1);
			//右子树
			root.right = rebuildBinaryTreeCore(preorder, (i - startInorder)
					+ startPreorder + 1, endPreorder, inorder, i + 1,
					endInorder);

		}
	}
	return root;
}
/*
	4,7,3数量为3个即i-startInorder
 1    2 4 7        3 5 6 8
      4 7 2    1   5 3 8 6

             1
         2       3
      4        5   6
         7   8
*/

测试方法:

public static void main(String[] args) {
	int preorder[] = {1, 2, 4, 7, 3, 5, 6, 8};
	int inorder[] = {4, 7, 2, 1, 5, 3, 8, 6};
	TreeNode treeNode = rebuildBinaryTree(preorder, inorder);
	System.out.println(treeNode);
}

举一反三:

类似的由中序和后序构建二叉树和有前序和中序构建二叉树的思想是类似的。重建二叉树可以有前序和中序推导出来,也可以由中序和后序推导出来。这里实现由中序和后序重建二叉树。

有中序和后序重建二叉树代码:

public static TreeNode rebuildBinaryTree(int[] postorder, int[] inorder) {
	if (postorder == null || inorder == null) {
		return null;
	}
	TreeNode root = rebuildBinaryTreeCore(postorder, 0,
			postorder.length - 1, inorder, 0, inorder.length - 1);
	return root;
}

public static TreeNode rebuildBinaryTreeCore(int[] postorder,
		int startPostorder, int endPostorder, int[] inorder,
		int startInorder, int endInorder) {

	if (startPostorder > endPostorder || startInorder > endInorder) { // 终止递归的条件
		return null;
	}
	TreeNode root = new TreeNode(postorder[endPostorder]);
	for (int i = startInorder; i <= endInorder; i++) {
		if (inorder[i] == postorder[endPostorder]) {
			root.left = rebuildBinaryTreeCore(postorder, startPostorder,
					startPostorder - 1 + (i - startInorder), inorder,
					startInorder, i - 1);
			root.right = rebuildBinaryTreeCore(postorder, startPostorder
					+ (i - startInorder), endPostorder - 1, inorder, i + 1,
					endInorder);
		}
	}
	return root;
}
/*
 *  后序:2  4  3  1          6    7    5
 *  中序:1  2  3  4     5    6    7
 *             5     
 *       1           7
 *           3     6  
 *         2   4   
 */

测试:

public static void main(String[] args) {
	int []inorder = {1, 2, 3, 4, 5, 6, 7};
	int []postorder = {2, 4, 3, 1, 6, 7, 5};
	TreeNode treeNode = rebuildBinaryTree(postorder, inorder);
	System.out.println(treeNode);
}

小思:

这道编程考查对二叉树的遍历的理解程度,只有掌握了二叉树的三种遍历,才可以推导出二叉树的结构;

这道题它的经典之处在于递归,在每次递归时它的经典是把一颗完整的二叉树,分成了左子树、根、右子树,再在每个左右子树中再分,即把大问题转化为局部小问题,最后解决问题。值得学习,递归精髓。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/130472.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • dom4j和jaxp解析工具的

    dom4j和jaxp解析工具的

    2021年12月4日
    31
  • MAX31865模块的使用-基于ZigBee_CC2530芯片 PT100测温

    MAX31865模块的使用-基于ZigBee_CC2530芯片 PT100测温前言  网络上关于ZigBee和MAX31865的相关资料较少,对于如何在CC2530上实现对PT100温度数据的读取的资料更是几乎没有。因此本文对MAX31865芯片和模块的使用进行简要介绍,并提供使用源码,同时提供自制模块的相关原理图。文章目录前言一、相关资料二、MAX31865芯片介绍2.1简介:2.2:读写时序2.3:配置寄存器2.4错误标志2.5温度读取三、MAX31865模块介绍3.1引脚介绍3.2线制选择与接线四、代码4.1配置I/O寄存器4.2SPI写寄存器4.3SPI读寄存

    2022年6月29日
    25
  • django框架菜鸟教程_django框架菜鸟教程

    django框架菜鸟教程_django框架菜鸟教程Django一、介绍1、简介是用python语言写的开源web开发框架,并遵循MVC设计。Django的主要目的是简便、快速的开发数据库驱动的网站。2、特点1)重量级框架2)MVT模式MVC其核心思想是分工、解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性,实现向后兼容。M全拼为Model,主要封装对数据库层的访问,对数据库中的数据进行增、删、改、查操作。…

    2025年10月8日
    2
  • Git教程 Git Bash详细教程「建议收藏」

    Git教程 Git Bash详细教程「建议收藏」  作为一个萌新,我翻遍了网上的GitBash教程,可能因为我理解力比较差,经常看不懂教程上在说什么。(。-`ω´-)所以我决定自己一边摸索一边记录,写教程造福那些理解力跟我一样差的人……第一篇教程会涉及如下内容(按照一般人的使用流程):下载、登录GitBash如何在GitBash中进入或者退出文件夹如何建立本地仓库配置SSHkey如何建立本地仓库和远程仓库的连接…

    2022年4月29日
    40
  • Mybatis常用jdbcType记录[通俗易懂]

    Mybatis常用jdbcType记录[通俗易懂]前言:Java常用的数据类型:https://blog.csdn.net/zhangyong01245/article/details/101310236Mysql常用的数据类型:https://blog.csdn.net/zhangyong01245/article/details/101157289常用数据类型表:MysqljdbcTypeJavatiny…

    2022年10月20日
    2
  • ws 激活码2021【永久激活】

    (ws 激活码2021)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月20日
    284

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号