<?php
/**
* 二叉树
* 1.二叉树的创建
* 2.二叉树的左插入、右插入
* 3.二叉树的前序遍历(递归/非递归堆栈实现)、中序遍历、后序遍历、层序遍历(队列实现)
* 4.二叉树的打印
* 5.二叉树的查找
* 6.二叉树的删除、左删除、右删除
*/
/**
* 结点
*/
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;
}
}
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);