实现二叉搜索树
2023-02-18 16:30:13 时间
前言
二叉搜索树是二叉树的一种
- 每个节点的左子节点一定比自身小
- 每个节点的右子节点一定比自身大
实现思路和代码
实现二叉搜索树类
- 定义内部节点类 包含以下属性
- key节点值
- left指向左子节点
- right指向右子节点
- 定义root属性表示根节点
function BinarySearchTree() {
this.root = null
function Node(key) {
this.key = key
this.left = null
this.right = null
}
}
插入节点
insert(key) {
//创建新节点
let node = new Node(key)
//判断根节点是否存在
if(this.root === null) { //根节点不存在
this.root = node
} else {
//递归比较新节点和当前节点
this.insertNode(this.root,node)
}
}
insertNode(node, newNode) {
//比较新节点和当前节点
if(newNode.key < node.key) { //在当前节点的左子节点
if(node.left === null) { //当前节点左子节点不存在
node.left = newNode
} else { //继续比较
this.insertNode(node.left, newNode)
}
} else { //在当前节点的右子节点
if(node.right === null) { //当前节点的右子节点不存在
node.right = newNode
} else { //继续比较
this.insertNode(node.right, newNode)
}
}
}
最大值
max() {
let node = this.root
while(node != null && node.right != null) {
node = node.right
}
return node
}
最小值
min() {
let node = this.root
while(node != null && node.left != null) {
node = node.left
}
return node
}
获取特定节点
search(key) {
//从根节点开始寻找
return this.searchNode(this.root, key)
}
searchNode(node, key) {
//判断节点是否存在
if(node === null) {
return false
}
if(key < node.key) { //向左查找
return this.searchNode(node.left, key)
} else if(key > node.key) { //向右查找
return this.searchNode(node.right, key)
} else {
return true
}
}
删除节点
- 找到要删除的节点
- 删除的节点为叶子节点(不存在左子节点和右子节点)删除1、5、9、12
- 删除的节点有一个节点(有一个左子节点或右子节点)
- 删除的节点有两个节点
- 删除的节点有两个几点时使用前驱节点或后继节点代替删除节点
- 前驱节点为删除节点左子节点中最大的值(5)
- 后继节点为删除节点右子节点中最小的值(9)
- 前驱节点不是删除节点的左子节点时(删除3、10):前驱节点父节点的右子节点指向前驱节点的左子节点;前驱节点的左子节点指向删除节点的左子节点
- 后继节点不是删除节点的右子节点时(删除7): 后继节点父节点的左子节点指向后继节点的右子节点;后继节点的右子节点指向删除节点的右子节点
remove(key) {
let parent = null
let current = this.root
this.isLeftChild = true
while(key != current.key) {
parent = current
if(key < node.key) {
isLeftChild = true
current = currrent.left
} else {
isLeftChild = false
current = current.right
}
}
if(current === null) return false
//删除节点为叶子节点
if(current.left === null && current.right === null) {
if(current === this.root) {
this.root = null
} else if(isLeftChild) {
parent.left = null
} else {
parent.right = null
}
}
//删除节点只有一个左子节点
else if(current.right === null) {
if(current === this.root) {
this.root = current.left
} else if(isLeftChild) {
parent.left = current.left
} else {
parent.right = current.left
}
}
//删除节点只有一个右子节点
else if(current.left === null) {
if(current === this.root) {
this.root = current.right
} else if(isLeftChild) {
parent.left = current.right
} else {
parent.right = current.right
}
}
//删除节点有两个子节点
else {
//获取后继或前驱节点
let successor = this.getSuccessor(current)
if(current === this.root) {
this.root = successor
} else if(isLeftChild) {
parent.left = successor
} else {
parent.right = successor
}
successor.left = current.left
let precursor = this.getPrecursor(current)
if(current === this.root) {
this.root = precursor
} else if(isLeftChild) {
parent.left = precursor
} else {
parent.right = precursor
}
precursor.right = current.right
}
}
获取后继、前驱节点
getSuccessor(delNode) {
let successor = delNode
let current = delNode.right
let successorParent = delNode
while(current != null) {
successorParent = successor
successor = current
current = current.left
}
if(successor != delNode.right) {
successorParent.left = successor.right
successor.right = delNode.right
}
}
getPrecursor(delNode) {
let precursor = delNode
let current = delNode.left
let precursorParent = delNode
while(current != null) {
precursorParent = precursor
precursor = current
current = current.right
}
if(precursor != delNode.left) {
precursorParent.right = precursor.left
precursor.left = delNode.left
}
}
先序遍历
- 先处理当前节点再遍历当前节点的左子树再遍历当前节点的右子树
preorderTraversal(handle) {
this.preorderTraversalNode(this.root, handle)
}
preorderTraversalNode(node, handle) {
if(node != null) {
handle(node.key)
this.preorderTraversalNode(node.left, handle)
this.preorderTraversalNode(node.right, handle)
}
}
中序遍历
- 先遍历当前节点的左子节点再处理当前节点再遍历当前节点的右子节点
middleorderTraversal(handle) {
this.middleorderTraversalNode(this.root, handle)
}
middleorderTraversalNode(node, handle){
if(node != null) {
this.middleorderTraversalNode(node.left, handle)
handle(node.key)
this.middleorderTraversalNode(node.right, handle)
}
}
后序遍历
- 先遍历当前节点的左子树再遍历右子树再处理当前节点
postorderTraversal(handle) {
this.postorderTraversalNode(this.root, handle)
}
postorderTraversalNode(node, handle) {
if(node != null) {
this.postorderTraversalNode(node.left, handle)
this.postorderTraversalNode(node.right, handle)
handle(node.key)
}
}
相关文章
- ICLR2023推荐系统投稿论文集锦
- 如何实现实时文件同步:inotify + rsyncd
- 解决jenkins打包时不能及时更新到最新代码的问题
- Microsoft Remote Desktop for Mac(微软远程连接工具) v10.8.1(2042)中英直装版
- Keepalived问题定位
- inotify-rsync文件实时同步问题记录
- springboot 之初见
- springboot 之日志配置
- springboot 之集成mybatis
- springboot 之集成Swagger2
- springboot 之集成quartz
- springboot 之集成RabbitMQ
- springboot 之集成AOP
- springboot 之集成kafka
- springboot 之集成springcloud eureka
- Lua数据结构
- Lua中函数的使用
- Lua局部变量和代码块
- Lua的控制结构
- 高低温湿热试验箱制冷剂泄漏如何检测?