史上最清晰講解平衡二叉樹的創建

                           

                           

第一步:假設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();

圖是作者辛辛苦苦畫的 請大家不要盜圖 如果想使用請標明來源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章