二叉搜索树-PHP

12 篇文章 0 订阅

二叉搜索树主要特征

1.根节点小于左节点,根节点大于右节点,树中不会存在相同值的两个节点

2.删除和插入的时候,要维护搜索二叉树的节点之间的大小

3.删除有些情况会麻烦一点,有右子树的时候,要找出删除节点的后继节点来代替当前节点

4.树的数据位置顺序就是中序遍历出来的数据位置

5.一样的数字,如果插入顺序不同,那么树结构也会不同

github地址 : https://github.com/luolaifa000/phpStudyCode/blob/master/BinSearchTree.php 

<?php
function pre($arr)
{
    $data = func_get_args();
    foreach($data as $key=>$val)
    {
        echo '<pre>';
        print_r($val);
        echo '</pre>';
    }
}

function prend()
{
    $data = func_get_args();
    foreach($data as $key=>$val)
    {
        echo '<pre>';
        print_r($val);
        echo '</pre>';
    }
    exit();
}
/**
 * 搜索二叉树插入和查找
 * 
 * @author yumancang
 *
 */
class TreeNode 
{
    /**
     * 左节点
     * @var unknown
     */
    public $lNode;
    
    /**
     * 右节点
     * @var unknown
     */
    public $rNode;
    
    /**
     * 父节点
     * @var unknown
     */
    public $pNode;
    
    public $val;
    
    public $data;
    
    /**
     * 构造
     * 
     * @param int $val
     * @param TreeNode $lNode
     * @param TreeNode $rNode
     */
    public function __construct(int $val = null ,TreeNode $lNode = null ,TreeNode $rNode = null)
    {
        $this->val = $val;
        $this->lNode = $lNode;
        $this->rNode = $rNode;
    }
}

class BinSearchTree
{
    public $treeRootNode;
    
    public function __construct()
    {
        $this->treeRootNode = null;
    }

    /**
     * 前序输出树 5 2 1 3 9 8 10
     * 根左右
     * 
     * @param TreeNode $rootNode
     */
    public function prePrintTree(TreeNode $rootNode = null)
    {
        pre($rootNode->val);
        if ($rootNode->lNode) {
            $this->prePrintTree($rootNode->lNode);
        }
        if ($rootNode->rNode) {
            $this->prePrintTree($rootNode->rNode);
        }
        //pre($rootNode);
    }
    /**
     * 中序输出   1 2 3 5 8 9 10
     * 左根右
     * 
     * @param TreeNode $rootNode
     */
    public function middlePrintTree(TreeNode $rootNode = null)
    {
        
        if ($rootNode->lNode) {
            $this->middlePrintTree($rootNode->lNode);
        }
        pre($rootNode->val);
        if ($rootNode->rNode) {
            $this->middlePrintTree($rootNode->rNode);
        }
    }
    
    /**
     * 后序输出  1 3 2 8 10 9 5
     * 左右根
     * 
     * @param TreeNode $rootNode
     */
    public function afterPrintTree(TreeNode $rootNode = null) 
    {
        if ($rootNode->lNode) {
            $this->afterPrintTree($rootNode->lNode);
        }
        if ($rootNode->rNode) {
            $this->afterPrintTree($rootNode->rNode);
        }
        pre($rootNode->val);
    }
    
    /**
     * 
     * 搜索二叉树插入数据
     * 
     */
    public function insertTree($val, &$rootNode, $parentNode = null)
    {
        if ($this->treeRootNode == null) {
            
            $rootNode = new TreeNode();
            $rootNode->val = $val;
            $rootNode->lNode = null;
            $rootNode->rNode = null;
            $rootNode->pNode = null;
            return true;
        } else {
            if ($rootNode == null) {
                $rootNode = new TreeNode();
                $rootNode->val = $val;
                $rootNode->lNode = null;
                $rootNode->rNode = null;
                $rootNode->pNode = $parentNode;
                return true;
            }
        }
        //插入过程已存在就返回不处理
        if ($val == $rootNode->val) {
            return false;
        }
        if ($val < $rootNode->val) {
            return $this->insertTree($val, $rootNode->lNode, $rootNode);
        }
        if ($val > $rootNode->val) {
            return $this->insertTree($val, $rootNode->rNode, $rootNode);
        }
    }
    
    /**
     * 查询二叉树
     * 
     * @param int $val
     * @param TreeNode $rootNode
     */
    public function serarchTree(int $val, TreeNode &$rootNode = null)
    {
        if ($rootNode == null) {
            return false;
        }
        if ($val == $rootNode->val) {
            return $rootNode;
        }
        if ($val < $rootNode->val) {
            return $this->serarchTree($val, $rootNode->lNode);
        }
        if ($val > $rootNode->val) {
            return $this->serarchTree($val, $rootNode->rNode);
        }
    }
    
    /**
     * 二叉树中删除节点
     * 
     * @param int $val
     * @param TreeNode $rootNode
     */
    public function deleteTree(int $val, TreeNode &$rootNode = null)
    {
        $node = $this->serarchTree($val,$rootNode);
        if (!$node) {
            return false;
        }
        //没有右子树
        if ($node->rNode == null) {
            $this->transplantNode($node,$node->lNode);
        } 
        //有右子树
        if ($node->rNode) {
            //右子节点下面没有左节点的话
            if ($node->rNode->lNode == null) {
                $this->transplantNode($node,$node->rNode);
            }
            //右子节点下面有左节点的话
            if ($node->rNode->lNode) {
                //找出下面最小的那个节点,就递归左边
                $minNode = $this->findNodeBelowMin($node->rNode->lNode);
                //移动节点
                $this->transplantNode($minNode,$minNode->rNode);
                $this->transplantSingleNode($node,$minNode);
            }
        }
    }
    /**
     * 移动节点不需要附带自己的左右
     * 
     * 
     * @param TreeNode $source
     * @param TreeNode $des
     * @return boolean
     */
    public function transplantSingleNode(TreeNode $source = null, TreeNode $des = null)
    {
        if ($source == null) {
            return false;
        }
        if ($source->pNode == null) {
            $this->treeRootNode = $des;
            return true;
        }
        //原节点是其父节点的左子树
        if ($source === $source->pNode->lNode) {
            $source->pNode->lNode = $des;
        }
        //原节点是其父节点的右子树
        if ($source === $source->pNode->rNode) {
            $source->pNode->rNode = $des;
        }
        if ($des != null) {
            $des->pNode = $source->pNode;
            $des->rNode = $source->rNode;
            $des->lNode = $source->lNode;
        }
        return true;
    }
    
    /**
     * 找出当前节点和它子树下面最小的节点
     * 
     * @param TreeNode $node
     * @return NULL|TreeNode
     */
    public function findNodeBelowMin(TreeNode $node = null)
    {
        if ($node == null) {
            return null;
        }
        while ($node->lNode != null) {
            $node = $node->lNode;
        }
        return $node;
    }
    
    /**
     * 找出当前节点和它子树下面最大的节点
     * 
     * @param TreeNode $node
     * @return NULL|TreeNode|unknown
     */
    public function findNodeBelowMax(TreeNode $node)
    {
        if ($node == null) {
            return null;
        }
        while ($node->rNode != null) {
            $node = $node->rNode;
        }
        return $node;
    }
    
    /**
     * 移动节点 需要附带自己的左右
     * 
     * @param TreeNode $source
     * @param TreeNode $des
     * @return boolean
     */
    public function transplantNode(TreeNode $source = null, TreeNode $des = null)
    {
        if ($source == null) {
            return false;
        }
        if ($source->pNode == null) {
            $this->treeRootNode = $des;
            return true;
        }
        //原节点是其父节点的左子树
        if ($source === $source->pNode->lNode) {
            $source->pNode->lNode = $des;
        }
        //原节点是其父节点的右子树
        if ($source === $source->pNode->rNode) {
            $source->pNode->rNode = $des;
        }
        $des != null && $des->pNode = $source->pNode;
        return true;
    }
    
    /**
     * 查找一个节点前继节点
     * 
     * @param int $val
     * @param TreeNode $rootNode
     */
    public function findPreNodeTree(int $val,TreeNode $rootNode = null)
    {

    }
    
    /**
     * 
     * 查找一个节点后继节点
     *
     * @param int $val
     * @param TreeNode $rootNode
     */
    public function findAfterNodeTree(int $val,TreeNode $rootNode = null)
    {

    }
}

$start = memory_get_usage();
$binTree = new BinSearchTree();
#插入树
$binTree->insertTree(5,$binTree->treeRootNode);
$binTree->insertTree(2,$binTree->treeRootNode);
$binTree->insertTree(9,$binTree->treeRootNode);
$binTree->insertTree(1,$binTree->treeRootNode);
$binTree->insertTree(3,$binTree->treeRootNode);
$binTree->insertTree(10,$binTree->treeRootNode);
$binTree->insertTree(8,$binTree->treeRootNode);
$binTree->insertTree(9.5,$binTree->treeRootNode);
$binTree->insertTree(11,$binTree->treeRootNode);
$binTree->insertTree(10.5,$binTree->treeRootNode);
$binTree->insertTree(10.6,$binTree->treeRootNode);

#打印树
pre("前序");
$binTree->prePrintTree($binTree->treeRootNode);
pre("中序");
$binTree->middlePrintTree($binTree->treeRootNode);
pre("后序");
$binTree->afterPrintTree($binTree->treeRootNode);
#搜索树
var_dump($binTree->serarchTree(6, $binTree->treeRootNode));
//prend($binTree->serarchTree(10, $binTree->treeRootNode)->pNode->pNode);
#删除树
//$binTree->deleteTree(10,$binTree->treeRootNode);
$binTree->deleteTree(10,$binTree->treeRootNode);
pre("中序");
$binTree->middlePrintTree($binTree->treeRootNode);
//pre($binTree->treeRootNode);
$end = memory_get_usage();
prend("占用内存:",($end-$start)/1024/1024);

?>

 

参考:https://blog.csdn.net/qq_21396469/article/details/78419609

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值