前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >PHP二叉树(三):红黑树

PHP二叉树(三):红黑树

作者头像
guanguans
发布于 2018-05-09 08:37:51
发布于 2018-05-09 08:37:51
1.4K00
代码可运行
举报
文章被收录于专栏:琯琯博客琯琯博客
运行总次数:0
代码可运行

红黑树

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php
/**
 * description: 红黑树
 */
//结点
class Node
{
    public $key;
    public $parent;
    public $left;
    public $right;
    public $IsRed;  //分辨红节点或黑节点

    public function __construct($key, $IsRed = TRUE)
    {
        $this--->key = $key;
        $this->parent = NULL;
        $this->left = NULL;
        $this->right = NULL;
        //插入结点默认是红色
        $this->IsRed = $IsRed;
    }
}

//红黑树
class Rbt
{
    public $root;

    /**
     * 初始化树结构
     * @param $arr 初始化树结构的数组
     * @return null
     */
    public function init($arr)
    {
        //根节点必须是黑色
        $this->root = new Node($arr[0], FALSE);
        for ($i = 1; $i < count($arr); $i++) {
            $this->Insert($arr[$i]);
        }
    }

    /**
     * (对内)中序遍历
     * @param $root (树或子树的)根节点
     * @return null
     */
    private function mid_order($root)
    {
        if ($root != NULL) {
            $this->mid_order($root->left);
            echo $root->key . "-" . ($root->IsRed ? 'r' : 'b') . '  ';
            $this->mid_order($root->right);
        }
    }

    /**
     * (对外)中序遍历
     * @param null
     * @return null
     */
    public function MidOrder()
    {
        $this->mid_order($this->root);
    }

    /**
     * 查找树中是否存在$key对应的节点
     * @param $key 待搜索数字
     * @return $key对应的节点
     */
    function search($key)
    {
        $current = $this->root;
        while ($current != NULL) {
            if ($current->key == $key) {
                return $current;
            } elseif ($current->key > $key) {
                $current = $current->left;
            } else {
                $current = $current->right;
            }
        }
        //结点不存在
        return $current;
    }

    /**
     * 将以$root为根节点的最小不平衡二叉树做右旋处理
     * @param $root(树或子树)根节点
     * @return null
     */
    private function R_Rotate($root)
    {
        $L = $root->left;
        if (!is_null($root->parent)) {
            $P = $root->parent;
            if($root == $P->left){
                $P->left = $L;
            }else{
                $P->right = $L;
            }
            $L->parent = $P;
        } else {
            $L->parent = NULL;
        }
        $root->parent = $L;
        $root->left = $L->right;
        $L->right = $root;
        //这句必须啊!
        if ($L->parent == NULL) {
            $this->root = $L;
        }
    }

    /**
     * 将以$root为根节点的最小不平衡二叉树做左旋处理
     * @param $root(树或子树)根节点
     * @return null
     */
    private function L_Rotate($root)
    {
        $R = $root->right;
        if (!is_null($root->parent)) {
            $P = $root->parent;
            if($root == $P->right){
                $P->right = $R;
            }else{
                $P->left = $R;
            }
            $R->parent = $P;
        } else {
            $R->parent = NULL;
        }
        $root->parent = $R;
        $root->right = $R->left;
        $R->left = $root;
        //这句必须啊!
        if ($R->parent == NULL) {
            $this->root = $R;
        }
    }

    /**
     * 查找树中的最小关键字
     * @param $root 根节点
     * @return 最小关键字对应的节点
     */
    function search_min($root)
    {
        $current = $root;
        while ($current->left != NULL) {
            $current = $current->left;
        }
        return $current;
    }

    /**
     * 查找树中的最大关键字
     * @param $root 根节点
     * @return 最大关键字对应的节点
     */
    function search_max($root)
    {
        $current = $root;
        while ($current->right != NULL) {
            $current = $current->right;
        }
        return $current;
    }

    /**
     * 查找某个$key在中序遍历时的直接前驱节点
     * @param $x 待查找前驱节点的节点引用
     * @return 前驱节点引用
     */
    function predecessor($x)
    {
        //左子节点存在,直接返回左子节点的最右子节点
        if ($x->left != NULL) {
            return $this->search_max($x->left);
        }
        //否则查找其父节点,直到当前结点位于父节点的右边
        $p = $x->parent;
        //如果x是p的左孩子,说明p是x的后继,我们需要找的是p是x的前驱
        while ($p != NULL && $x == $p->left) {
            $x = $p;
            $p = $p->parent;
        }
        return $p;
    }

    /**
     * 查找某个$key在中序遍历时的直接后继节点
     * @param $x 待查找后继节点的节点引用
     * @return 后继节点引用
     */
    function successor($x)
    {
        if ($x->left != NULL) {
            return $this->search_min($x->right);
        }
        $p = $x->parent;
        while ($p != NULL && $x == $p->right) {
            $x = $p;
            $p = $p->parent;
        }
        return $p;
    }

    /**
     * 将$key插入树中
     * @param $key 待插入树的数字
     * @return null
     */
    public function Insert($key)
    {
        if (!is_null($this->search($key))) {
            throw new Exception('结点' . $key . '已存在,不可插入!');
        }
        $root = $this->root;
        $inode = new Node($key);
        $current = $root;
        $prenode = NULL;
        //为$inode找到合适的插入位置
        while ($current != NULL) {
            $prenode = $current;
            if ($current->key > $inode->key) {
                $current = $current->left;
            } else {
                $current = $current->right;
            }
        }

        $inode->parent = $prenode;
        //如果$prenode == NULL, 则证明树是空树
        if ($prenode == NULL) {
            $this->root = $inode;
        } else {
            if ($inode->key < $prenode->key) {
                $prenode->left = $inode;
            } else {
                $prenode->right = $inode;
            }
        }

        //将它重新修正为一颗红黑树
        $this->InsertFixUp($inode);
    }

    /**
     * 对插入节点的位置及往上的位置进行颜色调整
     * @param $inode 插入的节点
     * @return null
     */
    private function InsertFixUp($inode)
    {
        //情况一:需要调整条件,父节点存在且父节点的颜色是红色
        while (($parent = $inode->parent) != NULL && $parent->IsRed == TRUE) {
            //祖父结点:
            $gparent = $parent->parent;

            //如果父节点是祖父结点的左子结点,下面的else与此相反
            if ($parent == $gparent->left) {
                //叔叔结点
                $uncle = $gparent->right;

                //case1:叔叔结点也是红色
                if ($uncle != NULL && $uncle->IsRed == TRUE) {
                    //将父节点和叔叔结点都涂黑,将祖父结点涂红
                    $parent->IsRed = FALSE;
                    $uncle->IsRed = FALSE;
                    $gparent->IsRed = TRUE;
                    //将新节点指向祖父节点(现在祖父结点变红,可以看作新节点存在)
                    $inode = $gparent;
                    //继续while循环,重新判断
                    continue;   //经过这一步之后,组父节点作为新节点存在(跳到case2)
                }

                //case2:叔叔结点是黑色,且当前结点是右子节点
                if ($inode == $parent->right) {
                    //以父节点作为旋转结点做左旋转处理
                    $this->L_Rotate($parent);
                    //在树中实际上已经转换,但是这里的变量的指向还没交换,
                    //将父节点和字节调换一下,为下面右旋做准备
                    $temp = $parent;
                    $parent = $inode;
                    $inode = $temp;
                }

                //case3:叔叔结点是黑色,而且当前结点是父节点的左子节点
                $parent->IsRed = FALSE;
                $gparent->IsRed = TRUE;
                $this->R_Rotate($gparent);
            } //如果父节点是祖父结点的右子结点,与上面完全相反
            else {
                //叔叔结点
                $uncle = $gparent->left;

                //case1:叔叔结点也是红色
                if ($uncle != NULL && $uncle->IsRed == TRUE) {
                    //将父节点和叔叔结点都涂黑,将祖父结点涂红
                    $parent->IsRed = FALSE;
                    $uncle->IsRed = FALSE;
                    $gparent->IsRed = TRUE;
                    //将新节点指向祖父节点(现在祖父结点变红,可以看作新节点存在)
                    $inode = $gparent;
                    //继续while循环,重新判断
                    continue;   //经过这一步之后,组父节点作为新节点存在(跳到case2)
                }

                //case2:叔叔结点是黑色,且当前结点是左子节点
                if ($inode == $parent->left) {
                    //以父节点作为旋转结点做右旋转处理
                    $this->R_Rotate($parent);
                    //在树中实际上已经转换,但是这里的变量的指向还没交换,
                    //将父节点和字节调换一下,为下面右旋做准备
                    $temp = $parent;
                    $parent = $inode;
                    $inode = $temp;
                }

                //case3:叔叔结点是黑色,而且当前结点是父节点的右子节点
                $parent->IsRed = FALSE;
                $gparent->IsRed = TRUE;
                $this->L_Rotate($gparent);
            }
        }
        //情况二:原树是根节点(父节点为空),则只需将根节点涂黑
        if ($inode == $this->root) {
            $this->root->IsRed = FALSE;
            return;
        }

        //情况三:插入节点的父节点是黑色,则什么也不用做
        if ($inode->parent != NULL && $inode->parent->IsRed == FALSE) {
            return;
        }
    }

    /**
     * (对外)删除指定节点
     * @param $key 删除节点的key值
     * @return null
     */
    function Delete($key)
    {
        if (is_null($this->search($key))) {
            throw new Exception('结点' . $key . "不存在,删除失败!");
        }
        $dnode = $this->search($key);
        if ($dnode->left == NULL || $dnode->right == NULL) { #如果待删除结点无子节点或只有一个子节点,则c = dnode
            $c = $dnode;
        } else { #如果待删除结点有两个子节点,c置为dnode的直接后继,以待最后将待删除结点的值换为其后继的值
            $c = $this->successor($dnode);
        }

        //为了后面颜色处理做准备
        $parent = $c->parent;

        //无论前面情况如何,到最后c只剩下一边子结点
        if ($c->left != NULL) {    //这里不会出现,除非选择的是删除结点的前驱
            $s = $c->left;
        } else {
            $s = $c->right;
        }

        if ($s != NULL) { #将c的子节点的父母结点置为c的父母结点,此处c只可能有1个子节点,因为如果c有两个子节点,则c不可能是dnode的直接后继
            $s->parent = $c->parent;
        }

        if ($c->parent == NULL) { #如果c的父母为空,说明c=dnode是根节点,删除根节点后直接将根节点置为根节点的子节点,此处dnode是根节点,且拥有两个子节点,则c是dnode的后继结点,c的父母就不会为空,就不会进入这个if
            $this->root = $s;
        } else if ($c == $c->parent->left) { #如果c是其父节点的左右子节点,则将c父母的左右子节点置为c的左右子节点
            $c->parent->left = $s;
        } else {
            $c->parent->right = $s;
        }

        $dnode->key = $c->key;

        $node = $s;

        //c的结点颜色是黑色,那么会影响路径上的黑色结点的数量,必须进行调整
        if ($c->IsRed == FALSE) {
            $this->DeleteFixUp($node,$parent);
        }
    }

    /**
     * 删除节点后对接点周围的其他节点进行调整
     * @param $key 删除节点的子节点和父节点
     * @return null
     */
    private function DeleteFixUp($node,$parent)
    {
        //如果待删结点的子节点为红色,直接将子节点涂黑
        if ($node != NULL && $node->IsRed == TRUE) {
            $node->IsRed = FALSE;
            return;
        }


        //如果是根节点,那就直接将根节点置为黑色即可
        while (($node == NULL || $node->IsRed == FALSE) && ($node != $this->root)) {
            //node是父节点的左子节点,下面else与这里相反
            if ($node == $parent->left) {
                $brother = $parent->right;

                //case1:兄弟结点颜色是红色(父节点和兄弟孩子结点都是黑色)
                //将父节点涂红,将兄弟结点涂黑,然后对父节点进行左旋处理(经过这一步,情况转换为兄弟结点颜色为黑色的情况)
                if ($brother->IsRed == TRUE) {
                    $brother->IsRed = FALSE;
                    $parent->IsRed = TRUE;
                    $this->L_Rotate($parent);
                    //将情况转化为其他的情况
                    $brother = $parent->right;  //在左旋处理后,$parent->right指向的是原来兄弟结点的左子节点
                }

                //以下是兄弟结点为黑色的情况

                //case2:兄弟结点是黑色,且兄弟结点的两个子节点都是黑色
                //将兄弟结点涂红,将当前结点指向其父节点,将其父节点指向当前结点的祖父结点。
                if (($brother->left == NULL || $brother->left->IsRed == FALSE) && ($brother->right == NULL || $brother->right->IsRed == FALSE)) {
                    $brother->IsRed = TRUE;
                    $node = $parent;
                    $parent = $node->parent;
                } else {
                    //case3:兄弟结点是黑色,兄弟结点的左子节点是红色,右子节点为黑色
                    //将兄弟结点涂红,将兄弟节点的左子节点涂黑,然后对兄弟结点做右旋处理(经过这一步,情况转换为兄弟结点颜色为黑色,右子节点为红色的情况)
                    if ($brother->right == NULL || $brother->right->IsRed == FALSE) {
                        $brother->IsRed = TRUE;
                        $brother->left->IsRed = FALSE;

                        $this->R_Rotate($brother);
                        //将情况转换为其他情况
                        $brother = $parent->right;
                    }

                    //case4:兄弟结点是黑色,且兄弟结点的右子节点为红色,左子节点为任意颜色
                    //将兄弟节点涂成父节点的颜色,再把父节点涂黑,将兄弟结点的右子节点涂黑,然后对父节点做左旋处理
                    $brother->IsRed = $parent->IsRed;
                    $parent->IsRed = FALSE;

                    $brother->right->IsRed = FALSE;
                    $this->L_Rotate($parent);
                    //到了第四种情况,已经是最基本的情况了,可以直接退出了
                    $node = $this->root;
                    break;
                }
            } //node是父节点的右子节点
            else {
                $brother = $parent->left;

                //case1:兄弟结点颜色是红色(父节点和兄弟孩子结点都是黑色)
                //将父节点涂红,将兄弟结点涂黑,然后对父节点进行右旋处理(经过这一步,情况转换为兄弟结点颜色为黑色的情况)
                if ($brother->IsRed == TRUE) {
                    $brother->IsRed = FALSE;
                    $parent->IsRed = TRUE;
                    $this->R_Rotate($parent);
                    //将情况转化为其他的情况
                    $brother = $parent->left;  //在右旋处理后,$parent->left指向的是原来兄弟结点的右子节点
                }

                //以下是兄弟结点为黑色的情况

                //case2:兄弟结点是黑色,且兄弟结点的两个子节点都是黑色
                //将兄弟结点涂红,将当前结点指向其父节点,将其父节点指向当前结点的祖父结点。
                if (($brother->left == NULL || $brother->left->IsRed == FALSE) && ($brother->right == NULL || $brother->right->IsRed == FALSE)) {
                    $brother->IsRed = TRUE;
                    $node = $parent;
                    $parent = $node->parent;
                } else {
                    //case3:兄弟结点是黑色,兄弟结点的右子节点是红色,左子节点为黑色
                    //将兄弟结点涂红,将兄弟节点的左子节点涂黑,然后对兄弟结点做左旋处理(经过这一步,情况转换为兄弟结点颜色为黑色,右子节点为红色的情况)
                    if ($brother->left == NULL || $brother->left->IsRed == FALSE) {
                        $brother->IsRed = TRUE;
                        $brother->right = FALSE;
                        $this->L_Rotate($brother);
                        //将情况转换为其他情况
                        $brother = $parent->left;
                    }

                    //case4:兄弟结点是黑色,且兄弟结点的左子节点为红色,右子节点为任意颜色
                    //将兄弟节点涂成父节点的颜色,再把父节点涂黑,将兄弟结点的右子节点涂黑,然后对父节点左左旋处理
                    $brother->IsRed = $parent->IsRed;
                    $parent->IsRed = FALSE;
                    $brother->left->IsRed = FALSE;
                    $this->R_Rotate($parent);
                    $node = $this->root;
                    break;
                }
            }
        }
        if ($node != NULL) {
            $this->root->IsRed = FALSE;
        }
    }

    /**
     * (对内)获取树的深度
     * @param $root 根节点
     * @return 树的深度
     */
    private function getdepth($root)
    {
        if ($root == NULL) {
            return 0;
        }
        $dl = $this->getdepth($root->left);

        $dr = $this->getdepth($root->right);

        return ($dl > $dr ? $dl : $dr) + 1;
    }

    /**
     * (对外)获取树的深度
     * @param null
     * @return null
     */
    public function Depth()
    {
        return $this->getdepth($this->root);
    }
}

(完)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-11-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
关于有限状态机(FSM)的一些思考
有限状态机,英文翻译是 Finite State Machine,缩写为 FSM,简称为状态机。状态机有 3 个组成部分:状态(State)、事件(Event)、动作(Action)。其中,事件也称为转移条件(Transition Condition)。事件触发状态的转移及动作的执行。动作也不是必须的,也可能只转移状态,不执行任何动作。
巫山老妖
2023/09/24
2.9K0
关于有限状态机(FSM)的一些思考
一个有限状态机的C++实现
先放一个用C++11实现的FSM的代码: kuafu 咱们先来看一下什么是有限状态机(Finite-state machine, FSM), 先给一个 百度百科的解释 简单说就是作一件事可能会经
扫帚的影子
2018/09/05
3.6K0
一个有限状态机的C++实现
有限状态机模型
在阅读harbor源码时,在jobservice代码中,发现实现了一个有限状态机。状态管理在系统设计中常被使用。通过实现它,可以方便的对程序的状态进行管理。状态在现实生活中,有很多存在的例子。例如,灯有开,关两种状态,当然如果较真的话,中间还可以有多个亮度的状态。红绿灯,登录状态,程序的生命周期等等,这个太多了。
暮雨
2018/11/15
1.8K0
有限状态机模型
有限状态机FSM的原理与GO的实现
有限状态机(Finite-state machine, 简写FSM)又可以称作有限状态自动机。它必须是可以附着在某种事物上的,且该事物的状态是有限的,通过某些触发事件,会让其状态发生转换。为此,有限状态机就是描述这些有限的状态和触发事件及转换行为的数学模型。 有限状态机组成 有限状态机有两个必要的特点,一是离散的,二是有限的。基于这两点,现实世界上绝大多数事物因为复杂的状态而无法用有限状态机表示。 而描述事物的有限状态机模型的元素由以下组成: 状态(State):事物的状态,包括初始状态和所有事件触发后的状
李海彬
2018/03/28
3.6K0
有限状态机FSM的原理与GO的实现
超轻量级有限状态机Mini-FSM
有限状态机(Finite State Machine,简称FSM),表示有限个状态以及在这些状态之间的转移和动作等行为的处理模型。在任何给定的时间点,有限状态机都处于某一特定状态,并且可以根据当前状态和输入条件,从当前状态转移到另一个状态。有限状态机相关的核心概念主要包括:
Yiwenwu
2024/05/18
1K0
超轻量级有限状态机Mini-FSM
设计模式-状态机模式
有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
简单的幸福
2020/05/08
4.1K0
设计模式-状态机模式
一个用go实现的有限状态机
不是特别喜欢,每次实例化fsm都需要重新传递对应events(虽然我们可以统一封装),我更期望在项目启动时把此项目涉及到不同业务状态机流转注册到fsm,对应:不同业务->[状态]->[事件]->处理事件主体(包含handler、params、hooks、observers等)。
RememberGo
2022/03/12
2.9K0
如何以面向对象的思想设计有限状态机
有限状态机又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型,用英文缩写也被简称为 FSM。
wenzid
2020/05/03
1.4K0
如何以面向对象的思想设计有限状态机
fsm:有限状态机
有限状态机(英语:finite-state machine,缩写:FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
一个会写诗的程序员
2020/09/28
1.6K0
fsm:有限状态机
笨办法学 Python · 续 练习 30:有限状态机
每当你阅读一本关于解析的书,都有一个可怕的章节,关于有限状态机(FSM)。他们对“边”和“节点”进行了详细的分析,每个可能的“自动机”的组合被转换成其他自动机,坦率地说,它有点多了。FSM 有一个更简单的解释,使得它们实用并且可理解,而不会违背相同主题的纯理论版本。当然你不会向 ACM 提交论文,因为你不知道 FSM 背后的所有数学知识,但如果你只想在应用程序中使用它们,那么它们就足够简单了。
ApacheCN_飞龙
2022/12/01
5580
OpenFSM是全网最好用的C++有限状态机
源代码:https://github.com/OpenMiniServer/openfsm
linyouhappy
2023/03/10
2K0
OpenFSM是全网最好用的C++有限状态机
(有限)状态机
而我们常常说的状态机指有限状态机,缩写是FSM(Finite State Machine)。
滚神大人
2021/09/10
2.5K0
‘SHIT’上最全有限状态机设计研究(一)-状态机介绍
本系列主要针对有限状态机进行分析和设计,其中主要包括两部分:时钟同步状态机的分析和时钟同步状态机的设计,预计会有五篇文章进行展开,其中介绍一篇,分析和设计分别有两篇,每一部分都会有相应的实例。
碎碎思
2020/06/30
1.4K0
JavaScript与有限状态机
有限状态机(Finite-state machine)是一个非常有用的模型,可以模拟世界上大部分事物。 简单说,它有三个特征:   * 状态总数(state)是有限的。   * 任一时刻,只处在一
ruanyf
2018/04/12
1K0
JavaScript与有限状态机
使用有限状态机原理实现英文分词
使用Python开发一个英文句子分词程序,把一段英文句子切分为每一个单词。不能导入任何官方的或者第三方的库,也不能使用字符串的split()方法。
青南
2018/08/30
1K0
使用有限状态机原理实现英文分词
前端工程师的编译原理指南-「有限状态机」
在上一篇文章中我们讨论了编译器的一次完整工作流程,需要经历解析阶段 (Parsing)、转化阶段 (Transformaiton)、生成阶段 (Code Generation) 三个阶段来处理我们的输入最终得到输出的结果。
19组清风
2022/02/28
6070
前端工程师的编译原理指南-「有限状态机」
状态机系列 (一) : 令人头疼的状态管理
这次,ycaptain 将带着大家解锁一条新的系列文章:「XState 有限状态机与状态图」
公众号@魔术师卡颂
2021/09/18
1.4K0
状态机系列 (一) : 令人头疼的状态管理
实战并发-使用分布式缓存和有限状态机
这里的并发不是高并发,只是将正式环境的一小段流量同时打到我的自测环境。一个请求同时多次发送,真正意义上并发处理同一个数据,主要需求是保证数据幂等性和正确性。
静儿
2019/03/19
1K0
实战并发-使用分布式缓存和有限状态机
大中台模式下如何构建复杂业务核心状态机组件
由此可见,对于复杂状态的管理是一个业务依赖,需求多变的场景。在公司初创期,可以采用硬编码方式,对于每一个操作进行状态判断,每一步操作定制一套逻辑链路。随着业务的增加,定制化链路显然不优雅,大量流程代码无法维护,此时中台通用解决思路就尤为重要,有限状态机(Finite State Machine,缩写:FSM)开始在中台落地。
玄姐谈AGI
2019/11/07
2.7K0
大中台模式下如何构建复杂业务核心状态机组件
AI 助力游戏开发实践-有限状态机
在数字娱乐产业中,游戏开发无疑是最具活力和创新性的领域之一。随着技术的进步和玩家需求的日益增长,游戏开发者面临着前所未有的挑战和机遇。游戏不仅要在图形和玩法上不断创新,还要提供流畅的用户体验和智能的游戏逻辑。在这样的背景下,有限状态机(FSM)成为了游戏开发中一个不可或缺的工具,它为游戏角色和系统的行为提供了一种清晰、可控的实现方式。
腾讯云开发者
2025/01/09
3450
AI 助力游戏开发实践-有限状态机
推荐阅读
相关推荐
关于有限状态机(FSM)的一些思考
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验