游戏开发-红点管理(使用二叉树)

二叉树实现红点管理

游戏中的红点系统,记录下使用二叉树更新和查询红点信息。

红点的信息是明显包含一个树形结构,这里使用二叉树,其中左节点表示孩子节点,右节点表示兄弟节点。
红点信息以数组形式表示,例如一组信息 [活动, 限时活动, 具体活动]

红点的更新与查询可分为:添加红点、删除红点、查询红点。
主要代码如下,注意二叉树递归遍历的细节

结构定义

    private redDotRoot: any;	// 根节点
    private redDotType: any = -1;

    constructor(type: any = -1) {
        this.redDotType = type;
        this.redDotRoot = this.createNode(type);
    }

    private createNode(type: any, left: any = null, right: any = null): any {
        let node = {
            type: type,
            left: left,
            right: right,
        }
        return node;
    }

查询红点

    /**
     * 查询是否为红点
     * @param args
     * @returns
     */
    public IsRedDot(args: any[]): boolean {
        if (!args || !args.length) return false;
        
        if (!this.redDotRoot) this.redDotRoot = this.createNode(this.redDotType);

        return this.queryNode(this.redDotRoot, args, 0) > 0;
    }

    // -1	没有该结点
    // 0	有该结点, 不是红点
    // 1	是红点
    private queryNode(node: any, args: any[], index: number): number {
        let nextNode = node.left;
        while (nextNode) {
            if (nextNode.type == args[index]) {
                if (index + 1 == args.length) {	// 查询最后一个
                    return nextNode.left != null ? 1 : 0;
                } else {
                    return this.queryNode(nextNode, args, index + 1);
                }
            }
            nextNode = nextNode.right;
        }

        return -1;
    }

添加红点

    /**
     * 添加红点信息
     * @param args 红点路径, 示例:[活动, 活动兑换, 彩灯, 具体兑换任务]
     * @param isCheck 增加红点前是否检查重复添加, 有些地方代码可能会Add多次. 建议在逻辑清晰的前提下, 设为false
     */
    public AddRedDot(args: any[], isCheck: boolean = false): void {
        if (!args || !args.length) return;

        if (!this.redDotRoot) this.redDotRoot = this.createNode(this.redDotType);

        // 判断是否重复添加
        if (isCheck && this.queryNode(this.redDotRoot, args, 0) >= 0) {
            return;		// 已有该结点不需要重复添加
        }

        this.addNode(this.redDotRoot, args, 0);
    }

    private addNode(node: any, args: any[], index: number): void {
        if (index + 1 == args.length) {
            // 最后一个无需在遍历
            let newNode = this.createNode(args[index], null, node.left);
            node.left = newNode;
            return;
        }

        let prevNode = node;
        let nextNode = node.left;
        while (nextNode) {
            if (nextNode.type == args[index]) {
                if (prevNode !== node) { // 使当前查询路径在第一个(小优化)
                    prevNode.right = nextNode.right;
                    nextNode.right = node.left;
                    node.left = nextNode;
                }

                this.addNode(nextNode, args, index + 1);
                return;
            }
            nextNode = nextNode.right;
        }

        nextNode = this.createNode(args[index], null, node.left);
        node.left = nextNode;
        this.addNode(nextNode, args, index + 1);
    }

删除红点

    /**
     * 删除红点信息
     * @param args 同上, 删除树中最后一个arg
     */
    public RemoveRedDot(args: any[]): void {
        if (!args) return;

        if (!this.redDotRoot) this.redDotRoot = this.createNode(this.redDotType);

        let tree = this.removeNode(this.redDotRoot, args, 0);
        // let tree = this.removeNode1(null, this.redDotRoot, args, 0, args.length);
        this.clearTree(tree);			// 清理需要删除的红点树的所有引用
    }

    private removeNode(node: any, args: any[], index: number): any {
        let prevNode = node;
        let nextNode = node.left;
        while (nextNode) {
            if (nextNode.type == args[index]) {
                if (prevNode !== node) { // 使当前查询路径在第一个(小优化)
                    prevNode.right = nextNode.right;
                    nextNode.right = node.left;
                    node.left = nextNode;
                }

                if (index + 1 == args.length) { // 查找结束
                    return nextNode;
                } else {
                    let ret = this.removeNode(nextNode, args, index + 1);
                    if (ret === null) return null;
                    if (nextNode.left === ret) {
                        if (ret.right === null) {
                            ret = nextNode;
                        } else {
                            nextNode.left = ret.right;
                            ret.right = null;
                        }
                    }
                    return ret;
                }
            }
            prevNode = nextNode;
            nextNode = nextNode.right;
        }
        return null;
    }

清理树结构

    /**清理树结构 */
    public Clear(): void {
        this.clearTree(this.redDotRoot);
        this.redDotRoot = null;
    }

    private clearTree(node: any): void {
        if (!node) return;
        this.clearTree(node.left);
        this.clearTree(node.right);
        node.left = null;
        node.right = null;
    }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值