典型的:HTML 就是一個樹結構
(一)二叉樹
特點:
1. 每一個父結點都有兩個子結點
2. 左側子節點存儲比父結點小的值,右側子節點存儲比父結點大的值
操作:增刪改查
代碼:
// 定義Node節點
class Node {
constructor (value) {
this.value = value,
this.left = null,
this.right = null
}
}
class Tree {
constructor () {
this.root = null // 首先定義根節點 爲null
}
// 尋找插入節點
insertNode (node, CurrentNode){
if (node.value > CurrentNode.value) {
if (CurrentNode.right) {
this.insertNode(node, CurrentNode.right) // 遞歸 繼續向下尋找
} else {
CurrentNode.right = node
}
} else if (node.value < CurrentNode.value) {
if (CurrentNode.left) {
this.insertNode(node, CurrentNode.left) // 遞歸 繼續向下尋找
} else {
CurrentNode.left = node
}
}
}
// 插入
insert (value) {
var node = new Node(value)
if (this.root) {
this.insertNode(node, this.root)
// 因爲要遞歸 所以 單獨封裝方法
} else {
this.root = node // 沒有根節點 設置爲根節點
}
}
// 遍歷節點
traverse (callback) {
this.traver(this.root, callback)
}
traver(node, callback) {
if (node === null) {
return
}
this.traver(node.left, callback)
callback(node.value) // 中序遍歷 後序遍歷 前序遍歷等等高改變這行代碼位置
this.traver(node.right, callback)
}
// 刪除節點
remove () {
}
// 二叉樹最小值 找到最左節點
getMin () {
// 空樹返回null
if (this.root === null) {
return null
}
var current = this.root
while(current.left) {
current = current.left
}
return current.value
}
// 獲取二叉樹搜索樹最大值 最右節點
getMax () {
// 空樹返回null
if (this.root === null) {
return null
}
var current = this.root
while(current.right) {
current = current.right
}
return current.value
}
// 獲取樹
getTree () {
return this.root
}
}
var tree = new Tree()
tree.insert(12)
tree.insert(13)
tree.insert(4)
tree.insert(13)
console.log(tree.getTree())
tree.traverse((value) => {
console.log('VALUE', value)
})
console.log(tree.getMin())
console.log(tree.getMax())
還有刪除一個結點,情況複雜 單獨貼
移除一個結點 三種情況:
1. 該結點沒有子節點 直接移除就可以
2. 該結點有一個子結點,將子結點替換爲該結點
3. 該結點有兩個子結點,這種情況最特殊 需要重新計算(最好的方案,一句話總結:替換爲右側子樹的最小子結點)
一個結點,它左側的樹的所有值都比它小,它右側的所有值都比他大,比它小才能往左側走,比它大才能往右側去
// 刪除結點 先查找 再刪除
removeNode (node, value) {
if (node === null) { return null }
if (value < node.value) { // 左側找
node.left = this.removeNode(node.left, value)
return node
} else if (value > node.value) { // 右側找
node.right = this.removeNode(node.right, value)
return node
} else { // 值相等 找到 node 就是當前結點
if (node.left === null && node.right === null) { // 葉結點 沒有子結點 直接刪除 反向構建 一層層 return
node = null
return node
}
if (node.left === null && node.right) {
node = node.right
return node // 右結點替換
}
if (node.right === null && node.left) {
node = node.left
return node // 左結點替換
}
if (node.right && node.left) { // 左右結點都存在
var minNode = this.findMinRight(node.right)
node.value = minNode.value
node.right = this.removeNode(node.right, node.value) // 從替換元素查找 刪除value的元素
return node
}
}
}
// 查找傳入結點的最小子結點
findMinRight (node) {
if (node === null) {
return null
}
while (node.left) {
node = node.left
}
return node
}
// 刪除節點 重新構建樹
remove (value) {
this.root = this.removeNode(this.root, value)
}
慢慢研究 一環套一環。。。頭禿