看图轻松理解数据结构与算法系列(二叉搜索树)

前言

推出一个新系列,《看图轻松理解数据结构和算法》,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握。本系列包括各类堆、各类队列、各类列表、各类树、各类图、各类排序等等几十篇的样子。mysql

关于树

对于树的数据结构你们都了解,只是树的类型有不少,因此可能又会对树产生一种陌生感。树其实就是由有限n(n>=1)个节点组成的一个具备层次关系的集合,它看起来像一棵倒挂的树,因此称之为“树”。算法

树的特色

  • 每一个节点有若干个或0个子节点;
  • 根节点没有父节点;
  • 每个非根节点有且只有一个父节点;
  • 每一个子节点能够分为多个不相交的子树;

二叉搜索树

二叉搜索树(Binary Search Tree,简写BST),又称为二叉排序树,属于树的一种,经过二叉树将数据组织起来,树的每一个节点都包含了健值 key、数据值 data、左子节点指针、右子节点指针。其中健值 key 是最核心的部分,它的值决定了树的组织形状;数据值 data 是该节点对应的数据,有些场景能够忽略,举个例子,key 为身份证号而 data 为人名,经过身份证号找人名;左子节点指针指向左子节点;右子节点指针指向右子节点。sql

二叉搜索树特色

  • 左右子树也分别是二叉搜索树。
  • 左子树的全部节点 key 值都小于它的根节点的 key 值。
  • 右子树的全部节点 key 值都大于他的根节点的 key 值。
  • 二叉搜索树能够为一棵空树。
  • 通常来讲,树中的每一个节点的 key 值都不相等,但根据须要也能够将相同的 key 值插入树中。

image

插入操做

  1. 若是为空树则将插入节点做为根节点。
  2. 若是不为空树则从根节点开始,比较插入节点与根节点的 key 值,值相同则不作任何处理直接返回,大于则继续比较右子节点R,小于则继续比较左子节点L。
  3. 右子节点R与插入节点比较,插入节点的 key 值大的话则继续往R节点的右子节点比较,小于的话则继续往R节点左子节点比较。
  4. 以此类推不断往下寻找,直到找到左子节点指针或右子节点指针为空的节点,将插入节点放进去。

对于下面这棵树,插入DH网络

image

建立D节点并与根节点比较,数据结构

image

D 小于 E,因而往左子节点继续比较,并发

image

D 大于 C,应该往右子节点方向,而此时 C 节点的右子节点指针为空,D 节点能够放置进去。机器学习

image

一样的,对于 H 节点,先建立 H 节点并与根节点比较,数据结构和算法

image

H 大于 E,因而往右子节点继续比较,学习

image

H 大于 G,应该往右子节点方向,而此时 G 节点的右子节点指针为空,H 节点能够放置进去。.net

image

插入顺序性

二叉搜索树的形状与节点插入顺序不一样而可能不一样,好比对于A B C D E F G H这些节点集,按E C A B D G F H顺序插入则为,

image

而若是调换前面两个节点,按照C E A B D G F H顺序插入则以下图,形状差异仍是挺大的,

image

极端状况下,按照A B C D E F G H顺序插入,则为,

image

查询操做

  1. 则从根节点开始,比较查询节点与根节点的 key 值,值相同则表示找到该节点,直接返回,大于则继续往右子节点R查找,小于则继续往左子节点L查找。
  2. 右子节点R与查询节点比较,查询节点的 key 值大的话则继续往R节点的右子节点查找,小于的话则继续往R节点左子节点查找。
  3. 以此类推不断往下寻找,直到找到节点的 key 值与查询节点的相同,则表示查找成功,若是最终找不到则说明不存在该节点。

对于下图的树查找 key 值为“B”和“G”的节点,

image

“B”与根节点的 key 值比较,

image

“B”小于“E”,往左子节点继续寻找,

image

“B”小于“C”,往左子节点继续寻找,

image

“B”大于“A”,往右子节点继续寻找,二者相等,找到。

image

继续查询 key 值为“G”的节点,与根节点比较,

image

“G”大于“E”,往右子节点,二者相等,找到。

image

删除操做

删除操做分三种状况进行,

  • 若是删除的节点为叶子节点,即它的左子节点指针和右子节点指针都为空时,则能够直接删掉该节点,并不会影响整棵树的结构。
  • 若是删除的节点只有一个子节点(左子节点或右子节点),则直接将子节点提高到被删除的节点位置。
  • 若是删除的节点有两个子节点,此时须要找到删除节点的中序后继或中序前驱来填补删除节点,中序后继其实就是全部大于删除节点中最小的那个,而中序前驱就是全部小于删除节点中最大的那个,由于二叉搜索树通过中序遍历后是一个递增序列,因此后继就是删除节点的后面那个节点,大于且大得最少的那个,好比1 2 3 4 5中4就是3的后继。前驱就是删除节点前面那个节点,好比1 2 3 4 5中2就是3的前驱。

状况一

删除“B”叶子结点,从根节点开始查找,

image

image

image

image

找到,直接删除,

image

状况二

假如树的结构以下图,如今要删除“C”节点,

image

从根节点开始找,

image

image

找到“C”节点,直接将原来指向“C”节点的右子节点指针指向“C”的子节点,

image

最终为,

image

状况三

要在以下的树中删除“E”节点,

image

“E”节点存在两个子节点,因而开始寻找“E”节点的中序前驱来替换它,前驱在左子节点“C”下最大值的那个节点,

image

要找“C”节点下最大值节点则一直往右,

image

直到不能继续往下,即“D”节点便是前驱,用“D”节点来替换“E”节点,

image

最终实现将“E”节点删除。

image

-------------推荐阅读------------

个人开源项目汇总(机器&深度学习、NLP、网络IO、AIML、mysql协议、chatbot)

为何写《Tomcat内核设计剖析》

个人2017文章汇总——机器学习篇

个人2017文章汇总——Java及中间件

个人2017文章汇总——深度学习篇

个人2017文章汇总——JDK源码篇

个人2017文章汇总——天然语言处理篇

个人2017文章汇总——Java并发篇


跟我交流,向我提问:

欢迎关注:

相关文章
相关标签/搜索