二分搜索樹也是二叉樹,和二叉樹長的同樣,就是有個特色,每一個節點的值比他的左子樹的值大,比他的右子樹的值小。以下圖所示:前端
// 聲明節點構造函數 當前節點的值,左節點,右節點
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老師很贊,建議你們都去看看他的小冊)