第一步:假设3的左右子树高度为R3 、那么4的左子树高度为L4 = R3+1、4的右子树高度为R3、所以在右旋之后
3的平衡因子为 R3-(1+h4) = R3-(1+R3) = -1
4的平衡因子为R3-R3 = 0
第二步:假设3的左子树高度为L3、那么右子树的高度为R3 = L3+1 、4的左右子树高度分别为R4、2的左右子树高度分别为L2 、L2+2
2的平衡因子为 L2 - L3 = R2-2-(R3-1)= 1+h3-R3-1 = R3-R3=0
3的平衡因子为 (L2+1)-R3 = (R2-2+1)-R3 = R2-1-R3 = 1+h3 - 1 -R3 = R3-R3 = 0
第一步:假设4的左子树高度为L4, 、那么4的右子树高度为R4 = L4-1、5的左子树高度为1+L4、 右子树高度为L4、所以在右旋之后
5的平衡因子为 R4-R5=R4-L4=-1
4的平衡因子为 L4-(1+h5)= L4 - (1+R5) = L4 -(1+L4) = -1
第二步:假设4的左子树高度为L4、那么右子树的高度为R4 = L4+1=R5+1 、2的左右子树高度分别为L2 、L2+2
2的平衡因子为 L2 - L4 = (R2-2)-L4 = (R4+1-2)-L4 = (L4+1+1-2)-L4 = 0
4的平衡因子为 (1+h2)- R4 = 1+L2-R4 = 1+R2-2-R4 = -1+1+R4-R4 = 0
第一步:假设3的左子树高度为L3, 、那么3的右子树高度为R3 = L3+1、5的左子树高度为1+R3、 右子树高度为R3、所以在右旋之后
5的平衡因子为 R3 - R5 = R3 - R3 = 0
3的平衡因子为 L3-(1+h5) = (R3-1)-(1+R5)= R3-2-R5 = R3-2-R3 = -2
第二步:假设3的左子树高度为L3、那么右子树的高度为R3 = L3+2 、2的左右子树高度分别为L2 、L2+2
2的平衡因子为 L2-L3 = (R2-2)- (R3-2)= (1+R3-2)-R3+2 = 1
3的平衡因子为 (h2+1)- R3 = (L2+1)-R3 = (R2-2+1)-R3 = 1+R3-1-R3 = 0
<?php
$list = [];
function main() {
$arr = [1, 2, 6, 6, 7, 5, 4, 3, 8, 10, 9];
$count = count($arr);
$needReverse = true; //是否需要再继续向上找 对树进行平衡操作
$root = ''; //根节点
for($i=0;$i<$count;$i++) {
insert($root, $arr[$i], $needReverse);
}
}
function insert(&$root, $value, &$needReverse) {
global $list;
echo "需要插入的值是{$value}\n";
if(empty($root)) {//插入节点 树有变化需要继续向上找 看是否需要对树进行平衡操作
$list[$value] = [
'Lvalue' => '', //左孩子值
'Rvalue' => '', //右孩子值
'balanceValue' => 0, //平衡因子
];
$root = $value; //根节点
$needReverse = true;
} else {
if($root == $value) { //如果插入的值重复 那么不插入
$needReverse = false;
return false;
} elseif($value < $root) { //如果插入的值小于父节点
if(!insert($list[$root]['Lvalue'], $value, $needReverse)) {//向父节点的左侧插入 如果插入失败 返回false 说明有重复的值
return false;
}
if($needReverse) {//如果插入节点成功 需要对树进行平衡判断 修改最小不平衡树
switch($list[$root]['balanceValue']) {
case 0: //父节点本来的平衡因子如果是0 因为是像左插入 所以平衡因子变成1 树的高度改变 需要继续进行平衡操作
$list[$root]['balanceValue'] = 1; $needReverse=true; break;
break;
case 1://父节点本来的平衡因子如果是1 说左子树比右子树高一 左插入后 平衡因子变为2 此时需要进行转换
leftBalance($root); $needReverse=false; break;
break;
case -1://父节点本来的平衡因子是-1 说明右子树比左子树高一 左插入后 平衡因子变为0 树的高度没有改变 不需要进行平衡操作
$list[$root]['balanceValue'] = 0; $needReverse=false; break;
break;
}
}
} else {//如果插入的值大于父节点
if(!insert($list[$root]['Rvalue'], $value, $needReverse)) {//向父节点的右侧插入 如果插入失败 返回false 说明有重复的值
return false;
}
if($needReverse) {//如果插入节点成功 需要对树进行平衡判断 修改最小不平衡树
switch($list[$root]['balanceValue']) {
case 0: //父节点本来的平衡因子如果是0 因为是像右插入 所以平衡因子变成-1 树的高度改变 需要继续进行平衡操作
$list[$root]['balanceValue'] = -1; $needReverse=true; break;
break;
case 1://父节点本来的平衡因子如果是1 说左子树比右子树高一 右插入后 平衡因子变为0 树的高度未改变 不需要继续进行平衡操作
$list[$root]['balanceValue'] = 0; $needReverse=false; break;
break;
case -1://父节点本来的平衡因子是-1 说明右子树比左子树高一 右插入后 平衡因子会变成-2 此时需要进行转换
rightBalance($root, $list); $needReverse=false; break;
break;
}
}
}
}
return true;
}
//右树高的时候对最小不平衡树的处理方式
function rightBalance(&$root) {
global $list;
$value = $root;
$Rvalue = $list[$root]['Rvalue'];
switch($list[$Rvalue]['balanceValue']) {
case -1://如果中间节点 的平衡因子是-1 说明他的结构是 右右的结构 即\的结构 这时候做左旋
LBalance($root);
$list[$root]['balanceValue'] = 0;
$list[$Rvalue]['balanceValue'] = 0;
break;
case 1:// 如果中间节点的平衡因子是1 说明他的结构是 右左的结构 即>的结构 这时候先右旋 然后再左旋
$RLValue = $list[$Rvalue]['Lvalue'];
switch($list[$RLValue]) {//如图所示 很清晰哦
case 0://如果右子树的左子树的平衡因子为0
$list[$root]['balanceValue'] = 0 ;
$list[$Rvalue]['balanceValue'] = 0;
break;
case -1: //如果右子树的左子树平衡因子为-1
$list[$root]['balanceValue'] = 1;
$list[$Rvalue]['balanceValue'] = 0;
break;
case 1: //如果右子树的左子树的平衡因子为1
$list[$root]['balanceValue'] = 0;
$list[$LValue]['balanceValue'] = -1;
break;
}
$list[$RLValue]['balanceValue'] = 0;
RBalance($Rvalue);
LBalance($root);
break;
}
}
//左树高的时候对最小不平衡树的处理方式
function leftBalance(&$root) {
global $list;
$value = $root;
$Lvalue = $list[$root]['Lvalue'];
switch($list[$Lvalue]['balanceValue']) {
case 1://如果中间节点 的平衡因子是1 说明他的结构是 左左的结构 即/的结构 这时候做右旋
RBalance($root);
$list[$root]['balanceValue'] = 0;
$list[$Rvalue]['balanceValue'] = 0;
break;
case -1:// 如果中间节点的平衡因子是-1 说明他的结构是 左右的结构 即<的结构 这时候先左旋 然后再右旋
$LRValue = $list[$Lvalue]['Rvalue'];
switch($list[$LRValue]) {//自己试试看看这里怎么写
case 0://如果左子树的右子树的平衡因子为0
break;
case -1: //如果左子树的右子树平衡因子为-1
break;
case 1: //如果左子树的右子树的平衡因子为1
break;
}
LBalance($Lvalue);
RBalance($root);
break;
}
}
//纯左旋
function LBalance(&$root) {
$Rvalue = $list[$root]['Rvalue'];
$list[$root]['Rvalue'] = $list[$Rvalue]['Lvalue'];
$list[$Rvalue]['Lvalue'] = $root;
$root = $Rvalue;
}
//纯右旋
function RBalance(&$root) {
$Lvalue = $list[$root]['Lvalue'];
$list[$root]['Lvalue'] = $list[$Lvalue]['Rvalue'];
$list[$Lvalue]['Rvalue'] = $root;
$root = $Lvalue;
}
main();
图是作者辛辛苦苦画的 请大家不要盗图 如果想使用请标明来源