一:二叉树和二叉搜索树
二:实现二叉搜索树
2.1 创建Node类表示二叉搜索树中的每个节点
1 2 3 4 5 6 7 8 9 10 11 12
| class Node { constructor(data, left, right) { this.data = data this.left = left this.right = right this.count = 1 } }
|
该图为二叉搜索树数据结构的组织方式,对于树,我们使用两个指针,一个指向左侧子节点,一个指向右侧右节点
2.2 创建BSTree 类的基本结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class BSTree { constructor() { this.root = null; } _removeNode(node, data) { } remove(data) { this.root = this._removeNode(this.root, data); } insert(data) { } find(data) { } getMinNode(node = this.root) { } getMaxNode(node = this.root) { } }
|
2.3 实现insert()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| insert (data) { let newNode = new Node(data, null, null) if (this.root === null) { this.root = newNode } else { let currentNode = this.root let parentNode = null while (true) { parentNode = currentNode if (newNode.data < currentNode.data) { currentNode = currentNode.left if (!currentNode) { parentNode.left = newNode break } }
else if (newNode.data > currentNode.data) { currentNode = currentNode.right if (!currentNode) { parentNode.right = newNode break } }
else if (newNode.data === currentNode.data) { currentNode.count++ break } } } }
|
- 首先创建一个新的节点
newNode
,该节点包含要插入的数据
- 检查根节点是否为空,若为空,说明这是第一个插入的节点,将根节点指向
newNode
- 如果根节点不为空,则需要找到合适的位置插入该节点
- 初始化当前节点
currentNode
为根节点this.root
,并且初始化父节点parentNode
为空
- 进入循环,直到找到合适的位置插入节点或者遇到相同的数据
- 在每次循环中,更新父节点
parentNode
为当前节点currentNode
- 判断要插入的节点值和当前节点值的大小关系
- 如果要插入的节点值小于当前节点值,说明要插入的节点应该在当前节点的左子树中
- 更新当前节点为当前节点的左子节点
currentNode.left
- 如果当前节点的左子节点为空,说明找到了插入位置,将新节点
newNode
设置为当前节点的左子节点,并且跳出循环
- 如果要插入的节点值大于当前节点值,说明要插入的节点应该在当前节点的右子树中
- 更新当前节点为当前节点的右子节点
currentNode.right
- 如果当前节点的右子节点为空,说明找到了插入位置,将新节点
newNode
设置为当前节点的右子节点,并且跳出循环
- 如果要插入的节点值等于当前节点值,说明要插入的节点与当前节点的值相同。
- 将当前节点的计数器
count
加一,表示重复出现的次数。
- 跳出循环。
2.4 实现find()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| find (data) { let currentNode = this.root while (currentNode) { if (currentNode.data == data) { return currentNode } else if (currentNode.data < data) { currentNode = currentNode.right } else { currentNode = currentNode.left } } return null }
|
2.5 实现getMinNode()和getMaxNode()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| getMinNode (node = this.root) { let currentNode = node while (currentNode.left) { currentNode = currentNode.left } return currentNode }
getMaxNode (node = this.root) { let currentNode = node while (currentNode.right) { currentNode = currentNode.right } return currentNode }
|
2.6 实现remove()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| _removeNode (node, data) { if (node === null) { return null } if (data === node.data) { if (node.left === null && node.right === null) { return null }
if (node.left === null) return node.right
if (node.right === null) return node.left
let tmpNode = this.getMinNode(node.right) node.data = tmpNode.data node.right = this._removeNode(node.right, tmpNode.data) return node } else if (data < node.data) { node.left = this._removeNode(node.left, data) return node } else { node.right = this._removeNode(node.right, data) return node } }
remove (data) { this.root = this._removeNode(this.root, data); }
|
- 代码接收两个参数:
data
表示待删除的节点的值,node
表示当前递归调用的节点。
- 如果待删除节点的值等于当前节点的值(
data == node.data
),则进入条件判断。
- 如果当前节点是叶子节点(即没有左子节点和右子节点),则将其置为null,表示删除该节点。
- 如果当前节点只有左子节点而没有右子节点,则返回其左子节点,将其作为当前节点的父节点的新子节点。
- 如果当前节点只有右子节点而没有左子节点,则返回其右子节点,将其作为当前节点的父节点的新子节点。
- 如果当前节点既有左子节点又有右子节点,则需要找到待删除节点的右子树上的最小值来替代待删除节点。
- 通过调用
getMinNode(node.right)
方法,找到右子树上的最小值所在的节点,并将其赋值给临时节点tmpNode
。
- 将临时节点
tmpNode
的值复制到待删除节点node
,相当于用右子树上的最小值替代了待删除节点。
- 再次递归调用
_removeNode()
方法,传入当前节点的右子节点和临时节点的值,以删除右子树上的最小值节点。
- 最后,返回当前节点
node
,表示删除操作完成。
- 如果待删除节点的值小于当前节点的值(
data < node.data
),则递归调用_removeNode()
方法,传入当前节点的左子节点和待删除节点的值,以在左子树上继续删除操作。
- 如果待删除节点的值大于当前节点的值,则递归调用
_removeNode()
方法,传入当前节点的右子节点和待删除节点的值,以在右子树上继续删除操作。
- 最终,整个删除操作完成后,返回当前节点
node
,并将其作为父节点的新子节点。
三:测试数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| let myTree = new BSTree();
myTree.insert(20); myTree.insert(13); myTree.insert(7); myTree.insert(9); myTree.insert(15); myTree.insert(14); myTree.insert(42); myTree.insert(22); myTree.insert(21); myTree.insert(24); myTree.insert(57);
|
1 2 3 4
| console.log(myTree.getMaxNode()); console.log(myTree.getMinNode()); myTree.remove(7) console.log(myTree.find(7));
|
四:全部代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| class Node { constructor(data, left, right) { this.data = data this.left = left this.right = right this.count = 1 } }
class BSTree { constructor() { this.root = null }
insert (data) { let newNode = new Node(data, null, null) if (this.root === null) { this.root = newNode } else { let currentNode = this.root let parentNode = null while (true) { parentNode = currentNode if (newNode.data < currentNode.data) { currentNode = currentNode.left if (!currentNode) { parentNode.left = newNode break } }
else if (newNode.data > currentNode.data) { currentNode = currentNode.right if (!currentNode) { parentNode.right = newNode break } }
else if (newNode.data === currentNode.data) { currentNode.count++ break } } } }
getMinNode (node = this.root) { let currentNode = node while (currentNode.left) { currentNode = currentNode.left } return currentNode }
getMaxNode (node = this.root) { let currentNode = node while (currentNode.right) { currentNode = currentNode.right } return currentNode }
find (data) { let currentNode = this.root while (currentNode) { if (currentNode.data == data) { return currentNode } else if (currentNode.data < data) { currentNode = currentNode.right } else { currentNode = currentNode.left } } return null } _removeNode (node, data) { if (node === null) { return null } if (data === node.data) { if (node.left === null && node.right === null) { return null }
if (node.left === null) return node.right
if (node.right === null) return node.left
let tmpNode = this.getMinNode(node.right) node.data = tmpNode.data node.right = this._removeNode(node.right, tmpNode.data) return node } else if (data < node.data) { node.left = this._removeNode(node.left, data) return node } else { node.right = this._removeNode(node.right, data) return node } } remove (data) { this.root = this._removeNode(this.root, data); } }
let myTree = new BSTree();
myTree.insert(20); myTree.insert(13); myTree.insert(7); myTree.insert(9); myTree.insert(15); myTree.insert(14); myTree.insert(42); myTree.insert(22); myTree.insert(21); myTree.insert(24); myTree.insert(57); console.log(myTree);
|