前端不懂算法(三)--归并排序

前端JS算法--归并排序 归并排序的时间复杂度是 O(n log n),这使得它在处理大型数据集时非常有效。然而,由于它需要额外的空间来存储合并后的数组,因此在空间复杂度上可能不如原地排序算法(如快速排序)高效。归并排序是一种分治算法,它将数组分成多个子数组,然后对这些子数组进行排序,最后将排序后的子数组合并成一个有序数组。整体思路如上图,需用递归实现,递归实现最重要的是写出递归公式、终止条件。:将数组分成两半,如果数组只有一个元素或为空,则不需要排序。:将排序后的两半合并成一个有序数组。:递归地对数组的两半进行归并排序。 阅读详情

本篇文章参考借鉴了以下文章和极客时间的数据结构与算法一文,若涉及侵权,请联系我删除。

前言

  之前的博客里面我们一块学习了,冒泡排序,插入排序,选择排序,这三种排序算法,它们的时间复杂度都是O(n2),适用于小规模数据的排序,本篇文章,我们一块来学习下归并排序。适用于大规模数据。

没看过之前文章的小伙伴可以先了解一下

核心思想

  归并排序的核心思想是 分治思想 ,非常巧妙。我们可以借鉴这个思想,来解决非排序问题,比如:如何在O(n)的时间复杂度内查找一个无需数组的第 K 大元素?,这就用到了归并排序。

归并排序原理

  归并排序的实现原理还是比较简单的,如果要排序一个数组,我们先把数组从中间分成前后两个部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就有序了。
在这里插入图片描述
  分治,顾名思义就是分而治之,将一个大问题分解成小的子问题来解决。小问题解决了,大问题也就解决了。

  从刚才的描述中可以看出,分治思想跟递归很像。是的,分治算法一般都是用递归实现的。分治是一种解决问题的处理思想,递归是一种编程技巧,这两者并不冲突。分治算法的思想我们放到后面的章节来梳理,现在不展开讨论,本篇文章重点还是排序算法。

如何实现归并排序

  如何用递归来实现归并排序?

  首先,递归代码的技巧是分析得出递推公式,找到终止条件,最后将递推公式翻译成递推代码。所以一起看看如何写出递推公式。

递推公式:
margin_sort(p...r) = merge(merge_sort(p...q), merge_sort(q+1...r))

终止条件:
p >= r不用再继续分了。

  该递推公式仔细观察就会发现:margin_sort(p...r)表示给下标从 p 到 r 之间的数组排序。现在将这个排序问题转化成两个子问题,margin_sort(p...q)和margin_sort(q+1...r),其中 q 是 p 和 r 的中间位置,也就是(p + r)/2。

  当下标从 p 到 q 和从 q + 1 到 r 这两个子数组都排序好之后,我们再将两个有序的子数组合并在一起,这样下标从 p 到 r 之间的数据也就好排序了。

  有了递推公式,下一步就是转换成代码了,各位请看:

//归并排序算法
function mergeSort(arr) {
  mergeSortFn(arr, 0, arr.length - 1)
}

//递归调用函数
function mergeSortFn(arr, p, r) {
  //递归终止条件
  if (p >= r) return;

  //取 p 到 r 之间的中位数 q
  let q = parseInt((p + r) / 2);

  //分治递归
  mergeSortFn(arr, p, q)
  mergeSortFn(arr, q + 1, r)

  //将A[p...q] 和 arr[q...r]合并为 arr[p...r]
  merge(arr, p, q, r);
}

  上面代码中merge()函数的作用,就是将两个有序数组,合并成一个新的有序数组,实现原理如图
在这里插入图片描述
  如图所示,申请一个临时数组tmp,大小与A[p...r]相同。我们用两个游标 i和j,分别指向A[p...q]和A[q+1...r]的第一个元素,比较这两个元素,A[i]和A[j],如果A[i] <= A[j],我们就把A[i]放入到临时数组tmp,并且i后移一位,否则就将A[j]放入到数组tmp,j后移一位。

  直到其中一个子数组中所有的数据都放入临时数组中,再把另一个数组中的数据依次加入到临时数组的末尾,这个时候临时数组存储的值就是两个子数组合并之后的结果。最后再把临时数组tmp中的数据拷贝到原始数组A[p...r]中。

  加上merge()部分的代码如下:

//归并排序算法
function mergeSort(arr) {
    mergeSortFn(arr, 0, arr.length - 1);
}

//递归调用函数
function mergeSortFn(arr, p, r) {
    //递归终止条件
    if (p >= r) return;

    //取 p 到 r 之间的中位数 q
    let q = parseInt((p + r) / 2);

    //分治递归
    mergeSortFn(arr, p, q);
    mergeSortFn(arr, q + 1, r);

    //将A[p...q] 和 arr[q...r]合并为 arr[p...r]
    merge(arr, p, q, r);
}


//合并分开的数据
function merge(arr, p, q, r) {
    let i = p,     //第一段序列下标
        j = q + 1, //第二段序列下标
        k = 0,     //临时存放数组下标
        tmp = [];  //临时存放数组

    while (i <= q && j <= r) {
        if (arr[i] <= arr[j]) {
            tmp[k++] = arr[i++];
        } else {
            tmp[k++] = arr[j++];
        }
    }

    //判断哪个子数组中有剩余数据
    var star = i, end = q;
    if (j <= r) {
        star = j;
        end = r;
    }

    //将剩余数据拷贝到临时数组
    while (star <= end) {
        tmp[k++] = arr[star++];
    }

    //将tmp中的数据拷贝回arr (*)
    for (k = 0, i = p; i <= r; i++, k++) {
        arr[i] = tmp[k];
    }
}

var arr = [10, 8, 6, 4, 9, 7, 5];
mergeSort(arr);
console.log('排序后的数组:', arr); // 排序后的数组:[4,5,6,7,8,9]

上面代码 (*)的部分,注意,这里把 tmp 替换到 arr 中不是单纯的完全替换,而是对应位置的替换,比如上文中的例子

  • 第一次替换,arr 是 [10, 8, 6, 4, 9, 7, 5] ,tmp 是 [8, 10]。        替换后 arr 变成 [8, 10, 6, 4, 9, 7, 5]
  • 第二次替换,arr 是 [8, 10, 6, 4, 9, 7, 5] ,tmp 是 [4, 6]。        替换后 arr 变成 [8, 10, 4, 6, 9, 7, 5]
  • 第三次替换,arr 是 [8, 10, 4, 6, 9, 7, 5] ,tmp 是 [4, 6, 8,10]。    替换后 arr 变成 [4, 6, 8, 10, 9, 7, 5]
  • 第四次替换,arr 是 [4, 6, 8, 10, 9, 7, 5] ,tmp 是 [7, 9]。        替换后 arr 变成 [4, 6, 8, 10, 7, 9, 5]
  • 第五次替换,arr 是 [4, 6, 8, 10, 7, 9, 5] ,tmp 是 [5, 7, 9]。       替换后 arr 变成 [4, 6, 8, 10, 5, 7, 9]
  • 第六次替换,arr 是 [4, 6, 8, 10, 5, 7, 9] ,tmp 是 [4, 5, 6, 7, 8, 9, 10]。替换后 arr 变成 [4, 5, 6, 7, 8, 9, 10]

归并排序性能分析

分析排序算法的三个方面,不记得的小伙伴点下方文章复习一下

第一、归并排序是稳定的排序算法吗?

  判断归并排序稳不稳定,关键在于往 tmp 中放数据的时候,先放谁?在合并过程中,如果有相同的元素,我们需要先把 A[p...q] 中的元素放入 tmp 数组,这样就保证了值相同的元素,在合并前后顺序不变。所以归并排序是一种稳定的排序算法 。

第二、归并排序的时间复杂度是多少?

  归并排序涉及递归,分析起来稍微有点复杂。我们知道递归是把 a 问题分解成 b ,c 问题,求解 b ,c 之后,合并起来,就能解决 a 问题。那么就会有这样一个公式, a 的时间是 b 的时间加上 c 的时间,再加上合并的时间。

  T(a) = T(b) + T(c) + k

  这样我们就有了 递归代码的时间复杂度的递推公式 。

  设对 n 个元素进行归并排序的时间需要 T(n) ,那分解成两个子数组的排序时间都是 T(n/2), 我们知道 merge() 函数合并两个有序子数组的时间复杂度是 O(n) ,所以归并排序的时间复杂度就是:

  • T(1) = C; n = 1 时,只需要常量级的执行时间。
  • T(n) = 2*T(n) + n; n > 1

  上面公式还是不够直观需要进一步计算。

T(n) = 2*T(n/2) + n
   = 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n
   = 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
   …
   = 2k *T(n/2k) + k*n
   …

  通过上面的分析推导,我们可以得到 T(n) = 2k T(n/2k) + kn 当 T(n/2k) = T(1) 时,也就是 n/2k = 1,我们得到 k = log2n 。

将 k 代入上面的公式,得到 T(n) = Cn + nlog2n。 如果用大 O 标记法表示, T(n) = O(nlogn)。 所以归并排序的时间复杂度为 O(nlogn)

  上面为什么 nlogn 没有写出 底数? ,这是因为我们在研究时间复杂度的时候,都是把 n 想象成无穷大,举个例子,O(logx(n)) 和 O(logy(n)) ,x != y,当 n 无穷大的时候,logx(n)/logy(n) 的极限可以发现,极限等于 lny/lnx ,是一个常数。

  也就是说,在n趋于无穷大的时候,这两个东西仅差一个常数。所以从研究算法的角度log的底数不重要。

 (提示:只要是时间复杂度中有log级别的,都是由于使用了分治思想,这个底数直接由分治的复杂度决定)

第三、归并排序的空间复杂度是多少?

  归并排序的时间复杂度在任何情况下都是 O(nlogn) ,看起来非常优秀,但是归并排序却并没有像快排那样应用广泛,这是因为归并排序有一个致命“弱点”,它并不是原地排序算法。

  这是因为归并排序的合并函数,在合并两个有序数组的时候,需要借助额外的存储空间。这一点很好理解,需要 tmp 的参与,而且 tmp 是根据所排序数组的大小决定的。那么归并排序的时间复杂度是多少呢?

  由于 tmp 是我们在定义在 merge() 函数中的变量,当函数执行完之后,变量就会被释放,所以归并排序的空间复杂度最大也不会超过 n ,空间复杂度就是 O(n)

前端十种排序算法解析 排序算法 时间复杂度(平均) 空间复杂度 稳定性冒泡排序 O(n²) O(1) 稳定选择排序 O(n²) O(1) 不稳定归并排序 O(n log n) O(n) 稳定快速排序 O(n log n) O(log n) 不稳定插入排序 O(n²) O(1) 稳定希尔排序 O(n log n) O(1) 不稳定基数排序 O(nk) O(n + k) 稳定计数排序 O(n + k) O(k) 稳定桶排序 O(n + k) O(n + k) 稳定。 阅读详情

相关推荐

前端面试必备——基本排序算法

排序算法是面试及笔试中必考点,本文通过动画方式演示,通过实例讲解,最后给出JavaScript版的排序算法

yuyurenjie的博客 1万+

前端算法刷题之路—归并排序(8个题目详细分析)

归并排序 = 递归 + 合并 实现 通过递归将大数组拆分成每一项,然后对两项进行有序合并。归并排序中重点为合并,即将两个有序数组合并为一个有序数组。 我们可以设置两个指针,一个指向左边数组的第一项,一个指向右边数组第一项,比较两个指针对应的数,将小的放入临时数组中,然后对应小的指针右移,不断循环直到两个指针都移到对应数组的末尾后。 最后把临时数组覆盖到原数组对应位置就可以了。 var mergeSort = function (arr, left, right) { if (left >=.

m0_49343686的博客 660

C语言试题176之实现归并排序算法

题目:实现归并排序算法概念及其介绍 归并排序(Merge sort)是建立在归并操作上的一种有效、稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。适用说明 当有 n 个记录时,需进行 logn 轮归并排序,每一轮归并,其比较次数不超过 n,元素移动次数都是 n,因此,归并排序的时间复杂度为 O(nlogn)。归并排序时需要和待排序记

码莎拉蒂 2800

前端算法之归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。把长度为n的输入序列分成两个长度为n/2的子序列;将两个排序好的子序列合并成一个最终的排序序列。对这两个子序列分别采用归并排序;

xiaohua0708day的博客 335

史上最全的前端十大经典算法,赶紧收藏起来吧

史上最全的前端十大经典算法,赶紧收藏起来吧 人生没有白走的路,每一步都算数,大家好,我是小王,今天,给大家分享的内容是:前端十大算法,原创不易,希望大家多多支持! 一、面试官为什么喜欢问算法,当面试官在面试数据结构和算法的时候,他真正面试你的是什么? 化繁为简,直达问题本质的能力。很多面试题都披着或业务或时髦技术的外衣,而且一开始可能还没有给你充足的信息,那能不能通过独立思考,和面试官沟通获得必要的约束和前提,然后透过现象看本质,就是一个很重要的考察点。而算法本身,就是计算机领域内无数先哲牛人多年

道阻且长,行则将至。 2256

ZYNQ程序固化实战:从BOOT.bin生成到QSPI/SD卡双启动模式详解

本文详细解析了ZYNQ 7000系列程序固化的完整流程,重点解决了程序断电丢失问题。通过实战演示,从生成BOOT.bin文件到配置QSPI与SD卡双启动模式,逐步指导开发者实现程序在外部存储中的永久驻留,确保产品脱离调试器独立运行。

weixin_29193259的博客 517

前端复习--归并排序

起因,昨天取面试猿题库,两个面试官,每人各只考了两道算法题. 其中有一道是考归并排序不使用递归或是栈结构实现,感觉手生,当时答得并不好,傻傻地问面试官,不能考个"快排"吗,面试官笑笑:"快排"太简单.... 1 传统方法,利用递归 归并排序其实要做两件事: (1)“分解”——将序列每次折半划分。 (2)“合并”——将划分后的序列段两两合并后排序。 真的就只有这两件事. 我们先去解

hellokingqwe的博客 649

Zemax光机热集成分析:从FEA数据导入到光学性能评估实战

在精密光学系统设计中,环境温度变化和机械应力是导致像质恶化的关键因素,这涉及到光、机、热多物理场的耦合分析。其核心原理在于,通过有限元分析(FEA)软件(如ANSYS)模拟热与力学载荷下的结构变形和温度分布,并将这些物理场数据精准映射到光学设计软件(如Zemax)中,以评估其对调制传递函数(MTF)、点列图等核心光学指标的影响。这项技术的工程价值在于,它使设计从静态的理想模型跃升至动态的工程现实,能够在设计阶段就预测并补偿环境扰动,从而显著提升光学系统在航空航天、车载镜头、高功率激光等严苛工况下的可靠性与稳

weixin_30565327的博客 356

前端排序算法-----并归排序

一. 归并排序 1.算法描述: (1)将数组划分成left和right两部分,分别对left和right循环递归上述操作直至数组的长度为1 (2)从内到外依次完成数组的大小的组合合并 2.算法实现: function mergeSort(arr){ //循环划分数组直至长度为1 if(arr.length==1)return arr let midIndex=Ma...

qq_39298826的博客 269

别再踩坑了!Vue3 + Vant 手把手教你搞定飞书网页应用免登(SSO),附完整代码和重定向URL配置

本文详细介绍了如何使用Vue3和Vant实现飞书H5应用的免登(SSO)功能,包括飞书后台配置的关键细节、Vue3前端实现的最佳实践以及常见问题排查指南。特别针对重定向URL配置、安全设置和错误处理等常见陷阱提供了解决方案,并附有完整代码示例和性能优化建议。

weixin_29323551的博客 404

使用 ArxivLoader 从 arXiv 加载学术文献并实现高效文档处理

arXiv是一个开放获取的学术存储平台,涵盖了物理、数学、计算机科学等多个领域的 200 万篇学术论文。这些文献中包含了如逻辑推理、机器学习等热门领域的最新研究进展。通过使用 ArxivLoader,我们可以轻松地搜索和加载 arXiv 上的学术文献,并将其转换为文本以供分析或应用于下游任务,例如问答系统、摘要生成或知识图谱构建。有时我们并不需要完整的文献内容,而是只需要摘要用于快速预览。可以使用 get_summaries_as_docs()# 获取文献摘要# 查看第一篇摘要。

hgSdaegva的博客 888

前端不懂算法(四)--快速排序

本篇文章参考借鉴了以下文章和极客时间的数据结构与算法一文,若涉及侵权,请联系我删除。 https://blog.youkuaiyun.com/baiyan3212/article/details/104524261 文章目录前言核心思想快速排序原理 前言   上一篇博客我们一块学习了, 归并排序,它的时间复杂度是 O(nlogn),是一种排序效率很高的算法,本篇文章,我们一块来学习一种效率高,并且名气很大...

不见浅诗的博客 598

暗黑地牢modfiles.txt文件生成工具

暗黑地牢modfiles.txt文件生成工具引言方法工具源码基本步骤 引言 玩过暗黑地牢mod,并手动修改了mod中文件的话,如果不同步修改modfiles.txt文件,就会引起各种问题,典型的比如马车刷不出mod英雄,商店和boss都不再出现mod饰品,怪物贴图丢失出现黑块等,要解决这个问题,就要修正mod文件夹下的modfiles.txt文件 方法 针对修改量大小,一般有几种方法: 如果修改较少,而且你还记得修改了哪几个文件,找到这几个文件,右键属性,查看大小,要用的是括号里面的字节数,然后打开mod

lttclaw_的专栏 5002

前端必须掌握的五种排序算法,你会几种?

在前端开发中,对数据进行排序是一项基本且常见的任务。掌握排序算法不仅可以帮助我们更有效地处理数据,还能提升代码的执行效率。冒泡排序、选择排序、插入排序、快速排序和归并排序。通过理解这些算法的原理和逻辑,我们可以更好地选择合适的排序方法来优化应用性能。正文开始💖💖💖。

前端探索者 3753

比例导引算法详解:从理论到Matlab实现(含3D轨迹可视化)

本文深入解析比例导引算法(PNG)的数学原理与Matlab实现,涵盖3D轨迹可视化技术。从基础运动学模型到导航比优化,详细讲解导弹拦截系统的核心算法,并提供Matlab代码示例,帮助读者掌握从理论到实战的全流程。

weixin_33725722的博客 548

【路径规划】Theta_star算法机器人栅格地图最短路径规划【含Matlab源码 2618期】

Theta_star算法机器人栅格地图最短路径规划 完整的代码,方可运行;可提供运行操作视频!适合小白!

订阅付费专栏Matlab(奶茶价版),可赠送奶茶价版付费专栏指定代码1份; 363

排序算法与前端交互优化

排序算法是前端开发中处理数据和优化交互的核心工具。从动态表格的列排序到拖拽重排列表,再到数据可视化的动态调整,排序算法直接影响用户体验和页面性能。常见的排序算法如冒泡排序、快速排序和归并排序在不同场景下各有优势,能够满足从小型交互到大数据处理的需求。结合现代前端技术,如 Vue 3 和 Web Worker,排序算法可以进一步提升交互流畅度和性能。

zimin的专栏 920

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

都2020年了,听说你还不会归并排序?手把手教你手写归并排序算法

本文介绍了归并排序的基本思想,递归方法的一般写法,最后一步步手写归并排序,并对其性能进行了分析。

超悦人生 3615

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

前端不懂算法(一)--冒泡排序

本篇文章参考借鉴了叶老师的数据结构与算法一文,若涉及侵权,请联系我删除。 文章目录前言如何分析一个“排序算法”?排序算法的执行效率1.最好情况,最坏情况,平均情况时间复杂度2.时间复杂度的系数,常数,低阶3.比较次数和交换(或移动)次数排序算法的内存消耗排序算法的稳定性冒泡排序Q1,冒泡排序是原地排序吗?Q2,冒泡排序是稳定的排序算法吗?Q3,冒泡排序的时间复杂度是多少? 前言   对于大多数人来...

不见浅诗的博客 902

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

程序员必须掌握哪些算法?——前端开发工程师需要掌握的算法

一个程序员一生中可能会邂逅各种各样的算法,但总有那么几种,是作为一个程序员一定会遇见且大概率需要掌握的算法。作为一名前端开发工程师,今天就通过这个话题和文章来聊聊前端开发工程师需要掌握的算法有哪些呢。

黛琳ghz的博客,期待你的关注。 1694

教你快速学习算法之归并排序

附Java/C/C++/机器学习/算法与数据结构/前端/安卓/Python/程序员必读书籍书单大全: 书单导航页(点击右侧 极客侠栈 即可打开个人博客):极客侠栈 ①【Java】学习之路吐血整理技术书从入门到进阶最全50+本(珍藏版) ②【算法数据结构+acm】从入门到进阶吐血整理书单50+本(珍藏版) ③【数据库】从入门到进阶必读18本技术书籍网盘吐血整理网盘(珍藏版) ④【Web前端】从HT...

qq_43554593的博客 267

前端常见算法

前端常见算法

NINE-NINE的博客 3465

前端算法笔记-归并排序

前言 准备根据修言老师的小册子中归并排序的内容,学习一下剑指offer 51 归并排序是对分治思想的典型应用,它按照如下的思路对分治思想“三步走”的框架进行了填充: 分解子问题:将需要被排序的数组从中间分割为两半,然后再将分割出来的每个子数组各分割为两半,重复以上操作,直到单个子数组只有一个元素为止。 求解每个子问题:从粒度最小的子数组开始,两两合并、确保每次合并出来的数组都是有序的。(这里的“子问题”指的就是对每个子数组进行排序)。 合并子问题的解,得出大问题的解:当数组被合并至原有的规模时

padawan75的博客 300

【算法】浅谈前端算法

作者:陈立林 链接:https://zhuanlan.zhihu.com/p/29974629 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 计算机领域,算法问题是不可忽视的。前端圈圈内圈外一直都有人调侃前端的算法问题。也有从事前端大数据可视化分析的我简单谈谈我对前端算法的看法。算法在前端的地位。算法简单来说,是一门研究计算机性能和资源分配的学科。 前端或者说J...

SchrodingerEgg的博客 992

前端必掌握的Fisher-Yates 洗牌算法等

洗牌算法(Fisher-Yates)快速排序(Quicksort)归并排序(Merge Sort)二分查找(Binary Search)

weixin_74085863的博客 2228
上一篇: 前端不懂算法(二)--插入排序,选择排序
下一篇: 前端不懂算法(四)--快速排序
不见浅诗~
博客等级 码龄7年 506粉丝 129原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值