JavaScript 二叉搜索树

一. 二叉搜索树的概念

什么是二叉搜索树?

  • 二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树

  • 二叉搜索树是一颗二叉树, 可以为空;如果不为空,满足以下性质:

    • 非空左子树的所有键值小于其根结点的键值。
    • 非空右子树的所有键值大于其根结点的键值。
    • 左、右子树本身也都是二叉搜索树。
  • 下面哪些是二叉搜索树, 哪些不是?

 

二叉搜索树的特点:

  • 二叉搜索树的特点就是相对较小的值总是保存在左结点上, 相对较大的值总是保存在右结点上.
  • 那么利用这个特点, 我们可以做什么事情呢?
  • 查找效率非常高, 这也是二叉搜索树中, 搜索的来源.

二叉搜索树的操作 

  • 二叉搜索树有哪些常见的操作呢?
    • insert(key):向树中插入一个新的键。
    • search(key):在树中查找一个键,如果结点存在,则返回true;如果不存在,则返回false
    • inOrderTraverse:通过中序遍历方式遍历所有结点。
    • preOrderTraverse:通过先序遍历方式遍历所有结点。
    • postOrderTraverse:通过后序遍历方式遍历所有结点。
    • min:返回树中最小的值/键。
    • max:返回树中最大的值/键。
    • remove(key):从树中移除某个键

二. 二叉搜索树的实现 

创建二叉搜索树 

  • 我们像封装其他数据结构一样, 先来封装一个BinarySearchTree的类 
// 创建BinarySearchTree
function BinarySerachTree() {
    // 创建结点构造函数
    function Node(key) {
        this.key = key
        this.left = null
        this.right = null
    }
    
    // 保存根的属性
    this.root = null
    
    // 二叉搜索树相关的操作方法
}

向树中插入数据 

  • 我们两个部分来完成这个功能.

  • 外界调用的insert方法

// 向树中插入数据
BinarySerachTree.prototype.insert = function (key) {
    // 1.根据key创建对应的node
    var newNode = new Node(key)
    
    // 2.判断根结点是否有值
    if (this.root === null) {
        this.root = newNode
    } else {
        this.insertNode(this.root, newNode)
    }
}
  • 插入非根结点 
BinarySerachTree.prototype.insertNode = function (node, newNode) {
    if (newNode.key < node.key) { // 1.准备向左子树插入数据
        if (node.left === null) { // 1.1.node的左子树上没有内容
            node.left = newNode
        } else { // 1.2.node的左子树上已经有了内容
            this.insertNode(node.left, newNode)
        }
    } else { // 2.准备向右子树插入数据
        if (node.right === null) { // 2.1.node的右子树上没有内容
            node.right = newNode
        } else { // 2.2.node的右子树上有内容
            this.insertNode(node.right, newNode)
        }
    }
}
  • 测试代码 
// 测试代码
var bst = new BinarySerachTree()

// 插入数据
bst.insert(11)
bst.insert(7)
bst.insert(15)
bst.insert(5)
bst.insert(3)
bst.insert(9)
bst.insert(8)
bst.insert(10)
bst.insert(13)
bst.insert(12)
bst.insert(14)
bst.insert(20)
bst.insert(18)
bst.insert(25)
  • 形成的树: 

 

  • 新的树: 

 

遍历二叉搜索树 

  • 前面, 我们向树中插入了很多的数据, 为了能很多的看到测试结果. 我们先来学习一下树的遍历.
    • 注意: 这里我们学习的树的遍历, 针对所有的二叉树都是适用的, 不仅仅是二叉搜索树.
  • 树的遍历:
    • 遍历一棵树是指访问树的每个结点(也可以对每个结点进行某些操作, 我们这里就是简单的打印)
    • 但是树和线性结构不太一样, 线性结构我们通常按照从前到后的顺序遍历, 但是树呢?
    • 应该从树的顶端还是底端开始呢? 从左开始还是从右开始呢?
    • 二叉树的遍历常见的有三种方式: 先序遍历/中序遍历/后续遍历. (还有程序遍历, 使用较少, 可以使用队列来完成)

先序遍历 

  • 遍历过程为:

    • ①访问根结点;
    • ②先序遍历其左子树;
    • ③先序遍历其右子树。
  • 遍历过程:

 

  • 遍历的代码实现 
BinarySerachTree.prototype.preOrderTraversal = function (handler) {
    this.preOrderTranversalNode(this.root, handler)
}

BinarySerachTree.prototype.preOrderTranversalNode = function (node, handler) {
    if (node !== null) {
        // 1.打印当前经过的节点
        handler(node.key)
        // 2.遍历所有的左子树
        this.preOrderTranversalNode(node.left, handler)
        // 3.遍历所有的右子树
        this.preOrderTranversalNode(node.right, handler)
    }
}
  •  测试代码:
// 测试前序遍历结果
var resultString = ""
bst.preOrderTraversal(function (key) {
    resultString += key + " "
})
alert(resultString) // 11 7 5 3 6 9 8 10 15 13 12 14 20 18 25
  • 代码先序遍历图解: 

 

中序遍历

  • 遍历过程为:

    • ①中序遍历其左子树;
    • ②访问根结点;
    • ③中序遍历其右子树。
  • 遍历过程:

 

  • 遍历的代码实现: 
// 中序遍历
BinarySerachTree.prototype.inOrderTraversal = funct
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 非常感谢您的提问。以下是使用 JavaScript 编写函数返回可能构成二叉搜索树的组合数的代码: ```javascript function numTrees(n) { const dp = new Array(n + 1).fill(0); dp[0] = 1; dp[1] = 1; for (let i = 2; i <= n; i++) { for (let j = 1; j <= i; j++) { dp[i] += dp[j - 1] * dp[i - j]; } } return dp[n]; } ``` 这个函数的参数 `n` 表示二叉搜索树的节点数,返回值是可能构成的二叉搜索树的组合数。这个函数使用动态规划的思想,时间复杂度为 O(n^2)。 希望这个代码能够帮助您解决问题。如果您还有其它问题,请随时提出。 ### 回答2: 编写一个使用 JS 编写的函数,返回可能构成二叉搜索树的组合数。我将使用动态规划的方法来解决这个问题。 动态规划的思想是将一个大的问题拆分成更小的子问题来解决,然后将子问题的解逐步累加得到整体的解。 首先,我们定义一个数组 dp,其中 dp[i] 表示 i 个节点可以构成的二叉搜索树的组合数。 当节点数为 0 或 1 时,只有一种组合方式,即空树或只有根节点的树,所以有 dp[0] = 1 和 dp[1] = 1。 然后,我们从 2 开始遍历到 n,计算 dp[i] 的值。对于每个节点数 i,我们可以将每个数字 j 作为根节点,将其左侧的 j-1 个节点构成左子树,将右侧的 i-j 个节点构成右子树。 左子树和右子树的组合数分别为 dp[j-1] 和 dp[i-j],所以 dp[i] 的值就是将所有可能的左右子树组合的结果累加起来。最后,返回 dp[n] 即可。 下面是用 JS 编写的实现: ```javascript function countBSTCombinations(n) { if (n < 0) return 0; const dp = new Array(n + 1).fill(0); dp[0] = 1; dp[1] = 1; for (let i = 2; i <= n; i++) { for (let j = 1; j <= i; j++) { dp[i] += dp[j - 1] * dp[i - j]; } } return dp[n]; } // 示例用法 console.log(countBSTCombinations(3)); // 输出5,因为有5种可能的BST组合:[1,null,2,3],[1,2,null,null,3],[1,3,2,null,null],[2,1,3,null,null],[3,1,null,null,2] ``` 这个函数可以用来计算构成给定节点数的所有二叉搜索树的可能组合数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值