PHP BinarySearchTree 二叉查找树

* 定义

对于树中的每个节点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,

 

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/fareast_mzh/article/details/81750581
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞