二叉搜索树是一种特殊的二叉树,它满足以下条件:

  • 非空左子树的所有值小于其根节点的值。
  • 非空右子树的所有值大于其根节点的值。
  • 左右子树均为二叉搜索树。

因为二叉搜索树是特殊的二叉树,代码实现上表现为继承,并且为了以后方便,我们在一般二叉树节点上添加三个方法:

function isLeaf(){
    return (!$this->leftNode) && (!$this->rightNode);
}

function isHalf(){
    return (!$this->isLeaf()) && (!$this->isFull());
}

function isFull(){
    return $this->leftNode && $this->rightNode;
}

这三个方法是用来反应节点子树数量的。

在正式书写代码之前我们先观察一下二叉树,我们可以发现,二叉搜索树中值最小的在二叉树的左下角,二叉搜索树值最大的在二叉树的右下角,据此我们可以写出二叉搜索树的查找最值节点的两个方法。

class Node_bst extends Node_tree{
    function __construct($value=NULL){
        parent::__construct($value);
    }

    static function findMax($bst){
        if(!($bst instanceof Node_bst)){
            return NULL;
        }
        while($bst->rightNode){
            $bst = $bst->rightNode;
        }
        return $bst;
    }

    static function findMin($bst){
        if(!($bst instanceof Node_bst)){
            return NULL;
        }
        while($bst->leftNode){
            $bst = $bst->leftNode;
        }
        return $bst;
    }

}

在二叉搜索树中找到值为X的节点,如果X小于根节点的值,那么如果二叉搜索树存在该值,那么一定在左子树中;如果X大于根节点的值,如果二叉搜索树存在该值,那么一定在右子树中。如果X等于根节点的值,还用说嘛。这就是在二叉搜索树中查找值为X的节点的思路。

static function find($bst,$data){
    if(!($bst instanceof Node_bst)){
        return NULL;
    }
    while($bst){
        if($bst->data>$data){
            $bst = $bst->leftNode;
        }else if($bst->data<$data){
            $bst = $bst->rightNode;
        }else{
            return $bst;
        }
    }
    return NULL;
}

到现在我们所讨论的操作都是对于一棵现成的二叉搜索树,那么二叉搜索树该如何构建呢?

在二叉搜索树中插入节点不能随便插入,毕竟根据定义节点所在的位置是有限制的。

static function insert($bst,$data){
    if(!($data instanceof $bst)){
        $data = new Node_bst($data);
    }

    if($data->data<$bst->data){
        if(!$bst->leftNode){
            $bst->setLeft($data);
        }else{
            self::insert($bst->leftNode,$data);
        }
    }else if($data->data>$bst->data){
        if(!$bst->rightNode){
            $bst->setRight($data);            
        }else{
            self::insert($bst->rightNode,$data);        
        }
    }

}

根据定义,如果新节点的值小于根节点,那么一定在左侧,如果没有左子树,直接作为左子树就好了,否则就需要把这个新节点插入到左子树这个二叉搜索树中。大于的情况类似,不做赘述。

关于二叉搜索树还有一个操作就是删除节点,我将从要被删除的节点的角度看这个问题。如果是叶节点,直接删掉该节点,删除父节点的引用就好了。如果只有一颗子树,父节点的相关引用指向这棵子树就可以了。最复杂的是有两棵子树的情况,我们可以找左子树的最大值节点,或者右子树的最小值节点代替该节点,这样在删除的同时能保证依然是二叉搜索树,并且改动最小。

// 删除节点
static function delete($node){
    $parentNode = $node->parentNode;
    if($node->isLeaf()){
        if($parentNode){
            if($parentNode->leftNode===$node){
                $parentNode->leftNode = NULL;
            }else{
                $parentNode->rightNode = NULL;
            }
        }
        $node->parentNode = NULL;
    }else if($node->isHalf()){
        if($node->leftNode){
            $node->leftNode->parentNode = $parentNode;
            if($parentNode){
                if($parentNode->leftNode===$node){
                    $parentNode->leftNode = $node->leftNode;
                    // $parentNode->setLeft($node->leftNode);
                }else{
                    $parentNode->rightNode = $node->leftNode;
                    // $parentNode->setRight($node->rightNode);
                }
            }
        }else{
            $node->rightNode->parentNode = $parentNode;
            if($parentNode){
                if($parentNode->leftNode===$node){
                    $parentNode->leftNode = $node->rightNode;
                }else{
                    $parentNode->rightNode = $node->rightNode;
                }
            }
        }

        $node->parentNode = NULL;
    }else{
        $rightMinNode = self::findMin($node->rightNode);
        $node->update($rightMinNode->data);
        self::delete($rightMinNode);
    }
}

关于二叉搜索树的代码清单如下:

class Node_bst extends Node_tree{
    function __construct($value=NULL){
        parent::__construct($value);
    }

    static function find($bst,$data){
        if(!($bst instanceof Node_bst)){
            return NULL;
        }
        while($bst){
            if($bst->data>$data){
                $bst = $bst->leftNode;
            }else if($bst->data<$data){
                $bst = $bst->rightNode;
            }else{
                return $bst;
            }
        }
        return NULL;
    }

    static function findMax($bst){
        if(!($bst instanceof Node_bst)){
            return NULL;
        }
        while($bst->rightNode){
            $bst = $bst->rightNode;
        }
        return $bst;
    }

    static function findMin($bst){
        if(!($bst instanceof Node_bst)){
            return NULL;
        }
        while($bst->leftNode){
            $bst = $bst->leftNode;
        }
        return $bst;
    }

    static function insert($bst,$data){
        if(!($data instanceof $bst)){
            $data = new Node_bst($data);
        }

        if($data->data<$bst->data){
            if(!$bst->leftNode){
                $bst->setLeft($data);
            }else{
                self::insert($bst->leftNode,$data);
            }
        }else if($data->data>$bst->data){
            if(!$bst->rightNode){
                $bst->setRight($data);            
            }else{
                self::insert($bst->rightNode,$data);        
            }
        }

    }

    // 删除节点
    static function delete($node){
        $parentNode = $node->parentNode;
        if($node->isLeaf()){
            if($parentNode){
                if($parentNode->leftNode===$node){
                    $parentNode->leftNode = NULL;
                }else{
                    $parentNode->rightNode = NULL;
                }
            }
            $node->parentNode = NULL;
        }else if($node->isHalf()){
            if($node->leftNode){
                $node->leftNode->parentNode = $parentNode;
                if($parentNode){
                    if($parentNode->leftNode===$node){
                        $parentNode->leftNode = $node->leftNode;
                        // $parentNode->setLeft($node->leftNode);
                    }else{
                        $parentNode->rightNode = $node->leftNode;
                        // $parentNode->setRight($node->rightNode);
                    }
                }
            }else{
                $node->rightNode->parentNode = $parentNode;
                if($parentNode){
                    if($parentNode->leftNode===$node){
                        $parentNode->leftNode = $node->rightNode;
                    }else{
                        $parentNode->rightNode = $node->rightNode;
                    }
                }
            }

            $node->parentNode = NULL;
        }else{
            $rightMinNode = self::findMin($node->rightNode);
            $node->update($rightMinNode->data);
            self::delete($rightMinNode);
        }
    }

}

results matching ""

    No results matching ""