sgi-stl3.0 - 手搓二叉搜索树

从STL源码到二叉搜索树实践:内存管理与迭代器设计 二叉搜索树(BST)作为基础数据结构,通过节点间的有序关系实现高效查找。其核心原理是通过左子树小于父节点、右子树大于父节点的规则维护数据有序性,平均时间复杂度可达O(log n)。在工程实践中,STL标准库的红黑树实现展现了内存管理、迭代器设计等关键技术价值。通过分离分配器(allocator)与构造操作,STL实现了内存策略的可插拔;双向迭代器设计则使容器能无缝对接泛型算法。这些技术在数据库索引、文件系统等需要高效查询的场景中广泛应用。本文以STL源码为蓝本,剖析如何实现支持模板编程、具备STL风格接口的 阅读详情

文章目录

前言

一、什么是二叉搜索树

二、结构

三、实现代码

拷贝构造函数

赋值运算符重载

析构函数

插入

中序遍历

 查找

删除

总结


前言

路漫漫其求远兮,吾将上下而求索;


一、什么是二叉搜索树

二叉搜索树(Binary Search Tree,BST),又称二叉排序树,是一种特殊的二叉树结构,它满足以下性质之一:

  1. 是一棵空树;

  2. 或满足以下所有条件:

    • 若左子树非空,则左子树上所有结点的值均小于或等于根结点的值;

    • 若右子树非空,则右子树上所有结点的值均大于或等于根结点的值;

    • 左子树和右子树也分别是二叉搜索树。

需要注意的是,根据实现需求,二叉搜索树可分为 不允许重复值(无冗余) 和 允许重复值(有冗余) 两种设计;

这种结构支持高效的查找、插入和删除操作,平均时间复杂度为 O(log n),但在最坏情况下(如退化为链表)可能降至 O(n)。所以综合而言,二叉搜索树的查找、插入、删除的效率为O(N),如果想要维持其O(logN)的效率,需要对其平衡进行控制,也就是AVL树、红黑树;

二、结构

定义搜索二叉树的节点结构:

    //定义节点
    template<class K>
    struct BSTNode
    {
        K _key;
        BSTNode<K>* _left;
        BSTNode<K>* _right; 

        BSTNode(const K& key):_key(key),_left(nullptr),_right(nullptr){}
    };

搜索二叉树的整体结构:

    template<class K>
    class BSTree
    {
        typedef BSTNode<K> Node;
    public:
        BSTree():_root(nullptr){}

        //拷贝构造,需要遍历+构造节点
        BSTree(const Node& t){}

        //赋值运算符重载 --》 利用拷贝构造的现代写法
        Node& operator=(Node t){}

        //析构函数 --》后序遍历释放节点
        ~BSTree(){}

        //插入
        bool Insert(const K& key){}
        //中序遍历
        void Inorder(){}
        //查找
        bool Find(const K& key){}
        //删除
        bool Erase(const K& key){}
    private:
        Node* _root;
    };

三、实现代码

拷贝构造函数

需要递归地遍历该二叉搜索树当中的节点,创建节点并处理连接关系;

参考代码如下:

        //拷贝构造,需要遍历+构造节点
        BSTree(const Node& t)
        {
            _root = copy(t._root);
        }

        Node* copy(Node* root)
        {
            //前序遍历构造一棵树
            if(root==nullptr) return nullptr;
            Node* newRoot = new Node(root->_key);
            newRoot->left = copy(root->_left);
            newRoot->right = copy(root->_right);

            return newRoot;
        }

赋值运算符重载

此处实现巧妙利用拷贝构造函数(传值传参会进行拷贝,那么我们在赋值运算符重载中利用swap 交换this 与 传值传参的局部对象即可实现)

参考代码如下:

        //赋值运算符重载 --》 利用拷贝构造的现代写法
        Node& operator=(Node t)
        {
            std::swap(_root , t._root);
            return *this;
        }

析构函数

析构的实现需要后序遍历这颗二叉搜索树,释放节点

参考代码如下:

        //析构函数 --》后序遍历释放节点
        ~BSTree()
        {
            Destory(_root);
            _root = nullptr;
        }
        void Destory(Node* root)
        {
            if(root==nullptr) return;
            Destory(root->_left);
            Destory(root->_right);
            delete root;
        }

插入

过程:

  • 如果根节点为空,直接创建一个节点然后插入
  • 如果根节点不为空,需要找到插入值key 合适的位置进行插入:当key 小于当前节点cur中存储的值,那么cur = cur->_left , 如果key 大于当前节点cur 当中存储的值,那么cur = cur->_right;至于key等于当前节点cur 中存储值的情况,需要结合实际情况(是否支持冗余)来决定,此处实现为不冗余;

参考代码如下:

        //插入数据,不允许插入冗余的数据
        bool Insert(const K& key)
        {   
            //空树的话,直接创建节点
            if(_root==nullptr)
            {
                _root = new Node(key);
                return true;
            }
            //找到合适的位置,利用前后指针
            Node* cur = _root, *prev = nullptr;
            while(cur)
            {
                if(key < cur->_key)
                {
                    prev = cur;
                    cur = cur->_left;
                }
                else if(key > cur->_key)
                {
                    prev = cur;
                    cur = cur->_right;
                }
                else{
                    //数据已经存在
                    return false;
                }
            }

            //找到了合适的位置,需要创建节点并处理链接关系
            cur = new Node(key);
            //判断这个节点需要放在prev 的左边还是右边
            if(key < prev->_key)
            {
                prev->_left = cur;
            }
            else{
                prev->_right = cur;
            }
            return true;
        }

中序遍历

二叉搜索树中序遍历的结果是有序的,我们实现的Inorder 需要传参,而在外部由于访问限定符的限制不易于外部调用传参,所以我们可以考虑在内部封装一层,即: void _Inorder(Node* root)

参考代码如下:

        //中序遍历
        void Inorder()
        {
            _Inorder(_root);
            std::cout << std::endl;
        }
        void _Inorder(Node* root)
        {
            if(root == nullptr) return;
            _Inorder(root->_left);
            std::cout << root->_key << " ";
            _Inorder(root->_right);
        }

 查找

查找的逻辑与插入数据的逻辑较为相似,比对当前节点cur 当中存储的值与 key 的大小关系,然后决定当前节点 cur 应该往左还是往右走;

参考代码如下:

        //查找数据
        bool Find(const K& key)
        {
            Node* cur = _root;
            while(cur)
            {
                if(key < cur->_key)
                {
                    cur = cur->_left;
                }
                else if(key > cur->_key)
                {
                    cur = cur->_right;
                }
                else{
                    return true;
                }
            }
            return false;
        }

删除

删除=查找存储值为key 的节点+处理删除之后的链接关系

需要分情况讨论:

  • 所删除的节点没有孩子节点 --》直接删除、处理其父节点的指针指向
  • 所删除的节点只有左孩子,需要其父节点”接管“该所删除节点的左孩子;
  • 所删除的节点只有右孩子,需要其父节点”接管“所删除节点的右孩子;
  • 所删除的节点既有左孩子又有右孩子,此时需要使用交换删除法,即在其左子树中找到最大的节点(或者是右子树中最小的节点)与所删除的节点进行交换,然后再删除;

需要注意的是,在实现删除逻辑的时候,需要判断所删除节点是否为根节点(如果为根节点,需要处理成员变量 _root)

参考代码如下:

        //删除一个节点 --》 需要判断当前这个节点是否存在孩子节点,需要对孩子节点的个数情况进行判断
        bool Erase(const K& key)
        {
            //查找 + 判断子节点的情况
            Node* cur = _root, * prev = nullptr;
            while(cur)
            {
                if(key < cur->_key)
                {
                    prev = cur;
                    cur = cur->_left;
                }
                else if(key > cur->_key)
                {
                    prev = cur;
                    cur = cur->_right;
                }
                else{
                    //找到了节点,判断这个节点是否存在子节点;当然,找到的节点也有可能为根节点,那么prev 为 nullptr
                    if(cur->_left == nullptr)
                    {
                        if(prev == nullptr)
                        {
                            _root = cur->_right;
                        }
                        else
                        {
                            //不存在左孩子,可能存在右孩子,判断cur 当前在 prev 的左边还是右边,然后将cur 的右孩子给给prev
                            if(cur == prev->_left)
                            {
                                prev->_left = cur->_right;
                            }else{
                                prev->_right = cur->_right;
                            }
                        }
                        delete cur;
                    }
                    else if(cur->_right == nullptr)
                    {
                        if(prev==nullptr)
                        {
                            _root = cur->_left;
                        }
                        else
                        {
                            if(cur == prev->_left)
                            {
                                prev->_left = cur->_left;
                            }else{
                                prev->_right = cur->_left;
                            }
                        }
                        delete cur;
                    }
                    else
                    {
                        //存在两个孩子,交换+删除的思想,需要找到cur 左子树当中的最大节点或者右子树当中的最小节点
                        Node* replaceParent = cur, *replace = cur;
                        while(replace->_left)//此处实现为找到右子树当中的最小节点,即最左节点
                        {
                            replaceParent = replace;
                            replace = replace->_left;
                        }
                        std::swap(cur->_key , replace->_key);
                        //处理连接关系,当前的replace 可能存在右孩子
                        if(replace == replaceParent->_left)
                        {
                            replaceParent->_left = replace->_right;
                        }
                        else
                        {
                            replaceParent->_right = replace ->_left;
                        }
                        delete replace;
                    }
                    return true;
                }
            }
            return false;
        }

总结

动手写一写吧~

《STL源码剖析》之RB-tree AVL树之外,另一个被广泛运用的平衡二叉搜索树是RB-tree。所谓红黑树,不仅是一个二叉搜索树,它还满足以下性质: 性质1. 每个节点是红色或黑色; 性质2. 根是黑色; 性质3. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点) 性质4. 从任一节点到NULL(树尾端)的任何路径都包含相同数目的黑色节点。 阅读详情

相关推荐

读书笔记 - STL源码剖析

前面有几篇文章的图片是用截图复制,粘贴过来的,结果发布直接没了。。好坑。 第一章 STL概论与版本简介 STL 六大组件 1:容器(vector,map,etc)STL容器是一种class template 2:算法:sort,search,srase。STL算法是一种function template 3:迭代器:扮演容器和算法的胶合剂。是一种class template 4

baidu_34674626的博客 1285

sgi-stl3.0 - 手搓平衡二叉搜索树(AVL)

AVL树是一种自平衡二叉搜索树,通过平衡因子(右子树高度-左子树高度)确保树的高度差不超过1,从而维持O(logn)的查找效率。文章详细介绍了AVL树的结构实现,包括节点定义、旋转操作(左旋、右旋、左右双旋、右左双旋)以及插入时的平衡因子调整。测试部分验证了树的平衡性,确保所有节点的平衡因子与计算值一致。AVL树通过动态调整保持平衡,有效避免了二叉搜索树退化为链表的情况。

Distinguished_z的博客 1252

使用vite+react+ts+Ant Design开发后台管理项目(四)

本文将引导开发者从零基础开始,运用、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈,构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导,文章旨在为开发者揭示如何利用这些技术工具,从项目构思到最终实现的全过程,提供清晰的开发思路和实用的技术应用技巧。使用vite+react+ts+Ant Design开发后台管理项目(一)使用vite+react+ts+Ant Design开发后台管理项目(二)

lbking666666的专栏 2006

C++二叉搜索树实现与STL源码解析

二叉搜索树(BST)是计算机科学中基础且重要的数据结构,通过左小右大的节点排列规则实现O(log n)级别的查找效率。其核心原理在于利用二叉树结构维护数据有序性,广泛应用于数据库索引、编译器符号表等场景。本文以C++ STL源码分析为切入点,深入解析BST的工程实现技巧,包括迭代器设计、内存管理优化等关键点,并对比SGI STL 3.0的红黑树实现差异。通过手写BST实现,开发者能更好理解STL关联式容器(如map/set)的底层机制,为学习更复杂的平衡二叉树打下坚实基础。

weixin_33326218的博客 210

OpenCV实战:如何用Debevec算法搞定相机响应函数(附完整代码)

本文详细介绍了如何使用OpenCV实现Debevec算法计算相机响应函数(CRF),并应用于HDR图像合成。通过完整的代码示例和工程实践问题解决方案,帮助开发者掌握从原理到实现的关键步骤,提升高动态范围成像和计算机视觉任务的处理能力。

weixin_29061041的博客 229

PHP+MYSQL宠物主题动态网页设计源码+数据库,大学生期末大作业,PHP课程设计

PHP+MYSQL宠物主题动态网页设计源码+数据库,大学生期末大作业,PHP课程设计提示:本文采用PHP对数据库进行操作:本文就介绍了PHP实现对MySQL数据库的增删改查操作基础内容。

900

深入解析AVL树实现与SGI STL优化技巧

平衡二叉搜索树(AVL树)是计算机科学中保证高效查找的关键数据结构,通过严格的平衡因子控制(左右子树高度差≤1)确保操作时间复杂度稳定在O(log n)。其核心原理涉及四种旋转操作(LL/RR/LR/RL)来动态维持平衡,这种特性使其在高性能计算、数据库索引等场景具有不可替代的价值。以SGI STL 3.0的实现为例,通过二级内存分配策略和特殊迭代器设计,AVL树的插入操作可获得15%-20%的性能提升。工程实践中,递归与非递归实现的取舍、缓存友好性优化以及内存泄漏防范都是开发者需要重点关注的领域。

weixin_42561476的博客 216

YOLO11的持续学习:如何在不遗忘旧数据的情况下学习新类别

类增量学习(Class-Incremental Learning, CIL)是持续学习(Continual Learning)的一个重要分支,它指的是模型在不遗忘已学旧类别知识的前提下,逐步学习新类别的能力。与传统机器学习假设所有数据一次可用不同,类增量学习更贴近现实世界应用场景——新的类别数据往往会随着时间推移逐步出现。 举个例子,假设我们已经训练好一个YOLOv11模型用于检测"猫"和"狗"两种动物,现在需要让模型新增识别"兔子"的能力。传统方法需要收集所有类别(猫、狗、兔子)的数据重新训练,而类增量

本博客聚焦 YOLOv11 全流程落地,涵盖架构优化、数据集处理、训练技巧与多场景部署,兼及国产数据库、Java 开发与 AI 模型应用,内容兼顾理论与工程实践,为开发者提供系统干货,助力高效提升技术能力。 1966

从SGI-STL源码解析二叉搜索树实现与优化

二叉搜索树作为基础数据结构,通过节点间的有序关系实现高效查找,其时间复杂度为O(log n)。STL中的关联容器如map和set底层采用红黑树实现,这是一种自平衡二叉搜索树,通过颜色标记和旋转操作维持平衡。在实际工程中,二叉搜索树的性能优化涉及内存管理、缓存命中及迭代器设计等多个方面。SGI-STL源码中的实现展示了工业级代码对内存局部性和类型安全的考量,例如使用专用节点分配器和类型萃取技术。理解这些底层机制不仅能提升数据结构认知,还能帮助开发者编写更高效的C++代码,特别是在需要频繁插入删除的场景下。

weixin_33391446的博客 239

目标跟踪与视频时序分析基础

两帧均有目标,却因快速移动导致检测框无重叠,仅靠交并比(IoU)无法维持身份关联。本文通过手算与纯Python实现最小跟踪流程,揭示IoU仅为位置线索,不能应对快速位移或遮挡。实验表明,即使目标真实存在,低重叠也会触发新编号。强调跟踪需结合运动预测、外观特征与阈值验证,避免误判。

Mr数据杨 2335

TMF8801 ToF激光测距传感器原理图设计,已量产(距离传感器)

这张 TMF8801 小板的外围结构就很有代表性。核心传感器是 U1 TMF8801,但真正构成量产价值的是外围那一圈:U2 把 VCC 整理成 3V,R1/R2/R5 与 R3/R4/R6 两组 10K 电阻稳定默认态,Q2 2N7002 和 U3 SN74LVC2G07DCKR 处理控制链路,传感器边上还有 C1/C4/C5 三颗 100nF 紧贴去耦。

不脱发的程序猿 159

SGISTL源码探究-STL中的红黑树(上)

前言本小节将进入到SGISTL的红黑树部分。关于红黑树,是一种比较复杂的数据结构,但是并不是特别难。如果对红黑树不太了解,可以去网上查阅相关的资料,因为本文的主要目的是分析STL中的红黑树的源码,和普通的红黑树略有不同,还要复杂一些,需要有一定的基础。基本概念首先什么是二叉搜索树,二叉搜索树即符合任何一个节点的值一定大于其左子树的任何一个节点的值并且小于其右子树的任何一个节点的值(节点的值不允许重复

Move_now的博客 1806

数据分析案例-车辆二氧化碳排放量数据可视化分析

本实验数据集来源于Kaggle,该数据集捕获了车辆二氧化碳排放量随不同特征变化的详细信息。数据集取自加拿大政府官方开放数据网站。其中包含 7 年期间的数据。总共有 7385 行和 12 列。各列变量含义解释如下:Make:车辆的品牌或制造商。Model:车辆的具体车型名称。Vehicle Class:车辆的分类,如紧凑型、SUV等。Engine Size(L):车辆发动机的尺寸,以升为单位。Cylinders:车辆发动机的气缸数。

m0_64336780的博客 1万+

SGI STL的rb_tree浅析

rb_tree是一种特殊的二叉搜索树,但是其对平衡的要求比avl_tree低,avl_tree要求左右子树的高度差不能大于1,而rb_tree只要求从一个节点至树的尾端的任何路径的黑节点的个数相等rb_tree必须满足的规则: 1.每个节点不是黑色就是红色; 2.根节点必须为黑色; 3.若节点为红色,则其子节点必须为黑色(红不连); 4.任意节点至树尾端的任何路径的黑色节点的个

github_33736971的博客 1075

5、数据库基础概念与数据建模全解析

本文深入解析了数据库的基础概念,包括函数依赖、决定因素和多值依赖等关键依赖关系,同时探讨了数据建模的重要方法论,如IDEF1X、信息工程和陈方法。此外,还介绍了SQL Server管理工作室的图表功能,帮助用户进行数据库的可视化设计。通过本文,读者将掌握数据库设计的核心知识,为构建高效、可扩展的数据库系统奠定基础。

81

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

STL源码剖析-RBTree

关联式容器 根据“数据在容器中的排列”特性,容器可分为序列式和关联式容器两种。标准的STL关联式容器可分为set(集合)和map(映射表)。这些容器的底层机制均以RB-tree完成,RB-tree也是一个独立容器,但并不对外开放。 此外,SGI STL还提供了一个不在标准规格之列的关联式容器:hash table(散列表)以及hash table为底层机制完成的hash_set(散列集合)、has...

weixin_37549298的博客 389

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

深入解析AVL树:从STL源码到工业级实现

平衡二叉搜索树是计算机科学中保证高效查找的关键数据结构,通过旋转操作维持严格的平衡条件,确保最坏情况下仍保持O(log n)的时间复杂度。AVL树作为最早发明的自平衡二叉搜索树,其核心在于平衡因子的动态维护和四种基本旋转操作。在工程实践中,AVL树被广泛应用于需要稳定查询性能的场景,如数据库索引和内存缓存系统。SGI STL 3.0对AVL树的实现展示了工业级代码的优化技巧,包括内存池预分配和迭代器优化等。通过分析STL源码中的节点设计和旋转算法,可以掌握构建高性能平衡树的关键技术。

weixin_42524276的博客 262

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

C++STL之map和set的使用

map和set 文章目录map和setsetset的使用set的插入set的遍历set的find接口set的erase接口map的介绍键值对mapmap的使用map的模板参数map的插入简单英文翻译字典统计字符串个数operator[]的使用erase的使用map和multimap的对比在OJ中的使用前k个高频单词题目描述错误代码写法正确代码写法 set set的使用 set的插入 #include<iostream> #include<set> using namespace s

小赵小赵福星高照的博客 1496

一篇足矣,带你吃透STL源码中hash table(哈希表)与关联式容器hash_set、hash_map

前面介绍的二叉搜索树和平衡二叉搜索树。二叉搜索树具有对数平均时间的表现,但这样的表现构造在一个假设上:输入数据有足够的随机性 文本要介绍一种名为hash table(哈希表/散列表)的数据结构,这种结构在插入、删除、搜索等操作上也具有“常数平均时间”的表现,而且这种表现是以统计为基础,不需依赖输入元素的随机性 哈希表可以在本人的数据结构文章中查看,文本就不再详细介绍了:https://blog...

董哥的黑板报 3499

【STL源码剖析】第五章 关联式容器 之 hashtable底层实现

hashtable二叉搜索树具有对视平均时间的表现,但这种的表现构造在一个假设上:输入数据有足够的随机性。这一节介绍一种名为hastable(散列表)的数据结构,这种结构在插入、删除、搜寻等操作上也具有“常数平均时间”的表现,而这种表现是以统计为基础的,不需仰赖输入元素的随机性。hashtable概述hashtable通过hash function将元素映射到不同的位置,但当不同的元素通过hash...

stt2019 644

STL源代码剖析 容器 stl_hashtable.h

本文为senlie原创。转载请保留此地址:http://blog.csdn.net/zhengsenlie hashtable --------------------------------------------------------------------------- 二叉搜索树具有对数平均时间的表现,它建立在输入数据有足够的随机性的如果 hashtabl...

weixin_30326741的博客 190

STL算法总体概览

一、什么是算法 算法,问题之解法也 广义而言,写的每个程序都是一个算法,其中的每个函数也都是一个算法 下面的一些文章我们将探讨极具复用价值的70余个STL算法,包括排序(sorting)、查找(searching)、排列组合(permutation)、以及用于数据移动、赋值、删除、比较、组合、运算等的算法 特定的算法往往搭配特定的数据结构,例如二叉搜索树(binary search tre...

董哥的黑板报 1356

STL源码剖析 容器 stl_hashtable.h

hashtable --------------------------------------------------------------------------- 二叉搜索树具有对数平均时间的表现,它建立在输入数据有足够的随机性的假设 hashtable 有常数平均时间的表现,基于统计,不需依赖输入元素的随机性 hashtalbe 的简单实现: 所有元素都 16-bits 不带正负号的整数,范围 0~65535,配置一个 array,索引号码为 0~65535,初值全部为 0 。 每一个元素

1402

STL关联容器概述

1. 概念 STL容器大的方向分为两类,序列式容器和关联式容器,这两者通过数据在容器内的排列来区分,关联容器是通过键(key)存储和读取元素的,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。标准的STL序列容器包括:vector、list、deque、heap(算法呈现)

yfk的专栏 7635

C++初阶(07):STL简介

STL(标准模板库)是C++的核心组件,包含容器、算法、迭代器等六大模块。常见容器包括vector(动态数组)、list(链表)和map(红黑树实现)。算法如排序、查找等通过迭代器与容器交互。智能指针(如shared_ptr)管理内存,避免泄漏。STL在面试中重点考查:vector扩容机制、map与哈希表区别、智能指针原理等。学习需从使用到理解底层实现(如空间配置器)。

2401_86650143的博客 840

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 210
上一篇: 网络缓冲区 · 通过读写偏移量维护数据区间的高效“零拷贝” Buffer 设计
下一篇: sgi-stl3.0 - 手搓平衡二叉搜索树(AVL)
秦少游在淮海
博客等级 码龄3年 1071粉丝 88原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值