php -树-二叉树的实现

27 篇文章 0 订阅

php -树-二叉树的实现

<?php
/**
 * 结点 
 */
class Node
{
   public $data; //结点数据
   public $left; //左孩子
   public $right; //右孩子

   public function __construct($data, $left=null, $right=null)
   {
       $this->data = $data;
       $this->left = $left;
       $this->right = $right;
   }
}
/**
 * 二叉树
 * 1.二叉树的创建
 * 2.二叉树的左插入、右插入
 * 3.二叉树的前序遍历(递归/非递归堆栈实现)、中序遍历、后序遍历、层序遍历(队列实现)
 * 4.二叉树的打印
 * 5.二叉树的查找
 * 6.二叉树的删除、左删除、右删除
 */
class Btree
{
   public $root; 
   
   /**
    * 初始化
    */
   public function init()
   {
       $this->root = new Node(null);       
       return $this->root;
   }
   
   /**
    * 左插入:
    *   若当前结点非空则左插入,当前结点左子树变为插入结点;
    *   原左子树变为插入结点的左子树
    * @param $cur 当前结点
    * @param $data 插入的数据
    */
   public function leftInsert($cur,$data) 
   {
      if (!$cur) 
          return false;

      //新建结点
      $node = new Node($data,$cur->left);
      $cur->left = $node;

      //返回新插入的结点
      return $node;
   }

   /**
    * 右插入
    */
   public function rightInsert($cur, $data)
   {
       if (!$cur)
           return false;
       $node = new Node($data,null,$cur->right);
       $cur->right = $node;
       
       return $node;
       
   }

   /**
    * 前序遍历 
    * @param unknown $root
    * @param array $res
    */
   public function preView($root,&$res=[])
   {
       if (!$root)
           return false;

       $res[]=$root->data; 
       $this->preView($root->left,$res);
       $this->preView($root->right,$res);

       return  $res;
   }

   /**
    *中序遍历
    */
   public function midView($root, &$res=[])
   {
       if (!$root)
           return  false;

       $this->midView($root->left, $res);
       $res[] = $root->data;
       $this->midView($root->right, $res);
       
       return $res;
   }
   
   /**
    * 后序遍历
    */
   public function aftView($root, &$res=[])
   {
       if (!$root)
           return false;
       
       $this->aftView($root->left, $res);
       $this->aftView($root->right, $res);
       $res[]=$root->data;
       
       return $res;
   }
   
   /**
    * 层序遍历 队列实现 
    * 分析:先跟结点->左->右,未访问的结点始终是
    *       按最先访问的结点的左子树右子树的顺序来访问, 因此符合队列特征
    *       跟结点入列,出列输出根结点数据,然后把左子树入列,右子树入列;
    *       继续重复出列,入列
    */
   public function floorView($root)
   {
       if (!$root)
           return false;

       $queue = [];//初始化队列 
       $queue[]=$root; //根结点入列
       $res = []; 
       
       while ($queue) {
           $cur = array_shift($queue); 
           $res[] = $cur->data;//根数据

           if ($cur->left)
               $queue[] = $cur->left; //先左孩子入列
           if ($cur->right)
               $queue[] = $cur->right; //再右孩子入列
       }

       return $res;
   }
   
   /**
    * 前序遍历非递归法 堆栈实现
    * 分析:未访问的结点中,最近访问的结点的左子树最先访问
    * 操作步骤:
    *   1.初始化一个堆栈
    *   2.根结点入栈
    *   3.若跟结点不为空,则出栈,打印当前结点数据;
    *           然后把当前结点的右孩子入栈,左孩子入栈
    *   4.循环3,继续出栈 入栈
    */
   public function pre2($root)
   {
       if (!$root)
           return false;

       $stack = [];//数组表示堆栈
       $res = [];
       $stack[] = $root;

       while ($stack) {
          $cur = array_pop($stack); //右端出,右端入 
          $res[]=$cur->data; //根数据

          if ($cur->right)
              $stack[]= $cur->right; //右子树先入栈

          if ($cur->left)
              $stack[]= $cur->left; //左子树后入栈
       }
       
       return $res;
   }
   
   /**
    * 打印二叉树:逆时针选择90°,先右再中再左
    * @param $n 缩进层
    */
   public function printView($root, &$res=[], $n = 0)
   {
       if (!$root)
           return false;

       $n++;//缩进层 
       $this->printView($root->right, $res, $n); 

       $s = '';
       for ($i=0;$i<$n;$i++)$s.='-----'; 

       $res[] = $s.$root->data;
       $this->printView($root->left, $res, $n);

       return $res;
   }
   
   /**
    * 二叉树查找
    *  先查当前结点是否存在,再查左,右2边
    *  @param $data 要查找的数据
    *  @return mixed
    */
   public function find($cur, $data) 
   {
      if (!$cur) 
          return false;
      
      if ($cur->data == $data) 
          return true;
      //左边找
      if ($cur->left && $this->find($cur->left, $data)) 
          return true;
      //右边找
      if ($cur->right && $this->find($cur->right, $data))
          return true;

      return false;
   }
   //左删除
   public function leftDel($cur) 
   {
       if (!$cur || !$cur->left)
           return false;

       $this->del($cur->left);
       $cur->left = null;
   }
   //右删除
   public function rightDel($cur)
   {
       if (!$cur || !$cur->right)
           return false;

       $this->del($cur->right);
       $cur->right = null;
   }
   //删除当前结点
   public function del(&$cur)
   {
       if (!$cur)
           return false;

       //存在左子树 删除左子树
       if ($cur->left)
           $this->del($cur->left);

       //存在右子树删除右子树
       if ($cur->right)
           $this->del($cur->right);

       //删除当前结点
       unset($cur); 
   }
}
/* 创建如下图所示的二叉树
 *              root
 *               /
 *              A
 *             / \
 *            B   C              
 *           /   / \ 
 *          D   E   F
 *           \
 *            G
 */
 $btree = new Btree();

 //初始化,构建二叉树
 $root = $btree->init();
 $cur = $btree->leftInsert($root, 'A');
 $cur = $btree->leftInsert($cur, 'B');
 $cur = $btree->leftInsert($cur, 'D');
 $btree->rightInsert($cur, 'G');
 $cur = $btree->rightInsert($root->left,'C');
 $btree->rightInsert($cur,'F');
 $btree->leftInsert($cur,'E');
 
 //前序遍历:ABDGCEF
 $pre = $btree->preView($root->left);
 print_r($pre);

 //前序遍历非递归,堆栈实现
 $pre = $btree->pre2($root->left);
 print_r($pre);

 //中序遍历:GDBAECF
$pre = $btree->midView($root->left);
 print_r($pre);

 //后序遍历: GDBEFCA 
$pre = $btree->aftView($root->left);
 print_r($pre);

 //层序遍历:ABCDEFG;
 $pre = $btree->floorView($root->left);
 print_r($pre);

 //打印二叉树:
 $pri = $btree->printView($root->left);
 print_r($pri);
 //结果如下:
 /*Array
 (
     [0] => ---------------F
     [1] => ----------C
     [2] => ---------------E
     [3] => -----A
     [4] => ----------B
     [5] => --------------------G
     [6] => ---------------D
     )
     */

//二叉树查找
$find = $btree->find($root->left, 'E');
var_dump($find);




 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值