重建二叉树(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);
}

小思:

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

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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 错误信息:java.lang.AbstractMethodError

    错误信息:java.lang.AbstractMethodErrorjava.lang.AbstractMethodError:org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose(Ljava/lang/String;Lorg/springframework/cloud/client/loadbalancer/Request;)Lorg/springframework/cloud/client/ServiceInstance;错误信息详细如下:org.springframewo

  • 完美解决:针对tensorflow中,tf.logging.set_verbosity(tf.logging.ERROR)问题。

    完美解决:针对tensorflow中,tf.logging.set_verbosity(tf.logging.ERROR)问题。tf.logging.set_verbosity(tf.logging.ERROR)代码作用:让tensorflow只讲错误信息进行记录。因为Tensorflow2.0移除了一些API,其中就包括logging属性。所以如果你用tensorflow2.0的话,请参考下文解决。解决方法:将此代码更换为:tf.compat.v1.logging.set_verbosity(tf.compat…

    2022年10月31日
  • MySQL——开窗函数

    MySQL——开窗函数

  • Nginx 和 Apache 安装[通俗易懂]

    Nginx 和 Apache 安装[通俗易懂]Nginx和Apache安装Nginx安装Ubuntu下安装CentOS下安装安装依赖下载并解压Nginx创建www用户运行configure文件检测程序编译安装创建软连接在init.d中创建nginx启动Nginx配置防火墙端口Apache安装Ubuntu下安装CentOS下安装安装依赖安装apr安装apr-util安装httpd在init.d中创建软连接启动Nginx安装Ubuntu下安装sudoapt-getinstallnginx–upgr

  • vue 对象判断为空_Vue中可用的判断对象是否为空的方法

    vue 对象判断为空_Vue中可用的判断对象是否为空的方法vue有两个方法可用1.JSON.stringify(evtValue)=='{}’2.Object.keys(xxx).length==0js判断对象是否为空对象的几种方法1.将json对象转化为json字符串,再判断该字符串是否为”{}”vardata={};varb=(JSON.stringify(data)==”{}”);alert(b);//true2…

  • 使用war包部署在Tomcat中运行

    使用war包部署在Tomcat中运行准备工具,Tomcat,eclipse 1选择你要导出的war包,选择你要的项目然后按照我圈起来的去操作 2,然后找到Web包,web下面还有一个WAR.file点击进去,找不到就在上面可以搜索的 3 第一个是你导出去的war包名称,第二个是你war包路径 4 这里我是导入在E盘中的 5把这个war包复制,然后去找你Tomcat的安…

发表回复

您的电子邮箱地址不会被公开。

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