在本文中,我将尽力解释一些您在编码面试之前应该学习的核心算法。

什么是二叉搜索树 (BST)?

在编码面试中很常见,BST 是一种树状数据结构,顶部有一个根。它们是存储数值的好方法,因为它们的有序性质允许快速搜索和查找。

与普通树相比,BST 具有以下特性:

  • 每个左孩子的值都比它的父母小
  • 每个右孩子的值都比它的父母大
  • 每个节点可以包含 0 到 2 个子节点。

下图应该更清楚地说明事情。

二叉树节点的定义

我们通常在 Javascript 中定义一个二叉树节点,函数如下:

 function TreeNode(val, left, right) {
     this.val = val
     this.left = left
     this.right = right
 }

二叉树基本遍历(中序、后序、前序)

首先要知道如何遍历 BST 的每个节点。这允许我们在 BST 的所有节点上执行一个功能。例如,如果我们想x在 BST 中找到一个值,我们就需要节点。

有三种主要方法可以做到这一点。幸运的是,他们有共同的主题。

中序遍历

递归算法是开始使用二叉树中序遍历的最简单方法。思路如下:

  • 如果节点为空,则什么都不做——否则,递归调用节点左子节点上的函数。
  • 然后,遍历完所有左子节点后,对节点进行一些操作。我们当前的节点保证是最左边的节点。
  • 最后,调用 node.right 上的函数。

Inorder 算法从左、中、右遍历树节点。

const inorder = (root) => {
    const nodes = []
    if (root) {
        inorder(root.left)
        nodes.push(root.val)
        inorder(root.right)
    }
    return nodes
}
// 对于我们的示例树,将返回 [1,2,3,4,5,6]

后序遍历

递归算法是开始后序遍历的最简单方法。

  • 如果节点为空,则什么都不做——否则,递归调用节点左子节点上的函数。
  • 当没有更多的左孩子时,调用 node.right 上的函数。
  • 最后,在节点上做一些操作。

后序遍历从左、右、中访问树节点。

const postorder = (root) => {
    const nodes = []
    if (root) {
        postorder(root.left)
        postorder(root.right)
        nodes.push(root.val)
    }
    return nodes
}
// 对于我们的示例树,将返回 [1,3,2,6,5,4]

前序遍历

递归算法是开始前序遍历的最简单方法。

  • 如果节点为空,则什么都不做——否则,在节点上做一些操作。
  • 遍历节点的左子节点并重复。
  • 遍历到节点的右孩子并重复。

后序遍历从中、左、右访问树节点。

const preorder = (root) => {
    const nodes = []
    if (root) {
        nodes.push(root.val)
        preorder(root.left)
        preorder(root.right)
    }
    return nodes
}
// 对于我们的示例树,将返回 [4,2,1,3,5,6]

什么是有效的二叉搜索树?

有效的二叉搜索树 (BST) 具有所有值小于父节点的左子节点,以及值大于父节点的所有右子节点。
要验证一棵树是否是有效的二叉搜索树:

  • 定义当前节点可以具有的最小值和最大值
  • 如果节点的值不在这些范围内,则返回 false
  • 递归验证节点的左孩子,最大边界设置为节点的值
  • 递归验证节点的右孩子,最小边界设置为节点的值
const isValidBST = (root) => {
    const helper = (node, min, max) => {
        if (!node) return true
        if (node.val <= min || node.val >= max) return false
        return helper(node.left, min, node.val) && helper(node.right, node.val, max)
    }
    return helper(root, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)
}

如何找到二叉树最大深度

在这里,算法试图找到我们 BST 的高度/深度。换句话说,我们正在查看 BST 包含多少个“级别”。

  • 如果节点为空,我们返回 0 因为它没有添加任何深度
  • 否则,我们将 1 添加到我们当前的深度(我们遍历了一层)
  • 递归计算节点子节点的深度并返回node.left和node.right之间的最大和
const maxDepth = function(root) {
    const calc = (node) => {
        if (!node) return 0
        return Math.max(1   calc(node.left), 1   calc(node.right))
    }
    return calc(root)
};

如何找到两个树节点之间的最小公共祖先

让我们提高难度。我们如何在我们的二叉树中找到两个树节点之间的共同祖先?让我们看一些例子。

在这棵树中,3和1的最低共同祖先是2。3和2的LCA是2。6和1和6的LCA是4。

看到这里的模式了吗?两个树节点之间的 LCA 要么是节点本身之一(3 和 2 的情况),要么是父节点,其中第一个子节点位于其左子树中的某处,而第二个子节点位于其右子树中的某处。

寻找两个树节点 p 和 q 之间的最低共同祖先(LCA)的算法如下:

  • 验证是否在左子树或右子树中找到 p 或 q
  • 然后,验证当前节点是 p 还是 q
  • 如果在左子树或右子树中找到 p 或 q 之一,并且 p 或 q 之一是节点本身,我们就找到了 LCA
  • 如果在左子树或右子树中都找到了 p 和 q,我们就找到了 LCA
const lowestCommonAncestor = function(root, p, q) {
    let lca = null
    const isCommonPath = (node) => {
        if (!node) return false
        var isLeft = isCommonPath(node.left)
        var isRight = isCommonPath(node.right)
        var isMid = node == p || node == q
        if (isMid && isLeft || isMid && isRight || isLeft && isRight) {
            lca = node
        }
        return isLeft || isRight || isMid
    }
    isCommonPath(root)
    return lca
};

😊 结尾想说的

到此,我们已经学会了如何遍历、验证和计算 BST 的深度。

到此这篇关于面向JavaScript入门初学者的二叉搜索树算法教程的文章就介绍到这了,更多相关JavaScript二叉搜索树算法内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

面向JavaScript入门初学者的二叉搜索树算法教程的更多相关文章

  1. html5 拖拽及用 js 实现拖拽功能的示例代码

    这篇文章主要介绍了html5 拖拽及用 js 实现拖拽,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. 用Swift实现MD5算法&amp;引入第三方类库MBProgressHUD

    之前项目里面是用objc写的MD5加密算法,最近在用swift重写以前的项目,遇到了这个问题。顺带解决掉的还有如何引入第三方的类库,例如MBProgressHUD等一些特别好的控件解决的方法其实是用objc和swift混合编程的方法,利用Bridging-header文件。你可以简单的理解为在一个用swift语言开发的工程中,引入objective-c文件是需要做的一个串联文件,好比架设了一个桥,让swift中也可以调用objective-c的类库和frame等等。

  4. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

  5. swift排序算法和数据结构

    vararrayNumber:[Int]=[2,4,216)">6,216)">7,216)">3,216)">8,216)">1]//冒泡排序funcmaopao->[Int]{forvari=0;i

  6. swift - 函数指针的应用 - 避免重复算法

    =nil;})}privatefuncsearch(selector:(Employee->Bool))->[Employee]{varresults=[Employee]();foreinemployees{if(selector(e)){results.append(e);}}returnresults;}}

  7. 如何用 Swift 实现 A* 寻路算法

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  8. swift算法实践1

    在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。波兰逻辑学家J.Lukasiewicz于1929年提出了另一种表示表达式的方法。逆波兰表达式,它的语法规定,表达式必须以逆波兰表达式的方式给出。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将栈顶的运算符从栈中弹出,直到栈顶运算符的优先级低于当前运算符,将该字符入栈。

  9. swift算法实践2

    字符串hash算法Time33在效率和随机性两方面上俱佳。对于一个Hash函数,评价其优劣的标准应为随机性,即对任意一组标本,进入Hash表每一个单元之概率的平均程度,因为这个概率越平均,数据在表中的分布就越平均,表的空间利用率就越高。Times33的算法很简单,就是不断的乘33,见下面算法原型。

  10. swift算法实践3)-KMP算法字符串匹配

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部