首先是二叉樹java
子節點的位置是肯定的,變現爲node
JS描述的完整代碼傳送門
可視化BST傳送門
樹是由節點組成的,要實現樹那麼先要實現節點
class Node { constructor (data, count = 1, left = null, right = null) { // 數值 this.data = data // 出現次數 this.count = count // 左右節點指向 this.left = left this.right = right } show () { return { data: this.data, count: this.count } } }
目前咱們只須要一個根節點的屬性,所以一個基本的BST
能夠描述爲:git
class BST { constructor () { // 初始化跟節點爲null this.root = null } }
咱們有了一個基本的BST
,這時候咱們能夠new
一個 bst
,那麼咱們怎麼插入數據呢?這時候咱們須要一個insert
方法,這個方法有如下的條件:github
Node
的一個實例bst
的根節點指向該節點
class BST { constructor () { // 初始化跟節點爲null this.root = null } /** * 插入數據 * @param data */ insert (data) { let n = new Node(data, 1) if (this.root === null) { // 沒有根節點,新的樹把待插入的值做爲根節點 this.root = n } else { // 有根節點,遍歷樹直到找到合適的位置 let current = this.root while (true) { if (data < current.data) { if (current.left === null) { current.left = n break } current = current.left } else if (data === current.data) { current.count += 1 break } else { if (current.right === null) { current.right = n break } current = current.right } } } } }
let testData = [ 43, 34, 67, 23, 34, 45, 2, 78, 34 ] let bst = new BST() console.log(JSON.stringify(bst)) for (let data of testData) { bst.insert(data) } console.log(JSON.stringify(bst))
插入數據前:web
{"root":null}
插入數據後bash
{ "root": { "data": 43, "count": 1, "left": { "data": 34, "count": 3, "left": { "data": 23, "count": 1, "left": { "data": 2, "count": 1, "left": null, "right": null }, "right": { "data": 28, "count": 1, "left": null, "right": null } }, "right": null }, "right": { "data": 67, "count": 1, "left": { "data": 45, "count": 1, "left": null, "right": null }, "right": { "data": 78, "count": 1, "left": null, "right": null } } } }
插入數據以後咱們是經過nodejs的logger來查看bst
,事實上,咱們還須要其餘的遍歷方法來查看bst
post
遍歷二叉樹一般有三種遍歷方法,分別是中序、先序和後序,他們的遍歷路徑不同
中序遍歷應該是最經常使用的一種遍歷方法
js中的描述測試
/** * 中序遍歷 * @param node */ inOrder (node) { if (node !== null) { this.inOrder(node.left) console.log(`data:${node.data},count:${node.count}`) this.inOrder(node.right) } }
上述例子中的輸出結果this
中序 data:2,count:1 data:23,count:1 data:28,count:1 data:34,count:3 data:43,count:1 data:45,count:1 data:67,count:1 data:78,count:1
路徑圖
spa
js中的描述
/** * 先序遍歷 * @param node */ preOrder (node) { if (node !== null) { console.log(`data:${node.data},count:${node.count}`) this.preOrder(node.left) this.preOrder(node.right) } }
上述例子中的輸出結果
先序 data:43,count:1 data:34,count:3 data:23,count:1 data:2,count:1 data:28,count:1 data:67,count:1 data:45,count:1 data:78,count:1
路徑圖
js中的描述
/** * 後序遍歷 * @param node */ postOrder (node) { if (node !== null) { this.postOrder(node.left) this.postOrder(node.right) console.log(`data:${node.data},count:${node.count}`) } }
上述例子中的輸出結果
後序 data:2,count:1 data:28,count:1 data:23,count:1 data:34,count:3 data:45,count:1 data:78,count:1 data:67,count:1 data:43,count:1
路徑圖
在二叉搜索樹中查找數據很是簡單
最小值爲樹中的最左邊的葉子節點獲得值,最大值爲最右邊子節點的值
/** * 查找最小值 * @returns {CanvasPixelArray|string|Object[]|*} */ getMin (node) { let current = node || this.root while (current.left !== null) { current = current.left } return current } /** * 查找最大值 * @returns {CanvasPixelArray|string|Object[]|*} */ getMax (node) { let current = node || this.root while (current.right !== null) { current = current.right } return current }
根據數據的大小判斷向左向右查找使得查找很是有效率
/** * 查找數據 * @param data * @returns {*} */ find (data) { let current = this.root, result = null while (current !== null) { if (data === current.data) { result = current break } else if (data < current.data) { current = current.left } else { current = current.right } } return result }
bst.getMax().data // 78 bst.getMax().count // 1 bst.getMin().data // 2 bst.getMin().count // 1
刪除數據實際上是操做二叉搜索樹中最麻煩的一部分
個人思路以下:
待刪除節點沒有子節點:
待刪除節點只有左節點或者右節點
待刪除節點既有左節點又有右節點
基於此,JS中的描述爲
/** * 刪除數據 * @param data */ remove ( data ) { this.root = this.removeDataFromNode(this.root, data) } /** * 從指定節點中刪除數據 * @param node * @param data * @returns {*} */ removeDataFromNode (node, data) { if (node !== null) { if (data === node.data) { if (node.left === null && node.right === null) { // 沒有子節點 return null } if (node.right === null) { // 只有左節點 return node.left } if (node.left === null) { // 只有右節點 return node.right } // 有作節點和右節點 // 取右節點的最小值 let tempNode = this.getMin(node.right) node.data = tempNode.data node.count = tempNode.count node.right = this.removeDataFromNode(node.right, tempNode.data) return node } else if (data < node.data) { node.left = this.removeDataFromNode(node.left, data) return node } else { node.right = this.removeDataFromNode(node.right, data) return node } } else { return null } }