寻找Nemo的乐趣:什么是二叉搜索树?
全文共2613字,预计学习时长7分钟
图源:unsplash
生活中,我们经常需要找东西或做决定,一个简单的方法就是将选择一分为二。假设你在玩“猜猜我是谁”的游戏,目标是猜测你的对手所选择的角色。你就可以问他们这样的问题,比如:
· 你的角色是男性还是女性?
· 男性。好,那他有胡子吗?
· 没有。好,他戴帽子吗?
我们在每一步都继续推断我们的选择。同理,二叉搜索树通过在每一步都减少选项来帮助找到想要的东西。
首先,二叉搜索树到底是什么?
二叉搜索树(BST)是一种特殊类型的树形数据结构,由节点及其子节点组成,子节点也被视作“后代”,可以把它想象成一棵倒置的树或者是树的根部。
每个节点最多只能有2个子节点:左节点和右节点。为了使它成为一个有效的二叉搜索树,左节点的值必须总是小于母节点,而右节点的值必须总是大于母节点。没有任何间隙的BST,即每个节点都有一个左节点和一个右节点的二叉搜索树,被称为“完美”树。
在完美树中,当遍历树时,每个级别中的节点数会翻倍,将前面的所有节点相加并在该数字上再添加“1”可以得出底层的节点总数。
当在平衡二叉搜索树中搜索一个元素时,平均需要花费额的时间为O(log n),在最坏的情况下,需要O(n)。你可以把在二叉搜索树中的搜索看作是“选择你自己的冒险”模型,从顶部节点开始,然后沿着树向下,在到达的每个节点问同样的2个问题。
· 我要找的值是否小于当前节点?如果是,向左走。
· 我要找的值是否大于当前节点?如果是,向右走。
插入和删除也非常快,平均花费O(log n)的时间。但有一个缺点就是不能像数组那样获得随机元素。
什么时候可以使用二叉搜索树?
假设你需要为Facebook这样的社交媒体应用程序设计一个数据库。该数据库需要处理数百万个用户名,并且需要在登录期间快速检索到其中一个用户名。由于每天都有新注册或删除的账户,你也需要方便进行插入和删除的操作。
通过一个排序过的数组进行二分搜索会非常快(需要花费O(log n)时间),但是插入或删除一个用户名会导致整个数组重新排序,需要花费O(n)时间,这取决于数组的大小,可能会相对慢一些。如果我们使用二叉搜索树,插入或删除的时间会快得多(花费O(log n)时间)。
如果有一个带有名字的二叉搜索树(比如这个《海底总动员》的树),就可以按字母顺序排列。
在字母表中,Dory在Marlin之前,所以它是左边的节点,而Moonfish在Marlin之后,所以它是右边的节点。同样地,在下一层搜索也遵循这个规律。Bruce在Crush之前,也在Dory和Marlin之前。Darla在Crush之后,但在Dory和Marlin之前。
现在准备好,是时候寻找Nemo了!
寻找Nemo!
假设已经有一个有效的二叉搜索树,并且需要找到Nemo。因为我们知道树中的节点是按字母顺序排序的,所以这应该相当简单。
从Marlin开始,左边是Dory,右边是Moonfish。我们知道Nemo在字母表中位于Marlin之后,所以我们将遍历到正确的节点(Moonfish)。Nemo按字母顺序是排在Moonfish之后的,所以继续往下看Moonfish的右子节点。很幸运,那是…Nemo!找到Nemo了!
效率很高。二叉搜索树减少了整个搜索过程的时间复杂性!如果树没有分类,只是一个普通的树形结构呢?或者要证实这是个二叉搜索树呢?目前有两种不同的搜索技术可以实现这一点。
什么是广度优先搜索?
广度优先搜索是一种在树(或图形)中一次遍历一级的方法,每次都从左到右在节点之间移动。
在《海底总动员》的例子中,Marlin首先会问Dory,“你知道我儿子Nemo在哪里吗?”如果它说不,Marlin就会问Moonfish同样的问题。如果它也说不,Marlin会再下一层,问Crush、Gill和Mr. Ray,然后Marlin就找到Nemo了!
广度优先搜索
如果在Mr. Ray之后没有找到Nemo,Marlin会到下一级询问Bruce和Darla等等。使用广度优先搜索可以找到起始节点(Marlin)和目标节点(Nemo)之间的最短距离。时间复杂度是O(n),因为在最坏的情况下,需要检查每个节点才能找到Nemo。
什么是深度优先搜索?
深度优先搜索(Depth first search)是一种从顶部节点一直向下遍历到其最远子节点的树(或图形)的方法,然后在未找到目标节点时再回去并尝试其他路径。
在《海底总动员》的例子中,Marlin首先会问Dory “你知道Nemo在哪里吗?” 如果她不知道,他就会问Crush同样的问题,因为Crush是Dory最左边的子节点。如果Crush也说没有,Marlin将移动到下一级去问Bruce,尽管他害怕成为鲨鱼的点心,但也会问问他有没有见到自己的儿子。
深度优先搜索
如果Bruce说没看到Nemo,并向Marlin保证“鱼是朋友,不是食物”,Marlin就需要回到上级,寻找另一个他还没有问到的节点。回到Crush那里,他会发现下一步应该问Darla。由于Crush的所有后代现在都被审问过了,Marlin会回到Dory那里,检查她其余的“后代”。Marlin需要把每个角色询问一遍后才能找到Nemo。
深度优先搜索顺序
与广度优先搜索一样,深度优先搜索也包括时间复杂度O(n),但空间复杂度可能有所不同。深度优先搜索通常占用较少的内存或空间,假设可以在遍历整个树之前找到目标节点。
由于二叉搜索树中的每增加一级节点会加倍(至少对于平衡树而言),如果丢失的节点(Nemo)位于树的较低位置,则可以使用深度优先搜索来节省内存。在最坏的情况下,两种方法的空间复杂度都是O(n)。
关于二叉搜索树以及如何通过代码实现它们还有很多需要学习,但这个有趣的案例会成为你了解数据结构的起点。
推荐阅读专题
留言点赞发个朋友圈
我们一起分享AI学习与发展的干货
编译组:黄弈、苏韫琦
相关链接:
https://medium.com/swlh/data-structures-101-what-is-a-binary-search-tree-5514e08cc8f
如转载,请后台留言,遵守转载规范
推荐文章阅读
ACL2018论文集50篇解读
EMNLP2017论文集28篇论文解读
2018年AI三大顶会中国学术成果全链接
ACL2017论文集:34篇解读干货全在这里
10篇AAAI2017经典论文回顾
长按识别二维码可添加关注
读芯君爱你
寻找Nemo的乐趣:什么是二叉搜索树?相关推荐
- 利用C语言实现二叉搜索树的遍历、查找、插入、删除
IDE:codebloks,编译器:gcc5.1.0 二叉搜索树和我们通常的二叉树还是有一定的区别,顾名思义,一颗二叉搜索树以一颗二叉树来组织,其中每一个结点就是一个对象.除了key(关键字)和卫星数 ...
- 树形结构:从二分查找,二叉搜索树寻找最近祖先,从递归到迭代,实现技巧总结
二分查找,二叉搜索树寻找最近祖先均是典型分治问题,把原问题分成三部分考虑,递归实现简单,迭代实现也比较简单,里面蕴含了一些从从递归到迭代的技巧,注意这里没有使用模拟栈技术. 深究其原因是,这一类型的递 ...
- 剑指Offer之寻找二叉搜索树的第k个节点
寻找二叉树的第k个节点 1.题目描述 2.解析 3.代码 3.1.中序遍历 3.2.利用堆栈 1.题目描述 给定一棵二叉搜索树,请找出其中的第k小的结点.例如, (5,3,7,2,4,6,8) 中,按 ...
- 二叉树 寻找二叉搜索树第K大的节点
给定一颗二叉搜索树,返回该二叉搜索树第K大的节点 思路:由于二叉搜索树的中序遍历序列是从小到大的序列,模拟这一过程每访问一个节点,count++直到第K个 注意点: 由于递归的进入与返回过程,递归调用 ...
- 数据结构二叉排序树建立_数据结构101什么是二叉搜索树
数据结构二叉排序树建立 In everyday life, we need to find things or make decisions, and one way to make that pro ...
- 消除左递归实验代码_「leetcode」108. 构造二叉搜索树【递归】【迭代】详解!
构造二叉搜索树,一不小心就平衡了 ❞ 108.将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树 ...
- LeetCode实战:二叉搜索树的最近公共祖先
背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Given a bin ...
- 数据结构之二叉搜索树(BST)
数据结构之二叉搜索树(BST) 1. 二叉搜索树定义 二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree). 二叉搜索树是具有有以下性质的二叉树: ( ...
- 剑指offer(Java实现) 二叉搜索树的后序遍历序列
题目描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个数字都互不相同. 解题思路 先找到右子树的开始位置,然后分别进行左右 ...
最新文章
- 手动将jar包导入pom依赖,让jar包适配本地maven项目
- 【数据结构】图的深度优先遍历 广度优先遍历
- FineReport搭建物流报表平台的解决方案
- [AngularJS] Reusable directive, require from parent controller
- linux 关闭ext3日志,ssh – 可以在Linux(ext3)上减慢日志写入速度吗?
- python发短信脚本_python脚本发送短信
- javascript概要
- html mysql查询_mysql查询
- 在eclipse中配置Tomcat时,出现“Cannot create a server using the selected type”的错误。...
- 局域网文件共享软件 开源_4个用于共享文件的开源工具
- 资源下载的终极利器-资源轻松简单下载-资源万能下载法
- 解决在ajax回调函数中循环遍历data数组无法获取数组下标为0之后的重复数据的问题
- js实现类似栈和队列的行为,以及push和unshift两个方法的性能测试
- 名帖358 文天祥 草书《谢昌元座右自警辞》
- python利用jieba实现中文分词
- 服务器30M带宽能承受多少人同时请求?
- 7-3 大炮打蚊子(15 分)
- c语言阶乘编程题,C语言编程题:阶乘计算
- 调皮的程序员:Linux之父雕刻在Linux内核中的故事
- sql要学mysql还是php,MySQL_与MSSQL对比学习MYSQL的心得(一)--基本语法,这一期主要是学习MYSQL的基本 - phpStudy...
热门文章
- 4款绝赞的安卓小说app,免费且书源超强!
- 如何实现在屏幕上有漂亮的刀光效果并有星星环绕
- 线程池,Volatile,原子性类AtomicInteger,乐观锁悲观锁,并发工具类Hashtable,ConcurrentHashMap类,Semaphore类
- Bazel 国内镜像源加速下载
- 创维linux进入工厂模式,创维37E700S进入工厂模式方法
- [Halcon小结] 判断Halcon区域region是否为空
- DTK Barcode Reader SDK,支持各种文档和图像格式
- 学英语四级和计算机软件,英语四级学习软件都有哪些好用啊
- WCE6.0 一些问题
- qiskit的grover算法demo