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. F - Qualification Rounds CodeForces - 868C 二进制

    F - Qualification Rounds CodeForces - 868C 这个题目不会,上网查了一下,发现一个结论就是如果是可以的,那么两个肯定可以满足. 然后就用二进制来压一下这个状态就 ...

  2. Day_08【面向对象】扩展案例1_测试项目经理类和程序员类

    分析以下需求,并用代码实现: 1.定义项目经理类 属性: 姓名 工号 工资 奖金 行为: 工作work 2.定义程序员类 属性: 姓名 工号 工资 行为: 工作work 要求: 向上抽取一个父类,让这 ...

  3. 【matlab 基础篇 03】一文带你全面了解 plot 绘图函数的使用(超详细+图文并茂)

    快速入门matlab,系统地整理一遍,如何你和我一样是一个新手,那么此文很适合你: 文章目录 1 前言 2 plot 2.1 显示正弦波 2.2 修改颜色 2.3 修改点的形状 2.4 修改线的形状 ...

  4. vue面试常遇到的面试题

    最近面试了好几家公司,总结一下经常被问到的面试题. 首先呢,一开始先来一个自我介绍,没啥好说的. 接下来就是考验你vue技术的问题了 一些常见的面试题 vue的生命周期 一共有八个阶段,分别为创建前后 ...

  5. STL库中神奇函数nth_element

    用法:nth_element(数组名,数组名+第k小元素,数组名+元素个数) 这个函数主要用来将数组元素中第k小的整数排出来并在数组中就位,随时调用. 例如: ]={,,,,},k ; cin> ...

  6. 7.2 Go type assertion

    7.2 Go type assertion 类型断言是使用在接口值上的操作. 语法x.(T)被称为类型断言,x代表接口的类型,T代表一个类型检查. 类型断言检查它操作对象的动态类型是否和断言类型匹配. ...

  7. 第七篇:wed版语音机器人

    wed版语音机器人: GitHub项目地址:https://github.com/Yang915/WebToy 特别说明:该项目在本机测试,通过浏览器调用系统麦克风(https请求),实际环境在Fir ...

  8. 使用urllib

    urlopen的基本用法: 工具为:python3(windows) 其完整表达式为: urllib.request.urlopen(url, data=None, [timeout, ]*, caf ...

  9. ajax提交可以上传文件的form表单

    var formData = new FormData($( "#fm")[0]);       $.ajax({            url: 'webnavigationcw ...

  10. python脚本实现接口自动化轻松搞定上千条接口用例

    接口自动化目前是测试圈主流的一个话题,我也在网上搜索了很多关于自动化的关键词,大多数博主分享的python做接口自动化都是以开源的框架,比如:pytest.unittest+ddt(数据驱动) 最常见 ...