二分搜索树也是二叉树,和二叉树长的同样,就是有个特色,每一个节点的值比他的左子树的值大,比他的右子树的值小。以下图所示:前端
// 声明节点构造函数 当前节点的值,左节点,右节点
class Node {
constructor(value) {
this.value = value
this.left = null
this.right = null
}
}
// 二分搜索树构造函数
class BST {
constructor() {
this.root = null
this.size = 0
}
getSize() {
return this.size
}
isEmpty() {
return this.size === 0
}
addNode(v) {
// 每次添加子节点后,更新树
this.root = this._addChild(this.root, v)
}
_addChild(node, v) {
if (!node) {
this.size++
return new Node(v)
}
if (node.value > v) {
console.log(`在${node.value}节点,添加左节点${v}`)
node.left = this._addChild(node.left, v)
} else if (node.value < v) {
console.log(`在${node.value}节点,添加右节点${v}`)
node.right = this._addChild(node.right, v)
}
return node
}
}
let bst = new BST()
// 第一个节点
bst.addNode(10)
// 后续节点
bst.addNode(8)
bst.addNode(6)
bst.addNode(3)
bst.addNode(7)
bst.addNode(9)
bst.addNode(12)
bst.addNode(11)
bst.addNode(15)
bst.addNode(14)
console.log(bst)
复制代码
运行结果以下:node
左节点值是8 右节点值12 中间节点值是10。函数
再展开左节点看一下this
右边就再也不展开赘述了spa
二叉树遍历 分为深度遍历(先序遍历、中序遍历、后序遍历,三种遍历的区别在于什么时候访问节点), 广度遍历(一层层地遍历)3d
绕不开的递归又出现了,想起有一天右边同事妹子很开心的和我说她知道了递归的终极奥义:“递归的终极奥义就是:不要想递归是怎么具体一步步实现的”code
那我先来实现一下先序遍历cdn
class BST {
...
// 添加先序遍历实现,其实就是很简单的几行代码
preTraversal() {
this._pre(this.root)
}
_pre(node) {
if (node) {
// 访问节点的值
console.log(node.value)
// 递归左右子树
this._pre(node.left)
this._pre(node.right)
}
}
}
// 用上面生成的bst实例执行一下,结果以下图
bst.preTraversal()
复制代码
那么这个结果是如何生成的呢?blog
一步步的推导递归的具体实现后,还真的觉的上面所说递归的奥义那句话总结的是颇有意思的。排序
class BST {
...
// 添加中序遍历实现,其实就是很简单的几行代码
midTraversal() {
this._mid(this.root)
}
_mid(node) {
if (node) {
// 1语句 后面讲解时候说'1语句'就指代下面这句
this._mid(node.left)
// 2语句
console.log(node.value)
// 3语句
this._mid(node.right)
}
}
}
// 用上面生成的bst实例执行一下,结果以下图
bst.midTraversal()
复制代码
那么再回退一下,打印出7以后,也就是node.left 是6这个节点的递归执行完毕了,此时此刻的node是8,而后执行console.log(node.value),再去执行3语句,此时此刻的3语句的参数是node.left,也就是9节点,对这个9节点,依次执行123语句,9节点没有子节点,因此只是打印出9 ,至此,整个8节点遍历完毕。
打印出了9以后, 8节点彻底遍历完毕了,8节点做为node.left,那么此时的node是10节点,执行2语句,打印出10 ,那么后续的,相信不用我再说了吧
这就是为何二分排序树的中序遍历的结果是排序好的。
class BST {
...
// 添加后序遍历实现,其实就是很简单的几行代码
backTraversal() {
this._back(this.root)
}
_back(node) {
if (node) {
// 1语句 后面讲解时候说'1语句'就指代下面这句
this._back(node.left)
// 2语句
this._back(node.right)
// 3语句
console.log(node.value)
}
}
}
// 用上面生成的bst实例执行一下,结果以下图
bst.backTraversal()
复制代码
未完待续
(以上参考掘金小册,融入本身的实操和思考,由于是收费小册,参考的地址原文没办法贴出来,yck老师很赞,建议你们都去看看他的小册)