红黑树之PHP代码简释

写在前面:
一,本文侧重诠释对算法的思考记录过程,忽略其他诸如代码简洁、字符编码等细节问题。
二,本文结合 红黑树插入过程图示 这篇一起看,有助于理解。

<?php
class Node {
	public $data;
	public $left = NULL;
	public $right = NULL;
	public $color = 0;
	public $parent = NULL;

	public function __construct($data) {
		$this->data = $data;

	}
}
//红黑树(Red-Black Tree)是每个节点都带有颜色属性的二叉排序(查找)树,具备以下特性:
//1,节点是红色或黑色
//2,根节点是黑色的
//3,每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据
//4,任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的
//5,每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点
class RBTree {
	private static $tree;

	const RED = 1;
	const BLACK = 0;

	public function getTree() {
		return self::$tree;
	}

	//中序遍历
	public function midOrderTraverse($p) {
		if (!isset($p->data) || !$p) {
			return;
		}

		if (isset($p->left->data)) {
			$this->midOrderTraverse($p->left);
		}
		
		if (isset($p->data)) {
			if ($p->color == self::RED) {
				echo "<input style='color:red;font-size:15px;border:none;width:30px;' value=$p->data>";
			} else {
				printf("%s\n", $p->data);
			}
		}
		
		// printf("%s\n", $p->data);
		// var_dump($p);
		if (isset($p->right->data)) {
			$this->midOrderTraverse($p->right);
		}
	}

	public function newNode($data) {
		$node = new Node($data);
		$node->left = new Node(NULL);//红黑树的每个叶子节点都是黑色,不存储数据
		$node->left->parent = $node;
		$node->right = new Node(NULL);
		$node->right->parent = $node;
		return $node;
	}

	public function insert($data) {
		if (!self::$tree) {
			$node = $this->newNode($data);
			self::$tree = $node;
			return;
		}

		$p = self::$tree;
		while (isset($p->data)) {
			if ($data < $p->data) {
				if (!isset($p->left->data)) {
					$node = $this->newNode($data);
					$node->color = self::RED;
					$node->parent = $p;
					$p->left = $node;
					$this->changeColor($p->left);
					return;					
				}
				$p = $p->left;
			} elseif ($data > $p->data) {
				if (!isset($p->right->data)) {
					$node = $this->newNode($data);
					$node->color = self::RED;
					$node->parent = $p;
					$p->right = $node;
					$this->changeColor($p->right);
					return;
				}
				$p = $p->right;
			}
		}
	}

	public function changeColor($tree) {
		//被关注节点的父节点不是根节点
		if (isset($tree->parent->parent)) {
			$isLeft = $this->isLeft($tree);
			$parentLeft = $this->isLeft($tree->parent);
			$uncle = $this->getUncle($tree);
			//case1:被关注节点的父节点和叔叔/伯伯节点都是红色
			if ($tree->parent->color == self::RED && $uncle->color == self::RED) {
				$tree->parent->color = self::BLACK;
				$uncle->color = self::BLACK;
				if (isset($tree->parent->parent->parent)) {//祖父不是根节点
					$tree->parent->parent->color = self::RED;
					$tree = $tree->parent->parent;//关注节点变成祖父节点
					if (isset($tree->parent->parent)) {
						$isLeft = $this->isLeft($tree);
						$parentLeft = $this->isLeft($tree->parent);
						$uncle = $this->getUncle($tree);
					}					
				}			
			}

			//case2:关注节点和其父节点都是红色,但不在同一侧(同为左侧或同为右侧),且叔叔/伯伯节点是黑色
			if (isset($tree->parent->parent) && $tree->parent->color == self::RED && ($isLeft ^ $parentLeft) && $uncle->color == self::BLACK) {
				if ($parentLeft) {//父节点在左侧
					$tree = $this->leftRotate($tree->parent)->left;
					$isLeft = TRUE;
				} else {
					$tree = $this->rightRotate($tree->parent)->right;
					$isLeft = FALSE;
				}
			}

			//case3:关注节点和其父节点都是红色,且在同一侧(同为左侧或同为右侧),且叔叔/伯伯节点是黑色
			if (isset($tree->parent->parent) && $tree->parent->color == self::RED && !($isLeft ^ $parentLeft) && $uncle->color == self::BLACK ) {
				$tree->parent->color = self::BLACK;
				$tree->parent->parent->color = self::RED;
				if ($parentLeft) {//父节点在左侧
					$tree = $this->rightRotate($tree->parent->parent);
				} else {
					$tree = $this->leftRotate($tree->parent->parent);
				}			
			} elseif (isset($tree->parent->parent) && $tree->parent->color == self::RED && $uncle->color == self::RED) {//case1
				$this->changeColor($tree);
			}
		}		
		
	}

	public function isLeft($tree) {
		$isLeft = FALSE;
		if ($tree->parent->left == $tree) {
			$isLeft = TRUE;
		}
		return $isLeft;
	}

	public function getUncle(&$tree) {
		$uncle = $tree->parent->parent->left;
		if ($tree->parent->parent->left == $tree->parent) {
			$uncle = $tree->parent->parent->right;
		}
		return $uncle;
	}

	//右旋
	public function rightRotate($tree) {
		$subTree = $tree->left;
		if ($tree->parent) {
			$subTree->parent = $tree->parent;//更新新子树的父节点
			$left = FALSE;
			if ($tree->parent->left == $tree) {
				$left = TRUE;
			}
		} else {
			$subTree->parent = NULL;
		}

		$tree->left = $subTree->right;//原来左节点的右子树挂到老的根节点的左子树
		$subTree->right->parent = $tree;
		$tree->parent = $subTree;//原来的左节点变成老的根节点的父节点
		$subTree->right = $tree;//原来的根节点变成原来左节点的右子树
		$tree = $subTree;
		if (!$tree->parent) {//旋转的是整棵树的根节点
			self::$tree = $tree;
		} else {
			if ($left) {//更新老的子树根节点父节点指针指向新的根节点
				$tree->parent->left = $tree;
			} else {
				$tree->parent->right = $tree;
			}
		}
		return $tree;
	}

	//左旋
	public function leftRotate($tree) {
		$subTree = $tree->right;
		if ($tree->parent) {
			$subTree->parent = $tree->parent;
			$left = FALSE;
			if ($tree->parent->left == $tree) {
				$left = TRUE;
			}
		} else {
			$subTree->parent = NULL;
		}

		$tree->right = $subTree->left;
		$subTree->left->parent = $tree;
		$tree->parent = $subTree;
		$subTree->left = $tree;
		$tree = $subTree;
		if (!$tree->parent) {
			self::$tree = $tree;
		} else {
			if ($left) {
				$tree->parent->left = $tree;
			} else {
				$tree->parent->right = $tree;
			}
		}
		return $tree;
	}
}

//测试数据
$treeObj = new RBTree();
$treeObj->insert(99);
// $treeObj->insert(78);
// $treeObj->insert(120);
// $treeObj->insert(66);
// $treeObj->insert(83);
// $treeObj->insert(57);
// $treeObj->insert(52);
// $treeObj->insert(61);
// $treeObj->insert(64);
// $treeObj->insert(59);
// $treeObj->insert(60);
// $treeObj->insert(70);
// $treeObj->insert(75);
// $treeObj->insert(72);
// $treeObj->insert(74);
$tree = $treeObj->getTree();
$treeObj->midOrderTraverse($tree);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值