<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>红黑树 &#8211; 编程技术记录</title>
	<atom:link href="https://blog.z6z8.cn/tag/%E7%BA%A2%E9%BB%91%E6%A0%91/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.z6z8.cn</link>
	<description>世界你好!</description>
	<lastBuildDate>Tue, 17 Sep 2019 08:11:21 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>红黑树实现 &#8211;php版本</title>
		<link>https://blog.z6z8.cn/2019/09/17/%e7%ba%a2%e9%bb%91%e6%a0%91%e5%ae%9e%e7%8e%b0-php%e7%89%88%e6%9c%ac/</link>
		
		<dc:creator><![CDATA[holdsky]]></dc:creator>
		<pubDate>Tue, 17 Sep 2019 08:11:21 +0000</pubDate>
				<category><![CDATA[php]]></category>
		<category><![CDATA[代码片段]]></category>
		<category><![CDATA[红黑树]]></category>
		<guid isPermaLink="false">http://139.155.43.7:8000/?p=340</guid>

					<description><![CDATA[&#60;?php //大部分代码按照自己对算法导论的伪代码的理解编写 namespace zxszl; /*  [&#8230;]]]></description>
										<content:encoded><![CDATA[<pre><code class="language-php">&lt;?php

//大部分代码按照自己对算法导论的伪代码的理解编写
namespace zxszl;

/*
红黑树的特性:
（1）每个节点或者是黑色，或者是红色。
（2）根节点是黑色。
（3）每个叶节点（NIL）是黑色。 [注意：这里叶节点，是指为空(NIL或NULL)的子节点！]
（4）如果一个节点是红色的，则它的子节点必须是黑色的。
（5）从一个节点到该节点的叶节点的所有路径上包含相同数目的黑节点。
*/
//参考 https://blog.csdn.net/v_JULY_v/article/details/6105630

class RedBlackNode
{
    public $parent;//父节点
    public $left; //左子节点
    public $right; //右子节点
    public $isRed; //红色节点或者黑色节点

    /**
     * 这里引入两个变量，是为了方便字典数据结构
     * 其中，key作为红黑树的排序依据    
     */
    public $key; //节点值
    public $value; //节点值

    public function __construct ()
    {
        $this-&gt;parent = null;
        $this-&gt;left = null;
        $this-&gt;right = null;
        $this-&gt;isRed = true;

        $this-&gt;key = null;
        $this-&gt;value = null;
    }
}
/**
 * 红黑树 ，左边小节点，右边大节点
 */
class RedBlackTree
{
     /**
     * 深度（树高度）
     * @param RedBlackNode $node
     * @return int
     */
    static public function depth($node)
    {
        if ($node === NULL) {
            return 0;
        }
        $left_d = RedBlackTree::depth($node-&gt;left);
        $right_d = RedBlackTree::depth($node-&gt;right);
        return ($left_d &gt; $right_d ? $left_d : $right_d) + 1;
    }
    /**
     * 最小节点
     * @return RedBlackNode 最小节点
     */
    static public function minNode($node)
    {
        $current = $node;
        if ($current !== null) {
            while ($current-&gt;left !== null) {
                $current = $current-&gt;left;
            }
        }
        return $current;
    }

    /**
     * 最大节点
     * @return RedBlackNode 最大节点
     */
    static public function maxNode($node)
    {
        $current = $node;
        if ($current !== null) {
            while ($current-&gt;right !== null) {
                $current = $current-&gt;right;
            }
        }
        return $current;
    }

    /**
     * 查找指定节点
     * @return RedBlackNode 节点
     */
    public function searchNode($key)
    {
        $current = $this-&gt;rootNode;
        while ($current !== NULL) 
        {
            if ($current-&gt;key === $key) {
                return $current;
            } elseif ($current-&gt;key &gt; $key) {
                $current = $current-&gt;left;
            } else {
                $current = $current-&gt;right;
            }
        }
        return null;
    }
    /**
     * 插入节点，若$key已经存在，则替换对应节点的$value
     * @return RedBlackNode 插入的节点
     */
    public function insertNode($key,$value)
    {
        //查找节点插入时的父亲节点
        $nodeParent = null;
        do
        {
            $tmp = $this-&gt;rootNode;
            while ($tmp !== null)
            {
                $nodeParent = $tmp;
                if ($key === $tmp-&gt;key ) {//已经存在key，不必再插入,只要替换value就可以
                    $tmp-&gt;value = $value;
                    return; 
                }
                else if ( $key &lt; $tmp-&gt;key ) {
                    $tmp = $tmp-&gt;left;
                }
                else {
                    $tmp = $tmp-&gt;right;
                }
            }
        }while(0);

        //创建新节点,节点为红色
        $node = new RedBlackNode();
        // $node-&gt;isRed = true;
        $node-&gt;key = $key;
        $node-&gt;value = $value;

        //插入节点
        $node-&gt;parent = $nodeParent;
        if ($nodeParent === null) {
            $this-&gt;rootNode = $node;
        }
        else if ($node-&gt;key &lt; $nodeParent-&gt;key) {
            $nodeParent-&gt;left = $node;
        }
        else {
            $nodeParent-&gt;right = $node;
        }
        //修正红黑树
        $this-&gt;p_insert_fixup($node);
    }
    /**
     * 删除节点
     */
    public function deleteNode ($key) {
        $z = $this-&gt;searchNode($key);
        if ( $z !== null ) //找到$key对应的节点
        {   //$z //待删除节点
            $y = null;
            $x = null;

            ///&gt;&gt;&gt;START $z不为null，那么经过操作，$y一定不为null
            if ($z-&gt;left === null || $z-&gt;right === null) {
                $y = $z;
            } else {
                $y = RedBlackTree::minNode($z-&gt;right); //$z的最小上限
            }
            ///&lt;&lt;&lt;END

            if ( $y-&gt;left !== null ) {
                $x = $y-&gt;left;
            } else {
                $x = $y-&gt;right;
            }

            //删除节点$y
            if ($x !== null){
                $x-&gt;parent = $y-&gt;parent;
            }

            if ($y-&gt;parent === null ) {
                $this-&gt;rootNode = $x;
            }
            else if ( $y === $y-&gt;parent-&gt;left ) {
                $y-&gt;parent-&gt;left = $x;
            }
            else {
                $y-&gt;parent-&gt;right = $x;
            }
            $xParent = $y-&gt;parent;

            //如果$y不是$z，那么用$y的信息覆盖$z,这样达到删除$z的目的
            if ($y !== $z) {
                $z-&gt;key = $y-&gt;key;
                $z-&gt;value = $y-&gt;value;
            }
            //如果删除的节点是黑色，则需要修正
            if ($y-&gt;isRed === false) {//$y可能是$z ,也可能是$z的最小上限
                $this-&gt;p_delete_fixup($x,$xParent);
            }
        }
    }

    /**
     * 修正红黑树
     * @param RedBlackNode node 插入的节点
     */
    private function p_insert_fixup($node)
    {
        while ($node-&gt;parent !== null &amp;&amp; $node-&gt;parent-&gt;isRed === true ) //如果node的父节点是红色 (node是红色)
        {
            $grandParent = $node-&gt;parent-&gt;parent; //祖父节点，一定存在 (根据红黑树性质，红色节点一定有父节点))
            if ($node-&gt;parent === $grandParent-&gt;left ) { //node的父节点是左孩子
                $uncle = $grandParent-&gt;right;
                //case1：node的父节点是红色，且叔节点是红色
                if ($uncle &amp;&amp; $uncle-&gt;isRed === true ) {
                    $uncle-&gt;isRed = false;
                    $node-&gt;parent-&gt;isRed = false;
                    $grandParent-&gt;isRed = true;
                    $node = $grandParent;
                    continue; //经过这一步之后，组父节点作为新节点存在（跳到case2）
                }
                //case2：node的父节点是红色,叔节点是黑色，node是其父节点的右孩子
                else if ($node === $node-&gt;parent-&gt;right ) {
                    $node = $node-&gt;parent;
                    $this-&gt;p_left_rotate($node);
                }
                //case3：node的父节点是红色,叔节点是黑色，node是其父节点的左孩子
                $node-&gt;parent-&gt;isRed = false;
                $grandParent-&gt;isRed = true;
                $this-&gt;p_right_rotate($grandParent);
            }
            else { //node的父节点是右孩子
                $uncle = $grandParent-&gt;left;
                //case1：node的父节点是红色，且叔节点是红色
                if ($uncle &amp;&amp; $uncle-&gt;isRed === true ) {
                    $uncle-&gt;isRed = false;
                    $node-&gt;parent-&gt;isRed = false;
                    $grandParent-&gt;isRed = true;
                    $node = $grandParent;
                    continue; //经过这一步之后，组父节点作为新节点存在（跳到case2）
                }
                //case2：node的父节点是红色,叔节点是黑色，node是其父节点的左孩子
                else if ($node === $node-&gt;parent-&gt;left ) {
                    $node = $node-&gt;parent;
                    $this-&gt;p_right_rotate($node);
                }
                //case3：node的父节点是红色,叔节点是黑色，node是其父节点的左孩子
                $node-&gt;parent-&gt;isRed = false;
                $grandParent-&gt;isRed = true;
                $this-&gt;p_left_rotate($grandParent);
            } 
        }
        $this-&gt;rootNode-&gt;isRed = false;
    }

    /**
     * 修正红黑树
     * @param RedBlackNode $x
     * @param RedBlackNode $xParent
     */
    private function p_delete_fixup($x,$xParent)
    {
        while ( $x !== $this-&gt;rootNode &amp;&amp; ($x ===null || $x-&gt;isRed === false ) )
        {
            if ($x === $xParent-&gt;left ) //$x不是根节点，那么$xParent一定存在
            { 
                $w = $xParent-&gt;right;
                if ($w !== null ) //若为null，则$w黑色
                {
                    //case1：$x黑, 兄弟节点$w红，父节点黑
                    if ($w-&gt;isRed === true ) 
                    {
                        $w-&gt;isRed = false;
                        $xParent-&gt;isRed = true;
                        $this-&gt;p_left_rotate($xParent);
                        $w = $xParent-&gt;right; //在左旋处理后，$xParent-&gt;right指向的是原来兄弟结点$w的右孩子，黑色
                    }
                    //case2：$x黑色， $w是黑色，且$w两个子节点都是黑色
                    if ( ($w-&gt;left===null || $w-&gt;left-&gt;isRed === false)
                            &amp;&amp; ($w-&gt;right===null || $w-&gt;right-&gt;isRed === false) )
                    {
                        $w-&gt;isRed = true;
                        $x = $xParent;
                        $xParent = $x-&gt;parent;
                    }
                    else 
                    {
                        //case3：$x黑色，$w黑色，$w左子是红色，$w右子是黑色
                        if ( $w-&gt;right===null || $w-&gt;right-&gt;isRed === false )
                        {
                            $w-&gt;left-&gt;isRed = false;
                            $w-&gt;isRed = true;
                            $this-&gt;p_right_rotate($w);
                            $w = $xParent-&gt;right;
                        }
                        //case4：$x黑色，$w黑色，$w右子是红色，$w左子的颜色任意
                        $w-&gt;isRed = $xParent-&gt;isRed;
                        $xParent-&gt;isRed = false;
                        if ($w-&gt;right !== null ) {
                            $w-&gt;right-&gt;isRed = false;
                        }
                        $this-&gt;p_left_rotate($xParent);
                        $x = $this-&gt;rootNode;
                        break;//加不加break都可以，因为下次循环条件不满足
                    }
                }
            }
            else //$x是右孩子  $x不是根节点，那么$xParent一定存在
            { 
                $w = $xParent-&gt;left;
                if ($w !== null ) //若为null，则$w黑色
                {
                    //case1：$x黑, 兄弟节点$w红，父节点黑
                    if ($w-&gt;isRed === true ) 
                    {
                        $w-&gt;isRed = false;
                        $xParent-&gt;isRed = true;
                        $this-&gt;p_right_rotate($xParent);
                        $w = $xParent-&gt;left; //在右旋处理后，$xParent-&gt;left指向的是原来兄弟结点$w的左孩子，黑色
                    }
                    //case2：$x黑色， $w是黑色，且$w两个子节点都是黑色
                    if ( ($w-&gt;left===null || $w-&gt;left-&gt;isRed === false)
                            &amp;&amp; ($w-&gt;right===null || $w-&gt;right-&gt;isRed === false) )
                    {
                        $w-&gt;isRed = true;
                        $x = $xParent;
                        $xParent = $x-&gt;parent;
                    }
                    else 
                    {
                        //case3：$x黑色，$w黑色，$w左子是黑色，$w右子是红色
                        if ( $w-&gt;left===null || $w-&gt;left-&gt;isRed === false )
                        {
                            $w-&gt;right-&gt;isRed = false;
                            $w-&gt;isRed = true;
                            $this-&gt;p_left_rotate($w);
                            $w = $xParent-&gt;left;
                        }
                        //case4：$x黑色，$w黑色，$w左子是红色，$w右子的颜色任意
                        $w-&gt;isRed = $xParent-&gt;isRed;
                        $xParent-&gt;isRed = false;
                        if ($w-&gt;left !== null ) {
                            $w-&gt;left-&gt;isRed = false;
                        }
                        $this-&gt;p_right_rotate($xParent);
                        $x = $this-&gt;rootNode;
                        break;//加不加break都可以，因为下次循环条件不满足
                    }
                }
            }
        }
        if ($x !== null ) {
            $x-&gt;isRed = false;
        }
    }

    /**
     * 对指定节点进行左旋操作
     * 左旋中的“左”，意味着“被旋转的节点将变成（自己右孩子的）一个左节点
     *      node                  right
     *      /  \                  /  \ 
     *     a  right   ======&gt;   node  c
     *        /  \              /  \
     *       b    c            a    b
     * 
     * @param RedBlackNode $node
     */
    private function p_left_rotate($node)
    {
        $rightChild = $node-&gt;right; //右孩子
        if ($rightChild === null){
            //右孩子为null，左旋结束
            return;
        }
        $rightChild-&gt;parent = $node-&gt;parent; //将 “node的父亲” 设为 “rightChild的父亲”
        if ($rightChild-&gt;parent === null) { 
            //情况1：如果 “rightChild的父亲” 是空节点，则将rightChild设为根节点
            $this-&gt;rootNode = $rightChild;
        }
        else if ($node === $node-&gt;parent-&gt;left ) { 
            //情况2：如果 node是它父节点的左孩子，则将rightChild设为“node的父节点的左孩子”
            $node-&gt;parent-&gt;left = $rightChild; 
        }
        else {
            // 情况3：(node是它父节点的右孩子) 将rightChild设为“node的父节点的右孩子”
            $node-&gt;parent-&gt;right = $rightChild; 
        }
        $node-&gt;parent = $rightChild; //将 “node的父节点” 设为 “rightChild”

        $node-&gt;right = $rightChild-&gt;left;    //将 “rightChild的左孩子” 设为 “node的右孩子”
        if ($rightChild-&gt;left !== null) {
            $rightChild-&gt;left-&gt;parent = $node;   //将 “node” 设为 “rightChild的左孩子的父亲”
        }
        $rightChild-&gt;left = $node; //将 “node” 设为 “rightChild的左孩子”
    }

    /**
     * 对指定节点进行右旋操作
     * 右旋中的“右”，意味着“被旋转的节点将变成（自己左孩子的）一个右节点”
     *      left                  node
     *      /  \                  /  \ 
     *     a  node   &lt;======    left  c
     *        /  \              /  \
     *       b    c            a    b
     * 
     * @param RedBlackNode $node
     */    
    private function p_right_rotate($node)
    {
        $leftChild = $node-&gt;left; //左孩子
        if ($leftChild === null) {
            //左孩子为null，右旋结束
            return;
        }
        $leftChild-&gt;parent = $node-&gt;parent; //将 “node的父节点” 设为 “leftChild的父节点”
        if ($leftChild-&gt;parent === null) {
            // 情况1：如果 “leftChild的父亲” 是空节点，则将leftChild设为根节点
            $this-&gt;rootNode = $leftChild;
        }
        else if ($node === $node-&gt;parent-&gt;left ) {
            // 情况2：如果 node 是它父节点的左孩子，则将leftChild设为“node的父节点的左孩子”
            $node-&gt;parent-&gt;left = $leftChild;
        }
        else {
            // 情况3：如果 node 是它父节点的右孩子，则将leftChild设为“node的父节点的右孩子”
            $node-&gt;parent-&gt;right = $leftChild;
        }
        $node-&gt;parent = $leftChild; //将leftChild设为“node的父节点”

        $node-&gt;left = $leftChild-&gt;right; //将 “leftChild的右孩子” 设为"node的左孩子"
        if ( $leftChild-&gt;right !== null ){
            $leftChild-&gt;right-&gt;parent = $node; //将node 设为 “leftChild的右孩子的父节点”
        }
        $leftChild-&gt;right = $node;   //将 "node" 设为 “leftChild的右孩子”
    }

    private $rootNode;
}

 $rbTree = new RedBlackTree();
 $testN = 10000;

 function testInsert( $rbTree )
 {
     global $testN;
     $tmpArray = array();
     for ($i = 0 ; $i &lt; $testN ; $i++)
     {
         array_push($tmpArray,$i);
     }
     shuffle($tmpArray);

     for ($i = 0 ; $i &lt; $testN ; $i++)
     {
         $k = $tmpArray[$i];
         $rbTree-&gt;insertNode($k,$k);
     }

     for ($i = 0 ; $i &lt; $testN ; $i++)
     {
         $node = $rbTree-&gt;searchNode($i);
         if($node === null) {
             echo "not found $i";
         }
         else if ($node-&gt;value !== $i ) {
             $value = $node-&gt;value;
             echo "found $i,but value is $value";
         }
     }
 }

 function testDelete( $rbTree )
 {
     global $testN;
     $tmpArray = array();
     for ($i = 0 ; $i &lt; $testN ; $i++)
     {
         array_push($tmpArray,$i);
     }
     shuffle($tmpArray);

     for ($i = 0 ; $i &lt; $testN ; $i++)
     {
         $k = $tmpArray[$i];
         $rbTree-&gt;deleteNode($k);
     }

     for ($i = 0 ; $i &lt; $testN ; $i++)
     {
         $node = $rbTree-&gt;searchNode($i);
         if($node !== null) {
             echo "found $i";
         }
     }
 }

 testInsert($rbTree);
 testDelete($rbTree);</code></pre>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
