khanat-opennel-code/code/web/app/app_achievements/class/AVLTree_class.php
2012-08-20 17:41:46 +02:00

340 lines
No EOL
6.9 KiB
PHP

<?php
class AVLTree {
/*---------------------------
AVL trees are balanced B-Trees. Please refer to http://en.wikipedia.org/wiki/AVL_tree
This implementation allows the functions insert, find and remove. Please
note, that remove does not rebalance the tree, since node removal is
quite rare in this project.
---------------------------*/
private $root;
private $debug;
function AVLTree($log = false) {
$this->root = null;
$this->debug = $log;
}
function preorder() {
$this->AVLpreorder($this->root);
}
private function AVLpreorder($p) { // recursive; output preorder representation
if($p != null) {
echo $p->getID().", ";
$this->AVLpreorder($p->getLeft());
$this->AVLpreorder($p->getRight());
}
}
function inorder() {
$this->AVLinorder($this->root);
}
private function AVLinorder($p) { // recursive; output postorder representation
if($p != null) {
$this->AVLinorder($p->getLeft());
echo $p->getID().", ";
$this->AVLinorder($p->getRight());
}
}
function insert($node) { // insert a new node
if($this->root == null) {
$this->root = new AVLTreeNode($node);
}
else {
$this->root = $this->AVLinsert($this->root,new AVLTreeNode($node));
}
}
function remove($id) { // remove a node
$n = $this->AVLfind($id,$this->root);
if($n != null) {
$this->AVLremove($this->root,$n);
return $n->getNode();
}
return null;
}
function find($id) { // find a node
$res = $this->AVLfind($id,$this->root);
if($res != null) {
return $res->getNode();
}
return null;
}
private function AVLfind($id,$n) { // recursive; search for a node
if($n != null) {
if($n->getID() != $id) {
if($n->getID() > $id) {
$n = $this->AVLfind($id,$n->getLeft());
}
else {
$n = $this->AVLfind($id,$n->getRight());
}
}
}
return $n;
}
private function AVLremove($r,$n) { // remove a node from the actual tree
if($n->getLeft() == null || $n->getRight() == null) {
$s = $n;
}
else {
$s = $this->Successor($n);
$n->setNode($r->getNode());
}
if($r->getLeft() != null) {
$p = $s->getLeft();
}
else {
$p = $s->getRight();
}
if($p != null) {
$p->setParent($s->getParent());
}
if($r->getParent() == null) {
$r = $p;
}
else {
$tmp = $s->getParent();
if($s == $tmp->getLeft()) {
$tmp->setLeft($p);
}
else {
$tmp->setRight($p);
}
}
return $r;
}
private function AVLinsert($r,$n) { // insert a node into the actual tree
if($r == null) {
$r = $n;
}
else {
if($n->getID() < $r->getID()) {
$r->setLeft($this->AVLinsert($r->getLeft(),$n));
$r = $this->balance($r); // rebalance
}
elseif($n->getID() > $r->getID()) {
$r->setRight($this->AVLinsert($r->getRight(),$n));
$r = $this->balance($r); // rebalance
}
$r->setHeight(max($r->getHeightLeft(),$r->getHeightRight())+1);
}
return $r;
}
private function balance($r) { // do a rebalancation of the tree
if($r->bal() == -2) {
$lc = $r->getLeft();
if($lc->getHeightLeft() >= $lc->getHeightRight()) {
$r = $this->RotateToRight($r);
}
else {
$r = $this->DoubleRotateLeftRight($r);
}
}
if($r->bal() == 2) {
$rc = $r->getRight();
if($rc->getHeightRight() >= $rc->getHeightLeft()) {
$r = $this->RotateToLeft($r);
}
else {
$r = $this->DoubleRotateRightLeft($r);
}
}
return $r;
}
private function Successor($r) { // find the successor for a node
if($r->getRight() != null) {
return $this->Minimum($r->getRight());
}
else {
$n = $r->getParent();
while($n != null && $r == $n->getRight()) {
$r = $n;
$n = $n->getParent();
}
return $n;
}
}
private function Minimum($r) { // find the minimum of a tree
if($r == null) {
return null;
}
if($r->getLeft() == null) {
return $r;
}
$p = $r;
while($p->getLeft() != null) {
$p = $p->getLeft();
}
return $p;
}
//rotations
private function RotateToRight($r) {
if($this->debug) {
echo "rotaRight<br>";
}
$v = $r->getLeft();
$r->setLeft($v->getRight());
$v->setRight($r);
$r->setHeight(max($r->getHeightLeft(),$r->getHeightRight())+1);
$v->setHeight(max($v->getHeightLeft(),$r->getHeight())+1);
return $v;
}
private function DoubleRotateLeftRight($r) {
$r->setLeft($this->RotateToLeft($r->getLeft()));
return $this->RotateToRight($r);
}
private function RotateToLeft($r) {
if($this->debug) {
echo "rotaLeft<br>";
}
$v = $r->getRight();
$r->setRight($v->getLeft());
$v->setLeft($r);
$r->setHeight(max($r->getHeightLeft(),$r->getHeightRight())+1);
$v->setHeight(max($v->getHeightRight(),$r->getHeight())+1);
return $v;
}
private function DoubleRotateRightLeft($r) {
$r->setRight($this->RotateToRight($r->getRight()));
return $this->RotateToLeft($r);
}
//end rotations
}
/*
* AVL tree nodes
*/
class AVLTreeNode {
private $height;
private $left;
private $right;
private $node;
private $parent;
function AVLTreeNode($node) {
$this->height = 0;
$this->left = null; // left child
$this->right = null; // right child
$this->node = $node; // actual data stored
$this->parent = null; // parent node
}
function getParent() {
return $this->parent;
}
function setParent($p) {
$this->parent = $p;
}
function getNode() {
return $this->node;
}
function getLeft() {
return $this->left;
}
function getRight() {
return $this->right;
}
function getHeightLeft() {
if($this->left == null) {
return -1;
}
return $this->left->getHeight();
}
function getHeightRight() {
if($this->right == null) {
return -1;
}
return $this->right->getHeight();
}
function bal() { // calculate value to eval balancing
$r = -1;
$l = -1;
if($this->right != null) {
$r = $this->right->getHeight();
}
if($this->left != null) {
$l = $this->left->getHeight();
}
return ($r-$l);
}
function getID() {
return $this->node->getID();
}
function getHeight() {
return $this->height;
}
function setHeight($h) {
$this->height = $h;
}
function setRight($r) {
$this->right = $r;
if($r != null) {
$r->setParent($this);
}
}
function setLeft($l) {
$this->left = $l;
if($l != null) {
$l->setParent($this);
}
}
function setNode($n) {
$this->node = $n;
}
}
?>