基本二叉树
二叉树用代码实现的基本逻辑在于:自身有一个key值,以及含有左右两个节点指针(在代码中,实现起来跟链表类似)
class Node{
this.key = key
this.left = null
this.right = null
this.root = root
}
常用的方法
insert(key)
:向树种插入一个新的键
insert(key){
if(node.left ==null){
node.left = new Node(key)
}else{
this.insert(node.left,key)
}
if(node.right ==null){
node.right = new Node(key)
}else{
this.insert(node.right,key)
}
}
search()
:查找一个数min()
:返回最小的值max()
:返回最大的值remove()
:移除某个值
树的遍历
中序遍历
具体规则为左-根-右
inOrderTraverseNode(node,callback){
if(node != null){
this.inOrderTraverseNode(node.left,callback)
callback(node.key)
this.inOrderTraverseNode(node.right,callback)
}
}
先序遍历
具体规则为根-左-右
preOrderTraverseNode(node,callback){
if(node!=null){
callback(node.key)
this.preOrderTraverseNode(node.left,callback)
this.preOrderTraverseNode(node.right,callback)
}
}
后序遍历
具体规则左-右-根
postOrderTraverseNode(node,callback){
if(node !=null){
this.postOrderTraverseNode(node.left,callback)
this.postOrderTraverseNode(node.right,callback)
callback(node.key)
}
}
搜索树中的值
最小值
//对于找值来说,最小值都存在树的最左下角
minNode(node){
let current = node
while(current !=null && current.left != null){
current = current.left
}
return current
}
最大值
//最大值存在于树的最右下角
maxNode(node){
let current = node
while(current !=null && current.right != null){
current = current.right
}
return current
}
特定的值
//key是需要找的值 node.key为当前节点的值
searchNode(node,key){
if(node ==null){
return false
}
if(node.key>key){
return this.searchNode(node.left,key)
}else if(node.key<key){
return this.searchNode(node.right,key)
}else{
return ture
}
}
删除节点
//删除前得先遍历树,找到需要删除的值
removeNode(node,key){
if(node ==null){
return null
}
if(node.key>key){
node.left = this.removeNode(node.left,key)
return node
}else if(node.key<key){
node.right = this.removeNode(node.right,key)
return node
}else{
//分为三种情况,第一种情况直接移除一个叶子节点
if(node.left ==null && node.right==null){
node = null
return node
}
//第二种情况,移除一个有一边节点的节点,此时需要将父节点直接指向该节点的子节点即可
if(node.left ==null){
node = node.right
return node
}else if(node.right ==null){
node = node.left
return node
}
第三种情况,移除一个拥有两个子节点的节点,此时需要找到该节点中最小的节点,将该节点的值替换到需要删除的节点中,并把最小的节点删除
const changemin = this.minNode(node.right)
node.key = changemin.key
node.right= this.remove(node.right,key)
return node
}
}
自平衡树
任何一个节点左右两侧子树的高度差最多为1
计算高度
getNodeHeight(node){
if(node ==null){
retuen -1
}
return Math.max(
this.getNodeHeight(node.left),this.getNodeHeight(node.right)
)
}
在AVL树中要计算右子树高度和左子树高度的差值(hr-hl),结果只能是0,-1,1,如果不是这三个值,就需要平衡
const BalanceFactor{
UNBALANCED_RIGHT:1,
SLIGHTLY_UNBALANCED_RIGHT:2,
BALANCED:3,
SLIGHTLY_UNBALANCED_LEFT:4,
UNBALANCED_LEFT:5
}
getBalanceFactor(node){
const heightDifference = this.getNodeHeight(node.left) -this.getNodeHeight(node.right)
switch(heightDifference){
case -2:
return BalanceFactor.UNBALANCED_RIGHT;
case -1:
return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT;
case 1:
return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT
case 2:
return BalanceFactor.UNBALANCED_LEFT
default:
return BalanceFactor.BALANCED
}
}
平衡操作(AVL旋转)
左-左(LL)向右的单旋转
左侧节点的高度 大于 右侧子节点的高度,并且左侧子节点也是平衡或者左侧较重的
rotationLL(node){
const tmp = node.left
node.left = tmp.right
tmp.right = node
return tmp
}
右-右(RR)向左的单旋转
右侧节点的高度 大于 左侧子节点的高度,并且左侧子节点也是平衡或者右侧较重的
rotationRR(node){
const tmp = node.right
node.right = tmp.left
tmp.left = node
return tmp
}
左-右(LR)向右的双旋转(先LL旋转,再RR旋转)
左侧节点的高度 大于 右侧子节点的高度,并且左侧子节点右侧较重,因此先左旋转修复,再对不平衡的节点右旋转修复
rotationLR(node){
node.left = this.rotationRR(node.left)
return this.rotationLL(node)
}
右-左(RL)向左的双旋转(先RR旋转,再LL旋转)
右侧节点的高度 大于 左侧子节点的高度,并且右侧子节点左侧较重
rotationRL(node){
node.right = this.rotationLL(node.right)
return this.rotationRR(node)
}
在AVL树中插入节点
在AVL树中移除节点
红黑树
红黑树跟AVL树类似,但是如果多次进行插入和删除,红黑树是更好的选择
- 每个节点不是红的就是黑的
- 根节点是黑的
- 所有叶节点都是黑的(NULL引用表示的节点)
- 如果一个节点是红的,他的两个叶子节点都是黑的
- 不能有两个相邻的红节点,一个红节点不能有红的父节点或者子节点
- 从给定的节点到它的后代节点的所有路径包含相同数量的黑色节点