如下图
你会发现使用右单旋与左单旋无法让其恢复为二叉平衡树
那是因为 节点6 与 节点7 这两个节点是变化分支。且是唯一的最深分支
左右双旋
当要对某个节点进行右单旋时
如果变化分支是唯一的最深分支,那么我们要对新根进行左单旋
然后再进行右单旋
这样的旋转叫做左右双旋
示例
图示
左右双旋过程动态图
最终图示

右左双旋
当要对某个节点进行左单旋时
如果变化分支是唯一的最深分支,那么我们要对新根进行右单旋
然后再进行左单旋
这样的旋转叫做右左双旋
左右双旋与右左双旋代码
class Node {constructor(value) {this.value = value;this.left = null;this.right = null;}}let node2 = new Node('2');let node5 = new Node('5');let node6 = new Node('6');let node7 = new Node('7');let node8 = new Node('8');node8.left = node7;node7.left = node6;node6.left = node5;node5.left = node2;/*** 判断是否为二叉平衡树* 平衡二叉的满足条件* 根节点的左子树与右子树的高度差不能超过1* 这棵二叉树的每个子树的符合第一条* @param {*} root 根节点* @returns Boolean*/function isBalanceTree(root) {if (!root) return true;// 获取左右子树的深度let left = getDeep(root.left);let right = getDeep(root.right);// 当左子树与右子树的深度差大于1说明不是二叉平衡树if (Math.abs(left - right) > 1) return false;// 遍历这个二叉树的每一个子树else return isBalanceTree(root.left) && isBalanceTree(root.right);}/*** 获取二叉树的深度* @param {*} root 节点* @returns Number 返回左右子树中最深的层数*/function getDeep(root) {if (!root) return 0;let left = getDeep(root.left);let right = getDeep(root.right);return Math.max(left, right) + 1;}/*** 利用单旋将二叉不平衡树变为二叉平衡树* @param {*} root 跟节点* @returns 返回平衡之后的根节点*/function change(root) {if (isBalanceTree(root)) return root; // 返回平衡之后的根节点// 走到这说明不是二叉平衡树// 判断平不平衡需要从下往上判断// 判断对二叉树进行平衡操作要按照后序遍历的顺序// 后序遍历 先左子树 后右子树 最后自己// 为何进行后序遍历,当根节点不是二叉平衡树,可能对子树进行单旋操作就成为二叉平衡树if (root.left != null) root.left = change(root.left); // change函数会返回平衡之后的跟节点,故需要接收返回的的根节点if (root.right != null) root.right = change(root.right);// change函数会返回平衡之后的跟节点,故需要接收返回的的根节点// 获取深度let leftTree = getDeep(root.left);let rightTree = getDeep(root.right);// 判断那里不符合二叉平衡树的要求if (Math.abs(leftTree - rightTree) < 2) return root;if (leftTree < rightTree) { //左浅 右深 左单旋// 获取变化分支的深度let changeTree = getDeep(root.right.left)// 获取不变分支的深度let noChangeTree = getDeep(root.right.right)// 当变化分支的深度大于不变化的分支时需要右左双旋if (changeTree > noChangeTree) {//将右子树进行右单旋root.right = rightRotate(root.right)}return leftRotate(root)} else if (leftTree > rightTree) { //左深 右浅 右单旋// 获取变化分支的深度let changeTree = getDeep(root.left.right)// 获取不变分支的深度let noChangeTree = getDeep(root.left.left)// 当变化分支的深度大于不变化分支的深度将进行左右单旋if (changeTree > noChangeTree) {// 将其左子树进行单旋root.left = leftRotate(root.left)}return rightRotate(root)}}/*** 左单旋* 旋转节点:不平衡的节点为旋转节点* 新根:旋转节点的右子树的根节点* @param {*} root 旋转节点* @returns 新的根节点*/function leftRotate(root) {// 找到新根let newNode = root.right;// 找到变化分支let changeNode = newNode.left;// 当前旋转节点的右孩子为变化分支root.right = changeNode;// 新根的左孩子为旋转节点newNode.left = root;// 返回新的根节点console.log('l')return newNode;}/*** 右单旋* 旋转节点:不平衡的节点为旋转节点* 新根:旋转节点的左子树的根节点* @param {*} root 旋转节点* @returns 新的根节点*/function rightRotate(root) {// 找到新根let newNode = root.left;// 找到变化分支let changeNode = newNode.right;// 当前旋转节点的左孩子为变化分支root.left = changeNode// 新根的右孩子为旋转节点newNode.right = root;// 返回新的根节点console.log('r')return newNode;}// 测试左右双旋let root = change(node8);console.log(root)

