`
frank-liu
  • 浏览: 1686244 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

BST reconstruction

 
阅读更多

简介

  根据给定一个二叉树的遍历顺序来构造二叉树是一个经常讨论的问题。这里针对BST,也就是二叉搜索树的一些遍历顺序来构造对应二叉树的场景进行讨论。因为是二叉搜索树,它本身的一些特殊特性使得我们来处理它们的时候有些不同。在之前的文章里有针对二叉树的各种遍历实现进行过讨论,可以作为一并的参考。

 

问题分析

  我们对二叉树的遍历最常用的有如下三种情况,前序、中序和后序遍历。每一种情况对应着我们访问元素的策略的不同,因此它们访问的序列也不同。从本身的定义来说,它们的访问更多的是一种递归的形式。针对二叉搜索树来说,它有一个独特的特性,就是每个节点的值比它的左子树的所有节点值大,同时比它右子树的所有节点小。也就是因为有这个特性,我们才可以根据一些遍历的顺序来重新构造整棵树。

  现在,有几个问题值得我们讨论。是不是所有这几种遍历的序列都可以重新构造出它原来对应的二叉树来呢?如果可以,该怎么来构造?

  首先假设我们有如下定义的树节点:

 

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    public TreeNode(int val) {
        this.val = val;
    }
}

 

根据前序构造BST

  我们都知道,对于二叉树的前序遍历来说,首先遍历的是它的根节点,然后是递归的遍历该节点的左子树,再递归的遍历该节点的右子树。所以对于一个序列来说,它的第一个元素肯定就是这棵树的根。按照原来的定义,我们需要找这个根的左右子节点。

  在这里我们就需要利用到二叉搜索树的特性了。对于它来说,它的根节点的值是肯定大于左子树的,同样也是小于右子树的。所以对于根节点来说,要在后面的序列中找到它的左子节点,就需要去找比本身小的元素。而且根据定义,遍历完这个节点后就需要遍历访问它的左子节点。所以原则上就是该节点后米的那个元素。所以我们只需要判断它后面的那个节点是否小于该节点,如果是则表示找到了目标节点。否则说明这个节点的左子节点不存在。针对这种情况我们需要特殊处理。既然这个值不存在,我们期望的结果就是让原来根节点的左子节点为null。我们可以返回一个特定的值,让程序根据这个值来返回null。

  对于右子节点的查找和推导也类似。我们去查找根节点后面第一个比它大的值。这也是根据前序遍历的定义推导。因为对该节点以及它的左子树遍历完之后才遍历它的右子树。而它和它左子树的节点元素值都小于等于它本身的值。所以只有当碰到比它大的时候才说明访问到它的右子树了。和查找左子节点类似,在没有找到的情况下返回特殊值-1。在程序处理时根据这个值返回null。

  我们将上述的讨论定义成一个递归的过程,于是可以得到如下的实现代码:

 

public TreeNode reconstruct(int[] a) {
		if(a == null || a.length < 1) return null;
		return reconstructRec(a, 0, a.length - 1);
	}

	public TreeNode reconstructRec(int[] a, int cur, int end) {
		if(cur == -1 || cur > end) return null;
		TreeNode node = new TreeNode(a[cur]);
		int left = findL(a, cur);
		int right = findR(a, cur);
		node.left = reconstructRec(a, left, right - 1);
		node.right = reconstructRec(a, right, end);
		return node;
	}

	private int findL(int[] a, int cur) {
		if(cur + 1 < a.length && a[cur] > a[cur + 1]) return cur + 1;
		else return -1;
	}

	private int findR(int[] a, int cur) {
		for(int i = cur + 1; i < a.length; i++) {
			if(a[i] > a[cur]) return i;
		}

		return -1;
	}

 

根据中序构造BST

  对于BST来说,对它的中序遍历则形成一个排序后的序列。但是根据这个排序的序列却不能唯一的确定对应的BST。假定以序列{1, 2, 3}来说,生成它的BST就可能有如下几种情况:

   而对于前面根据前序递归构造BST的问题来说,它可以首先确定根节点。然后在确定根节点的情况下根据本身的值范围特性缩小范围来递归的确定它的子节点。对于中序遍历来说则无法确定唯一的根节点。所以仅仅根据中序遍历的序列并不能唯一的构造BST。

 

根据后序构造BST

  有了前面前序遍历的构造推导,后序遍历的推导也类似。根据它本身的定义, 最后访问到的元素是根节点,所以序列中最后的节点就是根节点。在确定了根节点的情况下,它的左子节点则应该在序列的前面,而且从定义来说应该是从该节点向前碰到的第一个小于它的元素。而求右子节点也类似,就看根节点的前一个元素是否为比它大的元素,是的则为它的右子节点,否则右子节点为空。

  按照这样的思路,我们可以得到如下的代码实现:

 

public TreeNode reconstructByPostOrder(int[] a) {
		if(a == null || a.length < 1) return null;
		return reconstructByPostOrderRec(a, 0, a.length - 1);
	}

	public TreeNode reconstructByPostOrderRec(int[] a, int l, int cur) {
		if(cur == -1 || cur < l) return null;
		TreeNode node = new TreeNode(a[cur]);
		int left = findLeft(a, cur);
		int right = findRight(a, cur);
		node.left = reconstructByPostOrderRec(a, l, left);
		node.right = reconstructByPostOrderRec(a, left + 1, right);
		return node;
	}

	private int findLeft(int[] a, int cur) {
		for(int i = cur - 1; i >= 0; i--) {
			if(a[i] < a[cur]) return i;
		}

		return -1;
	}

	private int findRight(int[] a, int cur) {
		if(cur - 1 >= 0 && a[cur - 1] > a[cur]) return cur - 1;
		else return -1;
	}

 

根据层次遍历顺序构造BST

  还有一个比较有意思的问题就是按层次的顺序遍历二叉树。因为是对应一层层的从左到右遍历二叉树。很明显,第一个节点就是根节点。而对于它的左子节点来说,肯定就是在后续的序列里碰到的比它小的元素。但是仅仅这个是否就足够了呢?假定对于某个子树来说,它当前的节点可能是某个节点的右子节点,这就表明这棵树的所有节点的值肯定会大于某个值了。所以不能仅仅根据一个值来判断节点的选择,需要取这个范围内的最小和最大值两个来确定。

  另外,对于满二叉树来说,它的左右子节点的取值其实是在某个范围的。为了提高程序的查找速度,我们可以用这个左右子节点的值作为限定。这样在后续的查询中可以不用去遍历完整个数组。在实际的示例中,我们还可能有部分节点的左右子节点为空的情况。所以对它们的左右子节点的查找最大也就是我们所计算的那个值了。这个值的计算和前面堆排序里计算左右子节点的方法是一样的,可以看后面详细的代码实现。

  这样,我们可以得到如下的实现代码:

 

public TreeNode reconstructByLevelOrder(int[] a) {
		if(a == null || a.length < 1) return null;
		return reconstructByLevelOrderRec(a, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
	}

	public TreeNode reconstructByLevelOrderRec(int[] a, int cur, int min, int max) {
		if(cur == -1) return null;
		TreeNode node = new TreeNode(a[cur]);
		int left = leftSon(a, min, cur);
		int right = rightSon(a, cur, max);
		node.left = reconstructByLevelOrderRec(a, left, min, a[cur]);
		node.right = reconstructByLevelOrderRec(a, right, a[cur], max);
		return node;
	}

	private int leftSon(int[] a, int min, int cur) {
		int left = cur * 2 + 1;
		int len = Math.min(a.length - 1, left);
		for(int i = cur + 1; i <= len; i++) {
			if(a[i] > min && a[i] < a[cur]) return i;
		}
		return -1;
	}

	private int rightSon(int[] a, int cur, int max) {
		int right = cur * 2 + 2;
		int len = Math.min(a.length - 1, right);
		for(int i = cur + 1; i <= len; i++) {
			if(a[i] > a[cur] && a[i] < max) return i;
		}
		return -1;
	}

 

总结

  因为有了BST的值范围限定特性,我们才能够根据仅仅某些单个的遍历序列唯一的确定一棵树。上面的实现讨论里主要应用了递归的方式。在实际的实现中我们也可以采用一些非递归的方式。可以参照后面的参考材料。这里就不再赘述了。

 

参考材料

http://algs4.cs.princeton.edu/32bst/

http://algorithms.tutorialhorizon.com/construct-binary-search-tree-from-a-given-preorder-traversal-using-recursion/

http://algorithms.tutorialhorizon.com/construct-binary-search-tree-from-a-given-preorder-traversal-using-stack-without-recursion/

 

  • 大小: 14.1 KB
分享到:
评论

相关推荐

    (BST24208,BST24108,BST24201,BST24212)CAN总线通讯板卡

    在本章节中,我们将深入探讨BST24108、BST24208、BST24201以及BST24212这几种型号的CAN总线通讯板卡的主要特点及其应用场景。 #### 二、BST24108 — PCI总线8通道CAN通讯卡 **主要特性:** - **PCI总线接口**:...

    (BST23108,BST23118,BST23208,BST23218,BST23608)串口通讯系列板卡用户手册

    综上所述,BST23X08/BST23X18系列串口通讯板卡凭借其灵活的配置选项、强大的功能以及广泛的兼容性,在工业自动化领域展现出了极高的实用价值。无论是对于初学者还是资深工程师而言,掌握这些核心知识点都是十分必要...

    GBT7714-2005NLang_Upp.bst GBT7714-2005NLang_Up.bst GBT7714-2005NLang.bst

    将bst文件放到MiKTeX的bst文件夹下自己新建的gbt7714-2005文件下,1)作者名称如 KERNER B S 的样式 GBT7714-2005NLang.bst 2)作者名称如 KERNER B S 的样式 GBT7714-2005NLang_UP.bst 3)作者名称如 Kerner B S 的...

    GBT7714-2005NLang.bst样式文件

    《GBT7714-2005NLang.bst样式文件详解与应用》 在学术研究和出版领域,正确引用参考文献是至关重要的。中国国家标准GB/T 7714-2005《文后参考文献著录规则》为中文文献的引用提供了统一规范。其中,`GBT7714-2005...

    BST34211离散量输入/输出卡用户手册

    ### BST34211离散量输入/输出卡用户手册关键知识点 #### 1. 概述 BST34X11是一款专为工业控制领域设计的48路离散量输入/输出卡,支持PCI/CPCI总线标准。该设备由北京神州飞航科技有限责任公司研发并生产,具有强大...

    BST纠偏调试步骤

    ### BST纠偏调试步骤详解 #### 一、纠偏镜头界面解释 纠偏镜头界面是BST纠偏系统的重要组成部分,用于实时监控物料的运行状态,并根据实际情况调整相机参数以达到最佳检测效果。以下是对该界面各部分含义的详细...

    Latex修改参考文献展示方式:修改apsrev4-1.bst文件

    Latex修改参考文献展示方式:修改apsrev4-1.bst文件 Latex是一种基于TeX的排版系统,广泛应用于学术论文、技术文档、图书出版等领域。其中,参考文献的展示方式是 Latex 的一个重要组成部分。本文将介绍如何修改...

    BST纠偏系统调试手册.pdf

    BST纠偏系统调试手册.pdf

    bst-4wd+V4.0发行版1

    根据提供的信息,我们可以了解到这是一份关于bst-4wd+V4.0发行版1的文档,主要关注的是与stm32微控制器相关的硬件设计细节。由于提供的文档内容较为复杂且部分信息不易解读,以下将重点围绕标题、描述以及部分可见...

    bst_example_wincc_step7.rar

    BST(Behavioral State Tree)是西门子推出的一个开源项目,旨在为自动化系统提供图形化编程和控制逻辑设计。在“bst_example_wincc_step7.rar”这个压缩包中,我们看到它结合了BST与西门子的两种强大工具:WinCC...

    数据结构二叉树BST源代码

    二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树数据结构,它具有以下特性: 1. 每个节点包含一个键(key)、一个关联的值、一个指向左子节点的引用和一个指向右子节点的引用。 2. 节点的键大于其左...

    BST物料纠偏系统 ekrPro com40 使用手册

    1. BST 物料纠偏系统概述 BST 物料纠偏系统是一种智能物流系统,旨在提高物流效率和准确性。该系统由 ekrPro com40 控制器和 CCD Pro 传感器组成,能够自动检测和纠偏物料。 2. ekrPro com40 控制器 ekrPro ...

    BST31204CPCI总线64路模拟量输入卡用户手册

    ### BST31204CPCI总线64路模拟量输入卡用户手册知识点解析 #### 产品概述 - **产品名称**:BST31204是一款高性能的CPCI总线模拟量输入卡,主要应用于工业自动化、数据采集和其他需要高精度模拟信号采集的应用场景...

    BST自动纠偏系统.pdf

    BST自动纠偏系统 BST自动纠偏系统是一种基于闭环控制链的自动化系统,旨在确保物料在生产过程中的精确位置控制。该系统由控制器、传感器、推动器和纠偏机构等组件组成。控制器是系统的核心,负责处理来自传感器的...

    BST树的构建与应用

    ### BST树的构建与应用:深入理解二叉排序树 #### 一、基础知识:什么是BST树? BST树,即**二叉搜索树**(Binary Search Tree),是一种特殊的二叉树,其每个节点都满足以下条件: - 节点的左子树只包含键值小于...

    BST.zip_bst

    二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树数据结构,它具有以下特性: 1. 每个节点包含一个键(key)、一个关联的值、一个指向左子节点的引用和一个指向右子节点的引用。 2. 节点的键大于其左子树...

    BST_javaBST_https://bst.91_bstcom_

    二分搜索树(Binary Search Tree,简称BST)是计算机科学中一种重要的数据结构,它是一种自平衡的二叉查找树。在BST中,每个节点都包含一个键(key)、一个关联的值、一个指向左子节点的引用以及一个指向右子节点的...

    BST-V51智能小车底板原理图1

    ### BST-V51智能小车底板电路原理图 #### 一、整体概述 BST-V51智能小车是一款集成了多种传感器与执行器的智能设备,主要用于教育及科研领域。其底板电路原理图展示了该智能小车的核心硬件设计,包括舵机供电模块、...

    BST树节点的插入,删除和查找

    **二叉搜索树(BST,Binary Search Tree)详解** 二叉搜索树是一种特殊的二叉树数据结构,它的每个节点都包含一个键值、一个指向左子节点的指针和一个指向右子节点的指针。在二叉搜索树中,对于任意节点,其左子树...

    bst.rar_bst_bst tree

    二叉搜索树(BST,Binary Search Tree)是一种特殊类型的二叉树,它的每个节点都包含一个键、一个关联的值、一个指向左子节点的引用和一个指向右子节点的引用。在二叉搜索树中,对于每个节点,其左子树中的所有节点...

Global site tag (gtag.js) - Google Analytics