//二叉树 class BinarySearchTree { constructor(){ this。root = null this .Node = class { constructor(key){ this。键 =键入 此。left = null 这个。right = null } } } 插入(键){ 让节点 = 新本 .Node(键) ,如果(!此。根){ 此。root = node } else { this。insertNode(此。根,节点) } } insertNode(节点,newNode){ //如果小于当前节点,插入到节点左侧,否则插入右侧 如果(节点。关键 > newNode。键){ 如果(节点。左){ 此。insertNode(节点。左,newNode) } else { 节点。left = newNode } } 否则 { 如果(节点。右){ 此。insertNode(节点。右,newNode) } else { 节点。right = newNode } } } //中序遍历是一种以上行顺序访问BST所有节点的方式,也就是以最小到最大的顺序访问所有节点。中序遍历应用的一种就是对 树进行排序inOrderTraverse(回调){ 函数 inOrderTraverseNode(节点,回调){ 如果(节点){ inOrderTraverseNode(节点。左,回调) 回调(节点。键) inOrderTraverseNode(节点。右,回调) } } inOrderTraverseNode(此。根,回调) } //先序遍历是以优于后代节点的顺序访问每个节点的先序遍历的一种应用是打印一棵树的结构化文档 preOrderTraverse(callBack){ function preOrderTraverseNode(node,callBack){ if(node ){ 回调(节点。键) preOrderTraverseNode(节点。左,回调) preOrderTraverseNode(节点。右,回调) } } preOrderTraverseNode(此。根,回调) } //后序遍历则是先访问节点的后代节点,在访问节点本身,后序遍历的一个应用是计算一个目录和它子目录中所有文件所占空间的大小 postOrderTraverse(callBack){ function postOrderTraverseNode(node回调){ 如果(节点){ postOrderTraverseNode(节点。左,回调) postOrderTraverseNode(节点。右,回调) callBack(节点。键) } } postOrderTraverseNode(此。根,回调) } //搜索节点树最小值,其实就是最左的值 min(){ let node = this。根 而(节点。左){ 节点 =节点。左 } 返回节点。key } //搜索节点数最大值,其实就是最右侧的值 max(){ let node = this。根 而(节点。右){ 节点 =节点。对 } 返回节点。关键 } //搜索特定的值 的搜索(键){ 函数 searchNode(键,节点){ 如果(键<节点。键){ 返回 searchNode(密钥,节点。左) } 否则如果(键>节点。键){ 返回 searchNode(关键节点。右) } else { return node } } 返回 searchNode(键,这个。根) } //删除一个节点 remove(key){ this。root = this。的removeNode(此。根,密钥) } 的removeNode(节点,关键){ 如果(!节点){ 返回NULL } 如果(节点。键 >键){ 节点。左 = 这个。的removeNode(节点。左,键) 返回节点 } 否则如果(节点。键 <键){ 节点。右 = 此。removeNode(节点,右键,键) 返回节点 } 其他 { //第一种情况:只有一个叶节点 ,如果(!节点离开!&&节点右){ node = null 返回节点 } //第二张情况:有一个子节点 ,如果(!节点左){ 节点=节点。正确的 返回节点 } 否则如果(!节点。右){ 节点=节点。左 返回节点 } //第三种情况:有两个子节点 //找到当前节点右侧树的最小值(最左侧的值)替代当前节点,并删除当前节点右侧树的最小值 let aux = node。右 而( AUX。左){ 辅助 =辅助。留下 } 节点。键 = 辅助。关键 节点。右 = 此。的removeNode(节点。右,辅助,关键) 返回节点 } } //自平衡树(AVL树) // AVL树是一种自平衡树。添加或则移除节点时,AVL树会尝尝自平衡。任意一个节点的左子树和右子树高度最多相差1 ,添加或移动节点是,AVL树会尽可能转换为完全树 //在AVL树中插入或者移除节点和BST完全相同。然而,AVL树的不同之处在于我们需要检查它的平衡因子,如果有需要,则将其逻辑用于树的平衡。 insertAVL(键){ 如果(!此。根){ 此。root = new this .Node(key) } else { //顶部也可能因为自平衡而重置 此。root = this。insertNodeAVL(此。根,密钥) } } insertNodeAVL(node,element){ if(node === null){ node = new this .Node(element) } 否则 { 如果(节点。关键 >元素){ 节点。左 = 这个。insertNodeAVL(节点左,元件) 如果(节点。左 ==!空 {) //判定平衡因子 如果(此。heightNode(节点。左) - 此。heightNode(节点。右)> 1){ 如果(元件<节点。左侧。键){ 节点= 这个。rotationLL(节点) } else { 节点= 这个。rotationLR(节点) } } } } 否则如果(节点。关键 <元件){ 节点。右 = 此。insertNodeAVL(节点。右,元件) 如果(节点。右 ==!空 {) 如果(此。heightNode(节点。右) - 此。heightNode(节点。左)> 1){ 如果(元件>节点。右。键){ 节点= 这个。rotationRR(节点) } else { 节点= 这个。旋转RL(节点) } } } } } 返回节点 } //计算平衡因子的高度 //在VAL树中,需要对每个节点计算右子树的高度(hr)和左子树高度(hl)的差值,该值应为0,1,-1如果结果不是这三个值之一,则需要平衡该AVL树,这就是平衡因子的概念 heightNode(node){ if(node === null){ return - 1 } else { return Math。最大值(本。heightNode(节点。左),此。heightNode(节点。右))+ 1 } } //(节点位置)节点操作 //右 - 右(RR)向左单旋转 //左 - 左(LL)向右单旋转 //左 - 右(LR)向右双旋转先做一次向左单旋转,在做一次向右单旋转 //右 - 左(RL)向左双旋转先做一次向右单旋转,在做一次向左单旋转 rotationRR(node){ let right = node。右 节点。右 = 右。左 右。left = node return right } rotationLL(node){ let left = node。左 节点。左 = 左。右 左。right =节点 return left } rotationLR(node){ 节点。左 = 这个。rotationRR(节点。左) 返回这个。rotationLL(节点) } rotationRL(节点){ 节点。右 = 此。rotationLL(节点。右) 返回这个。rotationRR(节点) } } 让tree = new BinarySearchTree() 树。insertAVL(11) 树。insertAVL(7) 树。insertAVL(15) 树。insertAVL(5) 树。insertAVL(3) 树。insertAVL(9) 树。insertAVL(10) 树。insertAVL(13) 树。insertAVL(12) 树。insertAVL(14) 树。insertAVL(20) 树。insertAVL(18) 树。insertAVL(25) 树。insertAVL(6) // tree.insertAVL(11) 树。preOrderTraverse(项目=> 控制台。日志(项))