数据结构与算法学习之路14--二叉树(下)

379 阅读2分钟

二叉查找树概念

二叉树中有一种特殊的二叉树--二叉查找树,它最大的特点就是支持动态数据集合的快速插入、删除、查找操作。二叉查找树要求在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。如下图所示

二叉查找树操作

查找

想查找某个值时从根节点出发,如果正好是要找的数据那就直接返回;如果根节点比要找的数据小那就遍历右子树寻找;如果根节点比要找的树大那就遍历左子树寻找。

插入

插入某个值时我们还是从根节点出发,如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。

删除

删除时需要分三种情况分析。

  • 要删除的值没有子节点。只需要将父节点指向该值得指针置null即可。
  • 要删除的值只有一个子节点。只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。
  • 要删除的值包含两个子节点。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上,然后再删除掉这个最小节点。

伪代码实现(PHP)

class Node
{
    public $value;
    public $left;
    public $right;
}

class Tree
{
    /**
     * 查找数据
     * @param  [type] $data [数据]
     * @return [type]       [description]
     */
    public function find($data)
    {
        if ($this->head == null) {
            return null;
        }

        $node = $this->head;

        while ($node != null) {
            if ($node->data == $data) {
                return $node;
            } elseif ($data > $node->data) {
                $node = $node->right;
            } else {
                $node = $node->left;
            }
        }

        return null;
    }

    /**
     * 插入数据
     * @param  [type] $data [数据]
     * @return [type]       [description]
     */
    public function insert($data)
    {
        if ($this->head == null) {
            $this->head = new TreeNode($data);
            return true;
        }

        $node = $this->head;

        while ($node != null) {
            if ($data > $node->data) {
                if ($node->right == null) {
                    $node->right = new TreeNode($data);
                    return true;
                }
                $node = $node->right;
            } else {
                if ($node->left == null) {
                    $node->left = new TreeNode($data);
                    return true;
                }
                $node = $node->left;
            }
        }
    }

    /**
     * 删除节点
     * @param  [type] $data [节点]
     * @return [type]       [description]
     */
    public function delete($data)
    {
        // 找到需要删除节点
        $node = $this->head;
        $pnode = null;
        while ($node != null) {
            if ($node->data == $data) {
                break;
            } elseif ($data > $node->data) {
                $pnode = $node;
                $node = $node->right;
            } else {
                $pnode = $node;
                $node = $node->left;
            }
        }        
        if ($node == null) {
            return false;
        }
        // 要删除的节点有两个子节点
        // 查找右子树中最小节点
        if ($node->left != null && $node->right != null) {
            $minPP = $node;
            $minP = $node->right;
            while ($minP->left != null) {
                $minPP = $minP;
                $minP = $minP->left;
            }
            $node->data = $minP->data;
            $node = $minP;
            // 删除掉右子树中的最小节点
            $minPP->left = null;
        }

        if ($node->left != null) {
            $child = $node->left;
        } elseif ($node->right != null) {
            $child = $node->right;
        } else {
            $child = null;
        }

        if ($pnode == null) {
            // 删除的是根节点
            $node = $child;
        } elseif ($pnode->left == $node) {
            $pnode->left = $child;
        } else {
            $pnode->right = $child;
        }
    }
}