Ruby on Rails 5+ postgresql jsonb 查詢
阿新 • • 發佈:2021-10-20
二叉樹結構圖:
樹頂部的節點是根節點,有子元素的節點叫做內部節點,沒有子元素的節點叫做外部節點或葉節點
節點和它的子節點稱為子樹
節點左側儲存小值,節點右側儲存大值
使用js實現二叉樹結構,待實現功能如下:
insert(key) 向樹中插入新的鍵 search(key) 在樹中查詢一個鍵,如果節點存在,返回true,如果不存在,返回false inOrderTraverse() 通過中序遍歷方式遍歷所有節點(由小到大排序) preOrderTraverse() 通過先序遍歷方式遍歷所有節點() postOrderTraverse() 通過後序遍歷方式遍歷所有節點 min() 返回樹中最小的值/鍵 max() 返回樹中最大的值/鍵 remove(key) 從樹中移除某個鍵程式碼(二叉樹資料結構會大量運用遞迴):
class Node{ // 節點 constructor(key){ this.key = key this.left = null this.right = null } } const compare = { Less_Than : -1, Bigger_Than : 1 } function defaultCompare(a, b){ // 比較大小 if(a === b){ return 0 } return a < b? compare.Less_Than : compare.Bigger_Than }
建立二叉樹類:
class BinarySearchTree{ // 二叉樹 constructor(compareFn = defaultCompare){ this.compareFn = compareFn // 用來比較節點值 this.root = null // 根節點 } }
插入節點:
根據左小右大,通過遞迴逐級下查,查詢待新增節點的位置
insert(key){ if (this.root === null){ this.root = new Node(key) } else{this._insertNode(this.root, key) } } _insertNode(node, key){ if(this.compareFn(key, node.key) === compare.Less_Than){ if(node.left === null){ node.left = new Node(key) }else{ this._insertNode(node.left, key) } }else{ if(node.right === null){ node.right = new Node(key) }else{ this._insertNode(node.right, key) } } }
查詢鍵是否存在:
和插入節點類似,通過遞迴,沿著一個方向逐級向下查詢,當查到null時,即不存在
search(key){ return this._searchNode(this.root, key) } _searchNode(node, key){ if(node === null){ return false } if(this.compareFn(key, node.key) === compare.Less_Than){ return this._searchNode(node.left, key) } else if(this.compareFn(key, node.key) === compare.Bigger_Than){ return this._searchNode(node.right, key) } else{ return true } }
中序遍歷所有節點的大小(由小到大排序):
callback引數傳入一個回撥函式,用來遍歷後執行
例如傳入const a = (val) => { console.log(val) }
返回結果是:由小到大依次排列的節點值,例:1,2,3,4,5,6,7,8,9
inOrderTraverse(callback){ this._inOrderTraverseNode(this.root, callback) } _inOrderTraverseNode(node, callback){ if(node != null){ this._inOrderTraverseNode(node.left, callback) callback(node.key) this._inOrderTraverseNode(node.right, callback) } }
先序遍歷:
和中序遍歷類似,只是遍歷結果發生了改變
preOrderTraverse(callback){ this._preOrderTraverseNode(this.root, callback) } _preOrderTraverseNode(node, callback){ if(node !== null){ callback(node.key) this._preOrderTraverseNode(node.left, callback) this._preOrderTraverseNode(node.right, callback) } }
後序遍歷:
和中序遍歷類似,只是遍歷結果發生了改變
postOrderTraverse(callback){ this._postOrderTraverseNode(this.root, callback) } _postOrderTraverseNode(node, callback){ if(node !== null){ this._postOrderTraverseNode(node.left, callback) this._postOrderTraverseNode(node.right, callback) callback(node.key) } }
最小值查詢:
直接查詢最左側子樹的最左側節點
min(){ return this._minNode(this.root) } _minNode(node){ if(node !== null && node.left !== null){ return this._minNode(node.left) }else{ return node } }
最大值查詢:
直接查詢最右側子樹的最右側節點
max(){ return this._maxNode(this.root) } _maxNode(node){ if(node !== null && node.right !== null){ return this._maxNode(node.right) }else{ return node } }
刪除指定節點:
首先,找到待刪除節點,若找不到,則返回原樹
若找到,分為三種情況:
1.節點為葉節點,即左右節點都為null,直接刪掉即可
2.節點為內部節點但左右有一側為null,則用另一側節點代替當前節點
3.節點左右側都有,則需要找到右側樹中的最小值來取代當前節點,然後再對右側樹執行一個末位節點刪除,刪除掉重複的原替代值
remove(key){ this.root = this._removeNode(key, this.root) } _removeNode(key, node){ if(node === null){ return null } if(this.compareFn(key, node.key) === compare.Less_Than){ node.left = this._removeNode(key, node.left) return node }else if(this.compareFn(key, node.key) === compare.Bigger_Than){ node.right = this._removeNode(key, node.right) return node }else{ // 第一種情況,刪除末位節點 if(node.left === null && node.right === null){ node = null return node } // 第二種情況,左或右節點為Null if(node.left === null){ node = node.right return node }else if(node.right === null){ node = node.left return node } // 第三種情況,左右都有子節點 // 找到右側子樹中最小的節點 const newNode = this._minNode(node.right) node.key = newNode.key // 刪除右側子樹中最小的節點 this._removeNode(newNode.key, node.right) return node } }