BST(Binary Search Tree)

基本特点:

  • 二叉树
  • 集合中的数据具有可比较大小的关键码
  • 数据之间满足BST特性
  • 中序遍历可得到一个递增的数据序列(可作为判断一棵二叉树是否是BST的方法)
  • 同一个数据集合,可存在多个不同形态的BST树

基本操作

  • 问题描述+求解动机+算法思想+算法步骤+性能分析
  • 进行操作,都需要:先找到要操作的数(位置),进行操作,保证BST的特性,保障优的算法性能。
查找(logn) 插入(logn ~ n)
若给定值小于根结点的关键字,则继续 在子树上进行查找 若给定值小于根结点的关键字,则继续在子树上进行插入; 将返回值(结点指针)设置为(当前)根结点的左孩子
若给定值大于根结点的关键字,则继续 在子树上进行查找 若给定值大于根结点的关键字,则继续在子树上进行插入; 将返回值(结点指针)设置为(当前)根结点的右孩子
若给定值等于根结点的关键字,则查找 成功 /

  删除操作:

  从最简单的情况开始——删除最小值

由BST特性可知,BST中最小值一定在左子树的最左边取到,于是去get到它。

BST删除最小值算法思想(非递归)

1)定义一个指向BST树结点的临时指针变量p和pp。

2)从BST的根结点开始;将其值赋值给p。

3)若p的左孩子不等于空指针,将p的值赋值给pp;然后,将p的左孩子指针的值赋值给p;

4)重复第3步,直至p的左孩子的值等于空,结束查找。

5)p所指结点即为最小值结点。

6)若最小值结点不是根结点(BST根结点的左孩子不为空),则将p的右孩子指针作为pp的左孩子,否则将根结点的右孩子作为新的根结点。

算法分析

BST的最小值结点,从根结点的左孩子开始, 第一个左孩子为空的结点。

算法的步骤分为查找和接入。

  • BST删除最小值的时间复杂度等于查找时间复杂度。
  • 如果二叉树是平衡的,则有n个结点的二叉树 的高度约为logn,但是,如果二叉树完全不平衡(如成一个链表的形状),则其高度可以达到n。

BST删除算法思想

  • 定位到待删除结点,此时有三种情况,设要删除结点为x,其父节点为px

      1) 无子节点:直接将该 px->child 置空;

      2) 有一个子节点:px->child = px->child->child;

      3) 有两个子节点:找到X结点右子树中的最值结点(后继结点)或者是左子树中的最值(前驱节点),交换X结点的值和该节点的值(实际上实现了两个结点的互换),删除该结点,设置被删除结点的地址为该结点右子树的的最小值地址。
  • 此时要注意的是,这里指的删除是指删除某一个值,而不是非要删除这个结点(用其他结点代替它被删除也行,反正值不会再出现在二叉树中了)。

# Heap
堆树或是一棵空树,或是具有下列性质的一棵**完全二叉树**(堆的局部有序特性):

  1. 每一个结点存储的值都小于等于其子节点存储的值——最小值堆(小顶堆)
  2. 每一个结点存储的值都大于等于其子节点存储的值——最大值堆(大顶堆)

    由于是完全二叉树,用顺序表就十分方便存储

    同一个数据集合,可以存在多个不同形态的堆

基本操作

插入:插入新值,新增结点,保持堆特性,算法代价要小

  在哪最容易插入呢?叶子结点 最后的那个

算法思想

均以最大值堆为例

  • 在堆的末尾新增一个结点,存放新元素值val;
  • 对其进行调整以维持堆的特性:

      1.若它大于父节点的值,则将其与父节点交换,继续进行比较;

      2.若它小于等于父节点的值或者是根节点了,则已处在正确位置,结束。

**算法分析**

  • 堆的插入操作,插入结点都是作为一个叶子 结点插入到堆中。
  • 算法的步骤分为插(接)入和交换值。
  • 接入过程不需要移动结点,也不会整体改动树,所以时间开销为常数。
  • 堆的插入时间复杂度取决于交换的次数。
  • 堆是完全二叉树,则有n个结点的堆的高度为logn。插入新元素时,最佳情况时不用交换,最差情况交换logn,平均情况为logn。

构建

  1. 逐个插入法:新建一棵空堆,然后把数据集中的n个元素依次取出,逐个执行堆的 插入基本操作。
  2. 交换法建堆:新建一棵有n个结点的完全二叉树;然后把数据集中的n个元素任意的存储到完全二叉树中;判断完全二叉树中所有的父子结点对,若父结点中的元素值小于子结点中的元素值,则交换,直至完全二叉树满足堆的性质。

      仅对第二种方法进行介绍。

交换法建堆算法思想

先要掌握调整结点的两种方法:向上调整and向下调整

  • 向上调整(上拉):将要调整的结点x与其父节点进行比较,若比其大,则将这俩交换位置,再继续将x与现在的父节点进行比较;直至x为根节点或x小于等于其父节点的值为止。
  • 向下调整(下拉):将要调整的结点x与其两个子节点进行比较,若小于它们,则取其中较大的那个与x交换,继续将x与其子节点进行比较;直至x大于它两个子节点的值或者为叶节点为止。

掌握了上面两种方法,那么建堆就容易了。
简述思路:
1. 直接将要存的数据按输入顺序存放到数组中;
2. **从[n/2]号位开始倒着枚举,对每个遍历到的结点i进行[i,n]范围内的调整**
  为什么倒着枚举呢?
  首先说为什么从[n/2]号位开始吧,因为其叶节点无法向下调整了,只需对所有非叶节点进行调整即可;
  每一次调整都**将一个结点调整到了合适的位置,也就是说,以该节点为根结点的树已经满足了堆的特性,当前子树中权值最大的结点就会处在根节点的位置,这样当遍历到其父亲结点时,就可以直接使用这个结果**。

   这种做法保证每个结点都是以其为根节点的子树中的权值最大的结点。

删除

  同样,我们先讨论最简单的情况——删除堆中最大值。

   由堆的性质可知,堆的最大值就是根节点,那么就删除第一个元素就可以了。那怎么删?

算法思想

  • 在堆树中找到保存最大值的结点

     1)最大值堆的最大值结点是最大值堆树的根结点。
  • 删除最大值

     2)保存最大值,交换堆的根结点的(最大)值与堆的最后一个 结点的值,堆的元素个数减一。
  • 保持树的堆特性

     若新树不空,对新的根结点的值R ,执行下拉(shiftdown)操作

     3)R的值大于或等于其两个子结点,此时堆结构已经完成;

     4)R的值小于某一个或全部两个子结点的值,此时R应与两个子结点中值较大的一个交换,若R仍然小于其新子结点的一个或两个。在这种情况下,只需要简单地继续这种将“R拉下来” 的过程,直至到达某一层使它大于它的子结点,或者它成为叶结点。

算法分析

  • 删除最大值堆的最大值,即删除最大值堆的根结点
  • 如果基于数组实现最大值堆,最大值在数组 的基地址。
  • 算法的步骤分为交换和维持堆性质
  • 堆删除最大值的时间复杂度等于对根结点执行一次下拉操作的时间复杂度。
  • 堆是完全二叉树,则有n个结点的堆的高度为logn。下拉根结点时,最佳情况时不用交换,最差情况交换logn,平均情况为logn。

删除算法

算法思想

  • 在堆树中找到保存被删除的值结点

     1)遍历最大值堆树,查找被删除的值,记住值的结点地址。 删除该值

     2)交换堆的结点的值与堆的最后一个结点的值,堆的元素个数减一。
  • 保持新树的堆特性

     3)这个结点位置新的值,可能比父结点的值大,要向上交换,直到 其小于或等于其父结点的值,或达到根结点位置

     4)然后这个值(新的位置)很可能比它的另一个子树的结点小,要执行下拉(shiftdown)操作:

      4.1)R的值大于或等于其两个子结点,此时堆结构已经完成;

      4.2)R的值小于某一个或全部两个子结点的值,此时R应与两个子 结点中值较大的一个交换,若R仍然小于其新子结点的一个或两个。在这种情况下,只需要简单地继续这种将“R拉下来”的过程,直至到达某一层使它大于它的子结点,或者它成为叶结点。

算法分析

  • 删除最大值堆的某个值。
  • 算法的步骤分为查找,交换和维持堆性质。
  • 如果基于数组实现最大值堆,堆删除值的时间复杂度取决于查找,交换和维持堆性质的的时间复杂度。
  • 堆是完全二叉树,则有n个结点的堆的高度为 logn。堆的查找操作时间复杂度为O(n),交换 的时间开销是常数,维持堆性质的上推和下拉操作的时间复杂度为O(logn),所以堆删除操作的时间复杂度为O(logn)

  那么我们来思考一下,为什么插入的时候将元素放到末尾只需将元素向上调整,而删除的时候,交换待删的元素与最后一个,需要向上调整再向下调整呢?为什么多了一步?

  其实仔细想想还是比较容易想到的。插入的时候,原有的堆就已经具有堆的特性,只是在最后加了一个元素需要调整。举个例子,就是说上面的所有父节点的值都大于两个子节点的值,一旦大于父节点,毫不犹豫需要上移且不可能需要再次下移

  而删除的时候,由于最后一个元素移到了中间某个位置,整个堆的特性都已经被破坏。举个例子,该值可能比它的子节点的值要小,如果仅向上调整的话会导致堆特性没法恢复


堆排序

  由堆的特性可知,堆顶元素是最大的,因此堆排序的直观思路就是取出堆顶元素,然后将堆的最后一个元素替换至堆顶,再进行依次针对堆顶元素的向下调整——如此重复直至堆中仅有一个元素未被遍历。

  具体实现时,为了节省空间,可以倒着遍历数组。假设当前访问到i号为,那么将堆顶元素与i号为元素交换,接着在[1,i-1]范围内对堆顶元素进行一次向下调整即可。


让我们来对比一下BST和堆吧

| BST Heap
insert logn
find n
delete logn
create n
Traverse n

BST and Heap详解的更多相关文章

  1. JVM性能分析工具详解--MAT等

    获得堆转储文件 巧妇难为无米之炊,我们首先需要获得一个堆转储文件.为了方便,本文采用的是 Sun JDK 6.通常来说,只要你设置了如下所示的 JVM 参数: -XX:+HeapDumpOnOutOf ...

  2. STL之heap与优先级队列Priority Queue详解

    一.heap heap并不属于STL容器组件,它分为 max heap 和min heap,在缺省情况下,max-heap是优先队列(priority queue)的底层实现机制.而这个实现机制中的m ...

  3. Tomcat使用详解

    Tomcat简介 官网:http://tomcat.apache.org/ Tomcat GitHub 地址:https://github.com/apache/tomcat Tomcat是Apach ...

  4. slf4j log4j logback关系详解和相关用法

    slf4j log4j logback关系详解和相关用法 写java也有一段时间了,一直都有用slf4j log4j输出日志的习惯.但是始终都是抱着"拿来主义"的态度,复制粘贴下配 ...

  5. 数据结构图文解析之:二叉堆详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  6. centos7.2环境elasticsearch-5.0.1+kibana-5.0.1+zookeeper3.4.6+kafka_2.9.2-0.8.2.1部署详解

    centos7.2环境elasticsearch-5.0.1+kibana-5.0.1+zookeeper3.4.6+kafka_2.9.2-0.8.2.1部署详解 环境准备: 操作系统:centos ...

  7. Chrome开发者工具详解(4)-Profiles面板

    Chrome开发者工具详解(4)-Profiles面板 如果上篇中的Timeline面板所提供的信息不能满足你的要求,你可以使用Profiles面板,利用这个面板你可以追踪网页程序的内存泄漏问题,进一 ...

  8. JAVA中的GC机制详解

    优秀Java程序员必须了解的GC工作原理 一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只 ...

  9. mysql配置文件my.cnf详解

    原文地址:mysql配置文件my.cnf详解 作者:gron basedir = path 使用给定目录作为根目录(安装目录). character-sets-dir = path 给出存放着字符集的 ...

随机推荐

  1. Android EventBus踩坑,Activity接收不了粘性事件。

    注解问题 EventBus 的 粘性事件,可以让 成功注册后的 Activity.Fragment 后再接收处理 这一事件. 但是今晚写代码时,突然发现粘性事件,发送不成功了.??? 具体情况是:我在 ...

  2. 题目分享X

    题意:一张票有n位数,如果这张票的前一半数字的和等于后一半数字的和(n一定是偶数),就称这张票为快乐票.有些数被擦除了,标记为’?’(’?‘的个数也是偶数),现在Monocarp 和 Bicarp 进 ...

  3. Java——一文读懂Spring MVC执行流程

    说到Spring MVC执行流程,网上有很多这方面的文章介绍,但是都不太详细,作为一个初学者去读会有许多不理解的地方,今天这篇文章记录一下我学习Spring MVC的心得体会 话不多说,先上图: Sp ...

  4. spring的bean的属性注入

    一.设置注入 设置注入要求: 要求属性在实体类中必须有getter 和setter方法,然后在spring的工厂中就可以使用property标签进行设值注入. 二.构造注入 通过类的构造方法的方式注入 ...

  5. 测试开发专题:spring-boot自定义异常返回

    上文测试开发专题:spring-boot统一异常捕获我们讨论了java异常以及如何使用Spring-Boot捕获异常,但是没有去说捕获异常后该如何进一步处理,这篇文章我们将对这个遗留的问题进行讨论. ...

  6. Vue + Element-ui实现后台管理系统(4)---封装一个ECharts组件的一点思路

    封装一个ECharts组件的一点思路 有关后台管理系统之前写过三遍博客,看这篇之前最好先看下这三篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-system ...

  7. 【FreeRTOS学习03】小白都能懂的Task Management 任务管理基本概念介绍

    在FreeRTOS中,线程的术语又可以被称之为任务,或许这样更加合适,本文将介绍任务的创建/删除,任务参数的使用,以及任务优先级: 1 软实时和硬实时 硬实时系统的任务运行正确性与响应时限是紧密相关的 ...

  8. DoNet:浅淡对delegate的理解

    1 前言 C#的相关文档,MSDN上其实已经很详细了,关于delegate的使用可以参 考MSDN上的文档https://msdn.microsoft.com/zh-cn/library/900fyy ...

  9. [hihoCoder1236 Scores 2015BeijingOnline]简单粗暴的分块+简单粗暴的bitset

    题意:50000个5维向量,50000次询问每一维都不大于某一向量的向量个数,强制在线. 思路:做完这题才知道bitset效率这么高,自己本地测试了下1s可以操作1010个bit,orz简单粗暴 令S ...

  10. window 10电脑永不熄屏的方法

    你的电脑是不是人还没有离开一会儿,经常锁屏,输入密码??反复反复,特别的折磨人,别急,下面我教你,告别反复,从此我的电脑我做主. 第一步,打开设置,进入个性化界面,点击锁屏界面,往下滑 第二步,找到屏 ...