* 定义
对于树中的每个节点x,它的左子树中所有关键字值小于x的关键字值,而他的右子树种所有关键字值大于x的关键字值
* SearchTree.php
<?php
/**
* Created by PhpStorm.
* User: Mch
* Date: 8/15/18
* Time: 23:33
*/
class Node {
public $element;
public $left;
public $right;
public function __construct($element, Node $left = null, Node $right = null) {
$this->element = $element;
$this->left = $left;
$this->right = $right;
}
}
class SearchTree {
private $root = null;
public function insert($x) {
$newNode = new Node($x);
if (is_null($this->root)) {
$this->root = $newNode;
} else {
self::insertNode($this->root, $newNode);
}
}
private static function insertNode(Node $node, Node $newNode) {
if ($newNode->element < $node->element) {
if ($node->left ===null) {
$node->left = $newNode;
} else {
self::insertNode($node->left, $newNode);
}
} else {
if ($node->right===null) {
$node->right = $newNode;
} else {
self::insertNode($node->right, $newNode);
}
}
}
public function delete($x) {
if (!is_null($this->root)) {
return self::deleteNode($x, $this->root);
}
return null;
}
private static function deleteNode($x, Node $t) {
$tmpCell = null;
if ($x < $t->element) {
// go left
$t->left = self::deleteNode($x, $t->left);
} else if ($x > $t->element) {
// go right
$t->right = self::deleteNode($x, $t->right);
} else {
// two children
if ($t->left && $t->right) {
// replace with smallest in right subtree
$tmpCell = self::findMinNode($t->right);
$t->element = $tmpCell->element;
$t->right = self::deleteNode($t->element, $t->right);
}
// one or zero children
else {
$tmpCell = $t;
if (is_null($t->left)) {
// also handles 0 children
$t = $t->right;
} else if (is_null($t->right)) {
$t = $t->left;
}
unset($tmpCell);
$tmpCell = null;
}
}
return $t;
}
public function preOrderTraverse(callable $callback) {
if (!is_null($this->root)) {
self::preOrderTraverseNode($this->root, $callback);
}
}
private static function preOrderTraverseNode(Node $node, callable $callback) {
if (is_null($node)) {
return;
}
$stack = [];
array_push($stack, $node);
while (count($stack)>0) {
$node = array_pop($stack);
call_user_func($callback, $node->element);
if (!is_null($node->right)) {
array_push($stack, $node->right);
}
if (!is_null($node->left)) {
array_push($stack, $node->left);
}
}
}
/*
private static function preOrderTraverseNode(Node $node, callable $callback) {
call_user_func($callback, $node->element);
if (!is_null($node->left)) {
self::preOrderTraverseNode($node->left, $callback);
}
if (!is_null($node->right)) {
self::preOrderTraverseNode($node->right, $callback);
}
}
*/
public function inOrderTraverse(callable $callback) {
if (!is_null($this->root)) {
self::inOrderTraverseNode($this->root, $callback);
}
}
private static function inOrderTraverseNode(Node $node, callable $callback) {
if ($node != null) {
$stack = [];
while (count($stack)!==0 || $node != null) {
if ($node != null) {
array_push($stack, $node);
$node = $node->left;
} else {
$node = array_pop($stack);
$callback($node->element);
$node = $node->right;
}
}
}
}
/*
private static function inOrderTraverseNode(Node $node, callable $callback) {
if (!is_null($node->left)) {
self::inOrderTraverseNode($node->left, $callback);
}
call_user_func($callback, $node->element);
if (!is_null($node->right)) {
self::inOrderTraverseNode($node->right, $callback);
}
}
*/
public function posOrderTraverse(callable $callback) {
if (!is_null($this->root)) {
self::posOrderTraverseNode($this->root, $callback);
}
}
private static function posOrderTraverseNode(Node $h, callable $callback) {
if (is_null($h)) {
return;
}
$stack = [];
array_push($stack, $h);
$c = null; // Node
// while stack is not empty
while (count($stack) > 0) {
$c = $stack[count($stack)-1]; // peek
if (!is_null($c->left) && $h !== $c->left && $h !== $c->right) {
array_push($stack, $c->left);
} else if (!is_null($c->right) && $h !== $c->right) {
array_push($stack, $c->right);
} else {
call_user_func($callback, array_pop($stack)->element);
$h = $c;
}
}
}
/*
private static function posOrderTraverseNode(Node $node, callable $callback) {
if (is_null($node)) {
return;
}
$s1 = [];
$s2 = [];
array_push($s1, $node);
while (count($s1) > 0) {
$node = array_pop($s1);
array_push($s2, $node);
if (!is_null($node->left)) {
array_push($s1, $node->left);
}
if (!is_null($node->right)) {
array_push($s1, $node->right);
}
}
while (count($s2) > 0) {
call_user_func($callback, array_pop($s2)->element);
}
}
*/
/*
private static function posOrderTraverseNode(Node $node, callable $callback) {
if (!is_null($node->left)) {
self::posOrderTraverseNode($node->left, $callback);
}
if (!is_null($node->right)) {
self::posOrderTraverseNode($node->right, $callback);
}
call_user_func($callback, $node->element);
}
*/
public function makeEmpty() {
if (!is_null($this->root)) {
self::makeEmptyNode($this->root);
}
}
private static function makeEmptyNode(Node $node) {
self::makeEmptyNode($node->left);
self::makeEmptyNode($node->right);
unset($node);
return ($node = null);
}
public function find(mixed $x) : TreeNode {
self::findNode($x, $this->root);
}
private static function findNode(mixed $x, Node $t) {
if ($t === null) {
return null;
}
if ($x < $t->element) {
return self::findNode($x, $t->left);
} else if ($x > $t->element) {
return self::findNode($x, $t->right);
}
return $t;
}
public function findMin() {
$t = self::findMinNode($this->root);
return $t->element;
}
private static function findMinNode(Node $t) :Node {
if ($t===null) {
return null;
} else if ($t->left === null) {
return $t;
}
return self::findMinNode($t->left);
}
public function findMax() {
$t = self::findMaxNode($this->root);
return $t->element;
}
private static function findMaxNode(Node $t) : Node {
if (!is_null($t)) {
while (!is_null($t->right)) {
$t = $t->right;
}
}
return $t;
}
}
* test:
$tree = new SearchTree();
$a = [6,2,8,1,4,3];
array_walk($a, function(&$value, $key, $tree) {
$tree->insert($value);
}, $tree);
// 6,1,2,3,4,8
$tree->preOrderTraverse(function($element) {
echo $element,',';
});
echo PHP_EOL;
$tree->inOrderTraverse(function($element) {
echo $element,',';
});
echo PHP_EOL;
// 1,3,4,2,6,8
$tree->posOrderTraverse(function($element) {
echo $element,',';
});
echo PHP_EOL;
echo 'max: '. $tree->findMax().PHP_EOL;
echo 'min: '. $tree->findMin().PHP_EOL;
$tree->delete(8);
$tree->inOrderTraverse(function($element) {
echo $element,',';
});
echo PHP_EOL;
* Run:
php SearchTree.php
6,2,1,4,3,8,
1,2,3,4,6,8,
1,3,4,2,8,6,
max: 8
min: 1
1,2,3,4,6,