基于4.2章节做的延伸,采用非递归的方式来实现前序遍历、中序遍历和后序遍历
1. 二分搜索树(本章节都基于该二分搜索树做举例)

2. 代码 (在traversalByStack方法中实现了非递归的遍历二叉树)
/**
* content: 二叉树的二分搜索树的实现
* auth: yujiaming
* create: 2020-10-25 */
<?php
namespace TreeBundle;
use ArrayBundle\BaseArray;
use StackBundle\BaseStack;
class BaseBinaryTree
{
public function __construct()
{
$this->rootNode = null;
$this->size = 0;
}
/**
* 二叉树的根节点
* @var Node
*/
protected $rootNode;
/**
* 获取根节点
* @return Node
*/
public function getRootNode(): Node
{
return $this->rootNode;
}
/**
* 二叉树的个数
* @var int
*/
protected $size;
/**
* 获取二叉树的元素个数
* @return int
*/
public function getSize(): int
{
return $this->size;
}
/**
* 判断是否为空
* @return bool
*/
public function isEmpty(): bool
{
return $this->size == 0;
}
/**
* 插入结点
* @param mixed $value
* @return void
*/
public function add($value): void
{
// 如果不存在根节点就插入根节点
if (is_null($this->rootNode)) {
$this->rootNode = new Node($value);
$this->size;
return;
} else {
$this->addChild($value, $this->rootNode);
return;
}
}
/**
* 插入儿子结点
* @param mixed $value
* @param Node|null $parentNode
*/
private function addChild($value, ?Node $parentNode): void
{
if (bccomp($parentNode->getValue(), $value) > 0) {
// 左儿子
if (is_null($parentNode->getLeftChild())) {
$parentNode->setLeftChild(new Node($value));
$this->size++;
return;
} else {
$this->addChild($value, $parentNode->getLeftChild());
}
} elseif (bccomp($parentNode->getValue(), $value) < 0) {
// 右儿子
if (is_null($parentNode->getRightChild())) {
$parentNode->setRightChild(new Node($value));
$this->size++;
return;
} else {
$this->addChild($value, $parentNode->getRightChild());
}
} else {
return;
}
}
const TRAVERSAL_PREORDER = 1; // 先序遍历
const TRAVERSAL_INORDER = 2; // 中序遍历
const TRAVERSAL_POSTORDER = 3; // 后序遍历
/**
* 遍历二叉树
* @param int $traversalType
* @return string
*/
public function traversal(int $traversalType = 1): string
{
$result = '';
switch ($traversalType) {
case self::TRAVERSAL_PREORDER:
$this->preorderTraversal($result, $this->rootNode);
break;
case self::TRAVERSAL_INORDER:
$this->inorderTraversal($result, $this->rootNode);
break;
case self::TRAVERSAL_POSTORDER:
$this->postorderTraversal($result, $this->rootNode);
break;
default:
break;
}
return $result;
}
/**
* 先序遍历
* @param string $result 结果值
* @param Node|null $node 结点
* @return void
*/
protected function preorderTraversal(string &$result, ?Node $node): void
{
if (is_null($node)) return;
// 拼接
if ($result != '') $result .= ' -> ';
// 先遍历当前节点
$result .= $node->getValue();
// 再遍历左儿子
$this->preorderTraversal($result, $node->getLeftChild());
// 在遍历右儿子
$this->preorderTraversal($result, $node->getRightChild());
return;
}
/**
* 中序遍历
* @param string $result 结果值
* @param Node|null $node 结点
* @return void
*/
public function inorderTraversal(string &$result, ?Node $node): void
{
if (is_null($node)) return;
// 先遍历左儿子
$this->inorderTraversal($result, $node->getLeftChild());
// 拼接
if ($result != '') $result .= ' -> ';
// 再获取当前结点
$result .= $node->getValue();
// 在遍历右儿子
$this->inorderTraversal($result, $node->getRightChild());
return;
}
/**
* 后序遍历
* @param string $result 结果值
* @param Node|null $node 结点
* @return void
*/
public function postorderTraversal(string &$result, ?Node $node): void
{
if (is_null($node)) return;
// 先遍历左儿子
$this->postorderTraversal($result, $node->getLeftChild());
// 在遍历右儿子
$this->postorderTraversal($result, $node->getRightChild());
// 拼接
if ($result != '') $result .= ' -> ';
// 再获取当前结点
$result .= $node->getValue();
return;
}
/**
* 非递归实现遍历
* @param int $traversalType
* @return string
*/
public function traversalByStack(int $traversalType = 1): string
{
$stack = new BaseStack(new BaseArray());
$result = '';
switch ($traversalType) {
// 前序遍历
case self::TRAVERSAL_PREORDER:
// 将根节点插入栈底
$stack->push($this->rootNode);
// 循环
while (!$stack->isEmpty()) {
// 弹出栈顶的结点
// 之后的循环会先弹出左儿子然后再弹出右儿子,中结点的值以及在上一次循环中被输出掉了
$node = $stack->pop();
// 将栈顶的元素拼接到结果集里
if ($result != '') {
$result .= ' -> ';
}
$result .= $node->getValue();
// 将弹出栈顶的右儿子插入栈中
if (!is_null($node->getRightChild())) {
$stack->push($node->getRightChild());
}
// 将弹出栈顶的左儿子插入栈中
if (!is_null($node->getLeftChild())) {
$stack->push($node->getLeftChild());
}
}
break;
// 中序遍历
case self::TRAVERSAL_INORDER:
// 将根节点赋值给node变量
$node = $this->rootNode;
// 循环
// !$stack->isEmpty() >> 用于判断栈里的元素是否都弹出
// !is_null($node) >> 用于判断是否与遍历完了左儿子结点
while (!$stack->isEmpty() || !is_null($node)) {
// 循环该结点,将该结点的所有左儿子一个一个插入栈中
while (!is_null($node)) {
$stack->push($node);
// echo '插入结点:'. $node->getValue(). PHP_EOL;
$node = $node->getLeftChild();
}
// 弹出栈顶的第一个元素,左儿子或者是根节点
$popNode = $stack->pop();
if ($result != '') {
$result .= ' -> ';
}
// 输出结果
$result .= $popNode->getValue();
// 将右儿子赋值给node结点变量中
$node = $popNode->getRightChild();
}
return $result;
break;
// 后序遍历
case self::TRAVERSAL_POSTORDER:
// 创建一个临时栈
$stackTmp = new BaseStack(new BaseArray());
// 将根节点放入栈底
$stackTmp->push($this->rootNode);
// 循环临时栈
while (!$stackTmp->isEmpty()) {
// 从临时栈顶弹出一个元素
$node = $stackTmp->pop();
// 将该元素的左儿子放入临时栈中
if (!is_null($node->getLeftChild())) {
$stackTmp->push($node->getLeftChild());
}
// 将该元素的右儿子放入临时栈中
if (!is_null($node->getRightChild())) {
$stackTmp->push($node->getRightChild());
}
// 将该结点放入需要遍历数据的栈中
$stack->push($node);
}
while (!$stack->isEmpty()) {
if ($result != '') {
$result .= ' -> ';
}
$result .= $stack->pop()->getValue();
}
break;
default:
break;
}
return $result;
}
}
3. 前序遍历
// 将根节点插入栈底
$stack->push($this->rootNode);
// 循环
while (!$stack->isEmpty()) {
// 弹出栈顶的结点
// 之后的循环会先弹出左儿子然后再弹出右儿子,中结点的值以及在上一次循环中被输出掉了
$node = $stack->pop();
// 输出栈顶的元素
echo $node->getValue();
// 将弹出栈顶的右儿子插入栈中
if (!is_null($node->getRightChild())) {
$stack->push($node->getRightChild());
}
// 将弹出栈顶的左儿子插入栈中
if (!is_null($node->getLeftChild())) {
$stack->push($node->getLeftChild());
}
}
代码流程解析

4. 中序遍历
// 将根节点赋值给node变量
$node = $this->rootNode;
// 循环
// !$stack->isEmpty() >> 用于判断栈里的元素是否都弹出
// !is_null($node) >> 用于判断是否与遍历完了左儿子结点
while (!$stack->isEmpty() || !is_null($node)) {
// 循环该结点,将该结点的所有左儿子一个一个插入栈中
while (!is_null($node)) {
$stack->push($node);
$node = $node->getLeftChild();
}
// 弹出栈顶的第一个元素,左儿子或者是根节点
$popNode = $stack->pop();
// 输出结果
echo $popNode->getValue();
// 将右儿子赋值给node结点变量中
$node = $popNode->getRightChild();
}

5. 后序遍历
// 创建一个临时栈
$stackTmp = new BaseStack(new BaseArray());
// 将根节点放入栈底
$stackTmp->push($this->rootNode);
// 循环临时栈
while (!$stackTmp->isEmpty()) {
// 从临时栈顶弹出一个元素
$node = $stackTmp->pop();
// 将该元素的左儿子放入临时栈中
if (!is_null($node->getLeftChild())) {
$stackTmp->push($node->getLeftChild());
}
// 将该元素的右儿子放入临时栈中
if (!is_null($node->getRightChild())) {
$stackTmp->push($node->getRightChild());
}
// 将该结点放入需要遍历数据的栈中
$stack->push($node);
}
while (!$stack->isEmpty()) {
echo $stack->pop()->getValue();
}

**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。