数据结构Map&Set的总结

C++的STL 中 set.map multiset.multimap 学习使用详细讲解(含配套OJ题练习使用详细解答) 阅读详情

Map & Set

在这里插入图片描述
​

​#搜索树#​

概念

二叉搜索树/二叉排序树,满足以下性质

  • 若左树不为空,则左树上所有节点的值都小于父节点的值
  • 若右树不为空,则右树上所有节点的值都大于父节点的值
  • 它的左右子树也满足以上性质

在这里插入图片描述
​

二叉搜索树的中序遍历是有序的:{0,1,2,3,4,5,6,7,8,9}


搜索树操作

插入Insert​

搜索树的插入也要满足本身性质,若插入元素在原本的搜索树中已经拥有,则插入失败

思路:定义Cur走到null位置,同时Parent做Cur的根节点,记录Cur之前走过的位置,避免cur定位丢失

public boolean insert(int key) {
        if (root == null) {
            root = new TreeNode(key);
            return true;
        }
        TreeNode cur = root;
        TreeNode parent = null;
        while (cur != null) {
            if (cur.val < key) {
                parent = cur;
                cur = cur.right;
            }else if (cur.val > key){
                parent = cur;
                cur = cur.left;
            }else {
                return false;
            }
        }
        TreeNode newNode = new TreeNode(key);
        if (parent.val > key) {
            parent.left = newNode;
        }else {
            parent.right = newNode;
        }
        return true;
    }

查找Remove​

定义Cur遍历搜索树,在对比左右子树.val 与Key的大小关系时,注意Cur的遍历方向

public TreeNode searchTree (int key) {
        if (root == null) {
            return null;
        }
        TreeNode cur = root;
        while (cur != null) {
            if (cur.val < key) {
                cur = cur.right;
            }else if (cur.val > key){
                cur = cur.left;
            }else {
                return cur;
            }
        }
        return null;
    }

删除

删除节点时,要注意不要破坏二叉搜索树的性质

思路:定义Cur并定位到待删除节点,待删除节点的父节点为Parent,找到Cur后分三种情况

在这里插入图片描述
​

  1. cur.left == null 三种情况

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ​

  2. cur.right == null 三种情况

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    ​

  3. cur两边都不为空的情况

    此时需要替换法进行删除,找到右子树中的最小节点(即最左节点),用它的值来填补到被删除节点中,覆盖Cur节点,再处理节点的指向问题

    在这里插入图片描述
    141411-2z160yv.png&pos_id=img-FIJuwRJm-1748409659958)​

    Q&A

    •  为什么不直取一层左子节点?—— 用if仅检查一层,是无法找到真正的最小节点

主框架:删除的准备工作

public void remove(int key) {
        if (root == null) {
            System.out.println("树为空");
            return;
        }
        TreeNode parent = null;
        TreeNode cur = root;
        while (cur != null) {
            if (cur.val < key) {
                parent = cur;
                cur = cur.right;
            }else if (cur.val > key){
                parent = cur;
                cur = cur.left;
            }else {
                removeNode(parent,cur);
                return;
            }
        }
    }

删除的实际操作在removeNode​方法中

private void removeNode(TreeNode parent, TreeNode cur) {
        if (cur.left == null) {
            if (cur == root) {
                root = root.right;
            }else if (cur == parent.left) {
                parent.left = cur.right;
            }else {
                parent.right = cur.right;
            }
        }else if (cur.right == null){
            if (cur == root) {
                root = root.left;
            } else if (cur == parent.left) {
                parent.left = cur.left;
            }else {
                parent.right = cur.left;
            }
        }else {
            TreeNode targetParent = cur;
            TreeNode target = targetParent.right;
            //找到右树中最左边的节点
            while (target.left != null) {
                targetParent = target;
                target = target.left;
            }
            cur.val = target.val;

            if (target == targetParent.left) {
                targetParent.left = target.right;
            }else {
                targetParent.right = target.right;
            }
        }
    }

搜索

Map和Set是专门搜索的数据结构,但他们的搜索效率与其他们具体实例化的子类有关——两者都是接口

在这里插入图片描述
​

以前的搜索方式有遍历搜索,二分查找,但都是适用于静态查找。当涉及到插删查改的操作时,我们需要效率更高的查找方式,即动态查找,此时引出查找工具——Map和Set——适合动态查找的集合容器

模型

我们一般把要搜索的数据叫做关键字,而关键字中可能或带有对应的“值”,我们叫键值对Key-Value

比如一个数组{1,2,3,4,4,4},我们要寻找每一个数字出现的次数,此时寻找的数字是关键字,而它们出现的次数则称之为对应的“值” 如数字4出现了3次,则键值对是<4 , 3>或<3 , 4>

  1. 纯Key模型
  2. Key-Value模型

Set中只存储Key模型,而Map存储Key-Value模型


Map

Map是一个接口,存储的是<Key , Value>键值对,并且k是唯一的

实例化对象需要实现类#TreeMap#​或#HashMap#​,还有个#LinkedHashMap#​,基于HashMap维护了一个双向链表记录来记录元素的插入次序

在这里插入图片描述

​

TreeMap和HashMap的区别

在这里插入图片描述
​

  • TreeMap的Key不能传null

常用方法

  • V put——存放键值

  • V get——返回key对应的value

  • V getOrDefault——返回key对应的value,如果key不存在,则建立新的key并返回新默认的value

  • V remove——移除的key

  • Set<> keySet(需要Set<>来接收)——返回所有不重复的key值的集合

  • Collection<> values(需要Collection<>来接收)——返回所有不重复的value的集合

  • ✨Set<Map.entry<K , V>> entrySet(需要Set<Map.entry<K , V>>接收)——返回所有的Key-Value的映射关系的集合

    关于Map.entry<K , V>

    entry可以看成是一个节点,相当于二叉树的Node节点,将键值打包成entry节点放入Set里面,同时它自身也实现了getValue和getKey方法

    ​ Set<Map.Entry<Object, Integer>> set = map.entrySet(); for (Map.Entry<Object, Integer> entry: set) { System.out.println("key: "+entry.getKey()+" -> val: "+entry.getValue()); }​

    若直接打印set则是各个Key-Value的集合

  • boolean containsKey

  • boolean containsValue

在这里插入图片描述
​

总结

  1. Map是一个接口,不能直接实例化对象,如果要实例化对象需要实现类TreeMap或HashMap

  2. Map中的Key / Value都可以被全部分离出来存到Set / Collection当中,Key是唯一的,Value可以重复

  3. Map中的Key不能被修改,Value可以被修改,如果要修改Key只能先删除再建立新的Key

  4. TreeMap的Key不能传null,HashMap可以——TreeMap的remove就不能传null,HashMap可以

  5. ✨Map中传的Key一定要可以比较——搜索树本质上来说每插入一个元素都要进行大小比较

    解决办法:

    1. 给自定义类实现Comparable接口——(TreeMap)
    2. 构造TreeMap时传比较器,注意HashMap不能传比较器——(TreeMap)
    3. 重写equals和hashCode方法——(HashMap)

Set

Set也是一个接口,他没有具体的对象,继承自Collection接口类,只能存储Key模型,而且Key也是唯一的,可以把它看成一个塑料袋(集合),里面装着杂乱无序的不重复的数据。

在这里插入图片描述
在这里插入图片描述
​

实现Set接口要实现类#TreeSet#​和#HashSet#​,还有个#LinkedHashSet#​,是在HashSet的基础上维护了一个双向链表来记录元素的插入次序

TreeSet和HashSet区别

在这里插入图片描述
​

  • TreeSet插入的Key不能是null——会空指针异常,但HashSet可以

常见方法

  1. boolean add——添加数据,但重复元素不会被添加成功

  2. boolean remove——删除集合中的所选数据

  3. void clear——清空集合

  4. boolean contains

  5. Iterator iterator——返回迭代器

    注意Map没有继承迭代器接口,如果需要迭代器遍历,需要强转为Set/List/Queue接口

在这里插入图片描述
​

总结

  1. Set只能存储K,且K也是和Map一样唯一的

  2. 💫TreeSet的底层是用Map实现的,其使用的Key与Object的一个默认的对象(Value)组成键值插入到Map中

  3. TreeSet插入的Key不能是null,但HashSet可以——故TreeSet的remove不能传null,HashSet可以传null

  4. Set最大的功能是对Key去重——TreeSet是天然去重的

  5. Set中的Key也是像Map一样不能修改的,如需修改要删除

  6. ✨Set中的Key也是一定要可比较——原理同Map

    解决方法:

    1. 给自定义类实现Comparable接口——(TreeSet)
    2. 构造TreeSet传入比较器,同理HashSet不能传比较器——(TreeSet)
    3. 重写equals和hashCode方法——(HashSet)

Map和Set的关系

  • TreeSet的底层是用Map实现的,其使用的Key与Object的一个默认的对象(Value)组成键值插入到Map中
  • TreeMap和TreeSet的复杂度都是log2N,它们的 K 都是要能比较大小的。
  • HashMap和HashSet的复杂度都是O(1),
  • 两者都是集合类型,且底层通常基于哈希表或红黑树来实现,两者的数据结构存在差异:Set主要关注元素的唯一性,但Map更关注键值对的关系

‍

前面提到了HashMap,HashSet,LinkedHashMap,LinkedHashSet,那Hash到底是什么呢?为什么他们的效率这么高?这就引入哈希表的概念

哈希表

概念

理想的搜索方法:不经过任何的比较,一次直接从表中得到想要的元素。如果构造一种存储结构,能够通过某种函数使得元素与它的关键字/码之间建立某种联系,那么在查找的时候就很容易得到这些元素

该方式就叫哈希方法,哈希方法中使用的函数就叫做哈希函数,构造出来的结构就为==哈希表==

‍

每一种数据结构它的哈希函数都不一致,但是哈希表本质上是一个数组,不过数组不是放的单一数据,而是存放的键值对,所以哈希表是数组的一种拓展,这是哈希表的表现形式

在这里插入图片描述
​

我们将学生信息包括名字和岁数(Key—Value),我们先通过哈希函数让Key进行计算,得出Index,确定键值对entry存放的位置,但是有一个问题,如果数据多了,别的key通过哈希函数可能也会得到相同的下标Index,像这样具有不同关键码但具有相同哈希地址的数据元素称为“同义词”,这个问题我们称之哈希冲突


哈希冲突

那么有哈希冲突就会有解决哈希冲突问题的办法

‍

哈希冲突是必然的,我们做的应该是降低冲突率,引起冲突的一个原因可能是哈希函数设计不合理,但是我们一般都不会涉及到设计哈希函数,但常用的哈希函数我们需要了解​

哈希函数设计的越精妙,产生哈希冲突的可能性就越低,但是无法避免哈希冲突

那反应哈希冲突率的一个数据叫负载因子


负载因子

哈希列表的负载因子定义为 α = 填入表中的元素 / 哈希表的长度

​
在这里插入图片描述
​

避免哈希冲突

两个方法 : 优化哈希函数、降低负载因子✨

  • 💯降低负载因子即需要对数组进行扩容,扩容之后需要对原来的数组的元素进行重新哈希分配——即重新哈希

    public void resize() {
    	Node[] newArray = new Node[array.length * 2];
    	for(int i = 0; i < array.length; i++) {
    		Node cur = array[i];
    		while(cur != null) {
    			int newIndex = cur.key%newArray.length;
    			Node curN = cur.next;
    			cur.next = newArray[newindex];
    			newArray[newindex] = cur;
    			cur = curN;
    		}
    	}
    	array = newArray;
    }

解决哈希冲突

两种常见方法:#闭散列#​和#开散列#​

闭散列

也叫开放地址法,当发生哈希冲突时, 如果哈希表没有被装满,说明哈希表还有位置可以放,那么就可以把Key放到空的位置上

  • 线性探测:从发生冲突的位置开始找到空位置放
  • 二次探测:优化了线性探测的问题(不重点解释,需要可再查找)

💫开散列(重点)

开散列,又叫链地址法(拉链法),首先对关键码集合用哈希函数计算哈希地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

与闭散列不同,这种将链表的头地址存储在哈希表的方式,不会影响与自己哈希地址不同的元素的增删查改的效率

在这里插入图片描述
放入的entry可以用头插也可以用尾插法,与链表的操作相似,由此可见,开散列的每个桶当中都放的哈希冲突的元素,

但如果出现极端情况,即所有元素都产生了冲突,都放到了同一个桶之中,那哈希表的增删查改的效率就退化为O(N),此时我们可以把这个桶转化为红黑树 TreeMap or TreeSet,效率就为O(log2N)

在这里插入图片描述
树化条件 :链表的长度 >= 8 && 数组长度 >= 64 如果红黑树删除后不满足条件或没必要再用红黑树时可以变回为哈希桶的结构

开散列可以认为是把大集合中的搜索问题转化为了小集合中做搜索了


💫与Java类集合的关系

  1. HashMap和HashSet都是Java中利用哈希表来实现的Map和Set
  2. Java会在冲突链表长度大于一定阈值的时候,将链表树化为红黑树TreeSet or TreeMap
  3. Java是用哈希桶来解决哈希冲突的(链表)
  4. ✨Java计算的哈希值实际上是调用类的hashCode方法,进行Key的对比时是调用equals方法。所以如果要调用自定义类作为HashMap或HashSet的值,必须覆写hashCode和equals方法,而且做到equals相等的对象,其hashCode一定是相等的,反之则不一定——hashCode相等equals未必相等(哈希冲突)

‍

汇编语言(第4版)王爽 课程设计2 详细实现(一、虚拟模式DOS运行篇) 由于虚拟模式的限制,我们编写的许多逻辑暂时不能被检验,而因为《汇编语言》编写时间较早,其所依赖的运行环境如今只能够依靠虚拟机来搭建。比如实模式DOS,搭建步骤比较繁琐,因此我将其它的部分放在下一篇文章中进行讲解。事实上,我们实现的程序属于《汇编语言》课程设计2中任务程序部分,其中的完整任务还涉及到将该任务程序安装到软盘等操作,这些也都需要在实模式下才能运行,所以统一放到下一篇文章进行实现。 阅读详情

相关推荐

Splunk CVE-2018-11409认证绕过漏洞深度解析

Splunk作为主流企业级日志分析平台,其Web管理接口的认证机制直接关系到整个安全运营体系的可信边界。CVE-2018-11409本质上是REST API路由层会话校验缺失引发的未授权访问问题,根源在于`/en-US/splunkd/__raw/`路径绕过了splunkweb与splunkd之间的信任链验证,导致配置文件、用户哈希、App源码等敏感信息明文泄露。该漏洞凸显了Web接口权限模型设计失守的风险,尤其在默认配置未加固、HTTPS未启用、初始密码未修改的生产环境中危害急剧放大。结合vulfocus

weixin_30875157的博客 596

【数据结构】Map和Set

本期主要讲解: 1、Map 和 Set的概念 2、Map 和 Set 使用的模型 3、Map 3.1 Map.Entry 简介 3.2 Map的常用方法 4、Set 4.1 Set 和 Map 的区别 4.2 Set 的常用方法

拼命阿紫冲冲冲! 2195

Git下载安装及环境配置,解决安装包下载慢问题(详细版)

Git是我们平时开发都要用到的项目管理工具,虽然有网页版的Git网站,但是在本地安装Git后,可以直接使用命令语句来进行项目的上传与克隆。还是非常方便的。今天就来介绍下Git的下载。1、首先在浏览器中搜索Git,进入到Git的官方下载界面或者直接复制下面这个链接。 2、点击download进入下载界面,选择自己需要平台的文件 3、下载标准版就可以4、但是会发现下载速度很慢,就找个镜像版 5、点击 https://registry.npmmirror.com/binary.html?path=git-for-

mengxiang_的博客 6万+

Set 和 Map 的区别

Set和Map的区别

努力学习前端的小白 2万+

Python爬虫实战:5分钟搞定大众点评评论数据抓取(附完整代码)

本文详细介绍了使用Python爬虫高效获取大众点评评论数据的5个关键技巧,包括环境配置、智能页面解析、反反爬策略、数据存储与容错设计以及性能优化。通过实战案例和完整代码,帮助开发者快速掌握文本挖掘技术,适用于市场分析和商业决策。

weixin_30660027的博客 290

别再乱提MR了!手把手教你配置GitLab的CI/CD与分支保护规则,让团队协作更丝滑

本文详细介绍了如何配置GitLab的CI/CD与分支保护规则,以优化团队协作流程。通过设置Protected Branches、MR流水线检查和自动化审批规则,有效防止不规范操作和合并冲突,提升开发效率与代码质量。特别强调MR(Merge Request)的正确使用,确保团队协作更丝滑。

weixin_28840591的博客 233

【数据结构】 Map和Set详解

一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以纯 key 模型,比如:有一个英文词典,快速查找一个单词是否在词典中快速查找某个名字在不在通讯录中Key-Value 模型,比如:统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号而Map中存储的就是key-value的键值对Set中只存储了Key。

m0_71731682的博客 4171

PCB阻焊工艺全解析:从油墨选择到显影测试的完整指南

本文深入解析PCB阻焊工艺全流程,从材料科学角度对比液态光成像(LPI)油墨、干膜阻焊等核心材料特性,系统阐述前处理、涂覆、预烤曝光、显影固化等关键步骤的工艺要点与参数控制。重点探讨了如何通过优化油墨选择与工艺参数,解决常见缺陷,提升PCB的可靠性、美观度及可制造性,为工程师提供从理论到产线实战的完整指南。

s3t4u的博客 551

Map和Set

Map和Set

如风暖阳的博客 1349

图像质量评估(5) -- 畸变(Distortion)

当图像中原本应该是直线的地方看起来发生了不自然的变形或扭曲时,我们称为图像畸变。有三种类型的镜头畸变:桶形畸变(后文使用英文barrel),枕形畸变(后文使用pincushion)和胡子畸变(后文使用英文wavef或mustache,这种畸变里包含了桶形畸变和枕形畸变)。有一个重要的点需要注意,根据透镜的类型以及透镜是否能够从相机中移除等条件不同,畸变会有不同的表现。 总的来说,旋转对称光学系统功能上会产生和物体几何相似的图形。但也有少数特殊的系统是例外,例如鱼眼镜头,这种镜头几何是故意设计为

vivo01的专栏 2万+

【ComfyUI】Wan2.2 Animate 背景保留动作迁移视频生成

本文介绍了一个基于ComfyUI的高精度视频生成工作流"Wan2.2 Animate",该系统融合动作捕捉、图像拼接和LoRA加权等技术,能自动识别人脸并完成精准动作迁移,同时保持背景稳定。工作流采用模块化设计,包含输入提取、图像融合、模型加载等关键节点,核心模型Wan2.2-Animate-14B支持fp8精度与BlockSwap控制。流程分为图像输入、动作提取、多图合成等五个阶段,通过文本提示编码器和图像语义编码器实现语义驱动的动作生成,最终输出高质量视频,适用于虚拟形象驱动和

Mr数据杨 2258

数据结构 Map&Set(搜索)

数据结构 Map&Set(搜索) (超详细)

Mwt258的博客 1834

海康VisionMaster与西门子Smart 200进行S7通信

海康VisionMaster与西门子Smart 200进行S7通信

haier123888的博客 8177

【数据结构】map&set详解

HashMap的底层也是哈希表,和之前的HashSet不同,HashMap中,当插入的key相同时,第二次插入会覆盖原来的value值,同时,如果存储的是自定义类型的对象还需要重写HashCode和equals方法。TreeMap和TreeSet底层一样,都是红黑树,根据键进行排序,排序规则也是类似的,对于非数值等类型,可以实现Comparable接口,指定比较规则,也可以传入比较器。当用HashSet实例化对象时,由于底层结构是哈希表,所以元素是无序的,而TreeSet底层是红黑树,是有序的。

2202_76097976的博客 2976

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

数据结构之Map&Set

Map和set是一种专门用来进行搜索的容器或者数据结构,Map和Set是一种适合动态查找的集合容器。其中TreeMap和TreeSet集合背后的数据结构就是搜索树,红黑树。其中TreeSet底层就是一个TreeMap。 一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型会有两种: 1. 纯 key 模型 2. Key-Value 模型 而Map中存储的就是key-value的键值对,Set中只存储了Key。

crazy_xieyi的博客 1434

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

「数据结构」Map&Set

🎇🎇🎇。

Ice_Sugar_7的博客 1541

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

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

java数据结构-map&set

α=散列表的长度填入表中的元素个数​。

xiaomo2249的博客 1155

数据结构---Map&Set

二叉搜索树又叫二叉排序树,因为他的中序遍历是有序的,它或者是一棵空树或者满足以下性质:若他左子树不为空,则左子树上的节点都小于根节点的值若他右子树不为空,则右子树上的节点都大于根节点的值他的左右子树也都是二叉搜索树这个就是一个二叉搜索树这也是一个二叉树所以,我们可以对这个进行处理,变成avl树(也是一种特殊的二叉搜索树)通过左右旋转来调整树的结构,以求让树更平衡1.当我们插入元素时,我们根据待插入元素的hashcode再通过一个哈希函数,计算出该元素的存放位置进行存放。

huapiaoy的博客 1386

Java数据结构-Map&Set

Map&Set复习。

qq_45965652的博客 907

Java数据结构——Map&Set

二叉搜索树(Binary Search Tree)满足:1.若左子树不为空,那左子树上所有节点的值都小于根节点的值2.若右子树不为空,则右子树上所有节点的值都大于根节点的值3.左右子树本身也是一个二叉搜索树中序遍历可以得到一个递增序列哈希表(Hash Table)是一种通过哈希函数将键映射到数组中某个位置。从而实现快速存取的数据结构。理想情况下,插入、删除、查找的时间复杂度都是O(1)。在HashMap中,判断两个Key是否相等的逻辑是:1.先比较hashCode是否相等。

wang_shu_mo_ran的博客 258

Java数据结构:Map&Set

二叉搜索树实现、Map(TreeMap/HashMap) & Set(TreeSet/HashSet)、哈希冲突(负载因子)、冲突解决(闭散列/开散列-哈希桶)、哈希表实现(哈希桶)、HashMap源码分析(tableSizeFor、hash、put、resize)

Zzzzmo_的博客 632

数据结构-Map&Set【基础】

map接口的常用方法,set接口的常用方法、宝石与石头、旧键盘打字、复制带有随机指针的链表

qq_43243800的博客 445

Java:数据结构-Map&Set

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树搜索二叉树的操作。

blamep的博客 1159

Java数据结构|map&set(一)

map与set用在搜索相关的场景。

ccydeboke的博客 641

数据结构基础知识【十】:Map&Set

Map

qq_45605223的博客 249
上一篇: MySQL数据类型
下一篇: MySQL——事务隔离性的图文总结
Jul1en_
博客等级 码龄2年 275粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值