算法系列15天速成——第十三天 树操作【下】

16 篇文章 0 订阅

算法系列15天速成——第十三天 树操作【下】


转自:http://blog.csdn.net/m13666368773/article/details/7530356


今天说下最后一种树,大家可否知道,文件压缩程序里面的核心结构,核心算法是什么?或许你知道,他就运用了赫夫曼树。

听说赫夫曼胜过了他的导师,被认为”青出于蓝而胜于蓝“,这句话也是我比较欣赏的,嘻嘻。

 

一  概念

    了解”赫夫曼树“之前,几个必须要知道的专业名词可要熟练记住啊。

 

    1: 结点的权

            “权”就相当于“重要度”,我们形象的用一个具体的数字来表示,然后通过数字的大小来决定谁重要,谁不重要。

    2: 路径

             树中从“一个结点"到“另一个结点“之间的分支。

    3: 路径长度

             一个路径上的分支数量。

    4: 树的路径长度

             从树的根节点到每个节点的路径长度之和。

    5: 节点的带权路径路劲长度

             其实也就是该节点到根结点的路径长度*该节点的权。

    6:   树的带权路径长度

             树中各个叶节点的路径长度*该叶节点的权的和,常用WPL(Weight Path Length)表示。

 

二: 构建赫夫曼树

        上面说了那么多,肯定是为下面做铺垫,这里说赫夫曼树,肯定是要说赫夫曼树咋好咋好,赫夫曼树是一种最优二叉树,

         因为他的WPL是最短的,何以见得?我们可以上图说话。

   

现在我们做一个WPL的对比:

图A: WPL= 5*2 + 7*2 +2*2+13*2=54

图B:WPL=5*3+2*3+7*2+13*1=48

 

我们对比一下,图B的WPL最短的,地球人已不能阻止WPL还能比“图B”的小,所以,“图B"就是一颗赫夫曼树,那么大家肯定

要问,如何构建一颗赫夫曼树,还是上图说话。

 

第一步: 我们将所有的节点都作为独根结点。

第二步:   我们将最小的C和A组建为一个新的二叉树,权值为左右结点之和。

第三步: 将上一步组建的新节点加入到剩下的节点中,排除上一步组建过的左右子树,我们选中B组建新的二叉树,然后取权值。

第四步: 同上。

 

三: 赫夫曼编码

      大家都知道,字符,汉字,数字在计算机中都是以0,1来表示的,相应的存储都是有一套编码方案来支撑的,比如ASC码。

 这样才能在"编码“和”解码“的过程中不会成为乱码,但是ASC码不理想的地方就是等长的,其实我们都想用较少的空间来存储

更多的东西,那么我们就要采用”不等长”的编码方案来存储,那么“何为不等长呢“?其实也就是出现次数比较多的字符我们采用短编码,

出现次数较少的字符我们采用长编码,恰好,“赫夫曼编码“就是不等长的编码。

    这里大家只要掌握赫夫曼树的编码规则:左子树为0,右子树为1,对应的编码后的规则是:从根节点到子节点

A: 111

B: 10

C: 110

D: 0

 

四: 实现

      不知道大家懂了没有,不懂的话多看几篇,下面说下赫夫曼的具体实现。

         第一步:构建赫夫曼树。

         第二步:对赫夫曼树进行编码。

         第三步:压缩操作。

         第四步:解压操作。

 

1:首先看下赫夫曼树的结构,这里字段的含义就不解释了。

复制代码
[csharp]  view plain  copy
  1. #region 赫夫曼树结构  
  2.      /// <summary>  
  3.  /// 赫夫曼树结构  
  4.  /// </summary>  
  5.      public class HuffmanTree  
  6.      {  
  7.          public int weight { getset; }  
  8.    
  9.          public int parent { getset; }  
  10.    
  11.          public int left { getset; }  
  12.    
  13.          public int right { getset; }  
  14.      }  
  15.      #endregion  

 

2: 创建赫夫曼树,原理在上面已经解释过了,就是一步一步的向上搭建,这里要注意的二个性质定理:

         当叶子节点为N个,则需要N-1步就能搭建赫夫曼树。

         当叶子节点为N个,则赫夫曼树的节点总数为:(2*N)-1个。

复制代码
[csharp]  view plain  copy
  1. #region 赫夫曼树的创建  
  2.          /// <summary>  
  3.  /// 赫夫曼树的创建  
  4.  /// </summary>  
  5.  /// <param name="huffman">赫夫曼树</param>  
  6.  /// <param name="leafNum">叶子节点</param>  
  7.  /// <param name="weight">节点权重</param>  
  8.          public HuffmanTree[] CreateTree(HuffmanTree[] huffman, int leafNum, int[] weight)  
  9.          {  
  10.              //赫夫曼树的节点总数  
  11.              int huffmanNode = 2 * leafNum - 1;  
  12.    
  13.              //初始化节点,赋予叶子节点值  
  14.              for (int i = 0; i < huffmanNode; i++)  
  15.              {  
  16.                  if (i < leafNum)  
  17.                  {  
  18.                      huffman[i].weight = weight[i];  
  19.                  }  
  20.              }  
  21.    
  22.              //这里面也要注意,4个节点,其实只要3步就可以构造赫夫曼树  
  23.              for (int i = leafNum; i < huffmanNode; i++)  
  24.              {  
  25.                  int minIndex1;  
  26.                  int minIndex2;  
  27.                  SelectNode(huffman, i, out minIndex1, out minIndex2);  
  28.    
  29.                  //最后得出minIndex1和minindex2中实体的weight最小  
  30.                  huffman[minIndex1].parent = i;  
  31.                  huffman[minIndex2].parent = i;  
  32.    
  33.                  huffman[i].left = minIndex1;  
  34.                  huffman[i].right = minIndex2;  
  35.    
  36.                  huffman[i].weight = huffman[minIndex1].weight + huffman[minIndex2].weight;  
  37.              }  
  38.    
  39.              return huffman;  
  40.          }  
  41.          #endregion  
  42.   
  43.          #region 选出叶子节点中最小的二个节点  
  44.          /// <summary>  
  45.  /// 选出叶子节点中最小的二个节点  
  46.  /// </summary>  
  47.  /// <param name="huffman"></param>  
  48.  /// <param name="searchNodes">要查找的结点数</param>  
  49.  /// <param name="minIndex1"></param>  
  50.  /// <param name="minIndex2"></param>  
  51.          public void SelectNode(HuffmanTree[] huffman, int searchNodes, out int minIndex1, out int minIndex2)  
  52.          {  
  53.              HuffmanTree minNode1 = null;  
  54.    
  55.              HuffmanTree minNode2 = null;  
  56.    
  57.              //最小节点在赫夫曼树中的下标  
  58.              minIndex1 = minIndex2 = 0;  
  59.    
  60.              //查找范围  
  61.              for (int i = 0; i < searchNodes; i++)  
  62.              {  
  63.                  ///只有独根树才能进入查找范围  
  64.                  if (huffman[i].parent == 0)  
  65.                  {  
  66.                      //如果为null,则认为当前实体为最小  
  67.                      if (minNode1 == null)  
  68.                      {  
  69.                          minIndex1 = i;  
  70.    
  71.                          minNode1 = huffman[i];  
  72.    
  73.                          continue;  
  74.                      }  
  75.    
  76.                      //如果为null,则认为当前实体为最小  
  77.                      if (minNode2 == null)  
  78.                      {  
  79.                          minIndex2 = i;  
  80.    
  81.                          minNode2 = huffman[i];  
  82.    
  83.                          //交换一个位置,保证minIndex1为最小,为后面判断做准备  
  84.                          if (minNode1.weight > minNode2.weight)  
  85.                          {  
  86.                              //节点交换  
  87.                              var temp = minNode1;  
  88.                              minNode1 = minNode2;  
  89.                              minNode2 = temp;  
  90.    
  91.                              //下标交换  
  92.                              var tempIndex = minIndex1;  
  93.                              minIndex1 = minIndex2;  
  94.                              minIndex2 = tempIndex;  
  95.    
  96.                              continue;  
  97.                          }  
  98.                      }  
  99.                      if (minNode1 != null && minNode2 != null)  
  100.                      {  
  101.                          if (huffman[i].weight <= minNode1.weight)  
  102.                          {  
  103.                              //将min1临时转存给min2  
  104.                              minNode2 = minNode1;  
  105.                              minNode1 = huffman[i];  
  106.    
  107.                              //记录在数组中的下标  
  108.                              minIndex2 = minIndex1;  
  109.                              minIndex1 = i;  
  110.                          }  
  111.                          else  
  112.                          {  
  113.                              if (huffman[i].weight < minNode2.weight)  
  114.                              {  
  115.                                  minNode2 = huffman[i];  
  116.    
  117.                                  minIndex2 = i;  
  118.                              }  
  119.                          }  
  120.                      }  
  121.                  }  
  122.              }  
  123.          }  
  124.          #endregion  


3:对哈夫曼树进行编码操作,形成一套“模板”,效果跟ASC模板一样,不过一个是不等长,一个是等长。
复制代码
[csharp]  view plain  copy
  1. #region 赫夫曼编码  
  2.          /// <summary>  
  3.  /// 赫夫曼编码  
  4.  /// </summary>  
  5.  /// <param name="huffman"></param>  
  6.  /// <param name="leafNum"></param>  
  7.  /// <param name="huffmanCode"></param>  
  8.          public string[] HuffmanCoding(HuffmanTree[] huffman, int leafNum)  
  9.          {  
  10.              int current = 0;  
  11.    
  12.              int parent = 0;  
  13.    
  14.              string[] huffmanCode = new string[leafNum];  
  15.    
  16.              //四个叶子节点的循环  
  17.              for (int i = 0; i < leafNum; i++)  
  18.              {  
  19.                  //单个字符的编码串  
  20.                  string codeTemp = string.Empty;  
  21.    
  22.                  current = i;  
  23.    
  24.                  //第一次获取最左节点  
  25.                  parent = huffman[current].parent;  
  26.    
  27.                  while (parent != 0)  
  28.                  {  
  29.                      //如果父节点的左子树等于当前节点就标记为0  
  30.                      if (current == huffman[parent].left)  
  31.                          codeTemp += "0";  
  32.                      else  
  33.                          codeTemp += "1";  
  34.    
  35.                      current = parent;  
  36.                      parent = huffman[parent].parent;  
  37.                  }  
  38.    
  39.                  huffmanCode[i] = new string(codeTemp.Reverse().ToArray());  
  40.              }  
  41.              return huffmanCode;  
  42.          }  
  43.          #endregion  


4:模板生成好了,我们就要对指定的测试数据进行压缩处理
复制代码
[csharp]  view plain  copy
  1. #region 对指定字符进行压缩  
  2.          /// <summary>  
  3.  /// 对指定字符进行压缩  
  4.  /// </summary>  
  5.  /// <param name="huffmanCode"></param>  
  6.  /// <param name="alphabet"></param>  
  7.  /// <param name="test"></param>  
  8.          public string Encode(string[] huffmanCode, string[] alphabet, string test)  
  9.          {  
  10.              //返回的0,1代码  
  11.              string encodeStr = string.Empty;  
  12.    
  13.              //对每个字符进行编码  
  14.              for (int i = 0; i < test.Length; i++)  
  15.              {  
  16.                  //在模版里面查找  
  17.                  for (int j = 0; j < alphabet.Length; j++)  
  18.                  {  
  19.                      if (test[i].ToString() == alphabet[j])  
  20.                      {  
  21.                          encodeStr += huffmanCode[j];  
  22.                      }  
  23.                  }  
  24.              }  
  25.    
  26.              return encodeStr;  
  27.          }  
  28.          #endregion  

 

5: 最后也就是对压缩的数据进行还原操作。

复制代码
[csharp]  view plain  copy
  1. #region 对指定的二进制进行解压  
  2.          /// <summary>  
  3.  /// 对指定的二进制进行解压  
  4.  /// </summary>  
  5.  /// <param name="huffman"></param>  
  6.  /// <param name="leafNum"></param>  
  7.  /// <param name="alphabet"></param>  
  8.  /// <param name="test"></param>  
  9.  /// <returns></returns>  
  10.          public string Decode(HuffmanTree[] huffman, int huffmanNodes, string[] alphabet, string test)  
  11.          {  
  12.              string decodeStr = string.Empty;  
  13.    
  14.              //所有要解码的字符  
  15.              for (int i = 0; i < test.Length; )  
  16.              {  
  17.                  int j = 0;  
  18.                  //赫夫曼树结构模板(用于循环的解码单个字符)  
  19.                  for (j = huffmanNodes - 1; (huffman[j].left != 0 || huffman[j].right != 0); )  
  20.                  {  
  21.                      if (test[i].ToString() == "0")  
  22.                      {  
  23.                          j = huffman[j].left;  
  24.                      }  
  25.                      if (test[i].ToString() == "1")  
  26.                      {  
  27.                          j = huffman[j].right;  
  28.                      }  
  29.                      i++;  
  30.                  }  
  31.                  decodeStr += alphabet[j];  
  32.              }  
  33.              return decodeStr;  
  34.          }  
  35.   
  36.          #endregion  

 

最后上一下总的运行代码

[csharp]  view plain  copy
  1. View Code   
  2.  using System;  
  3.  using System.Collections.Generic;  
  4.  using System.Linq;  
  5.  using System.Text;  
  6.    
  7.  namespace HuffmanTree  
  8.  {  
  9.      class Program  
  10.      {  
  11.          static void Main(string[] args)  
  12.          {  
  13.              //有四个叶节点  
  14.              int leafNum = 4;  
  15.    
  16.              //赫夫曼树中的节点总数  
  17.              int huffmanNodes = 2 * leafNum - 1;  
  18.    
  19.              //各节点的权值  
  20.              int[] weight = { 5, 7, 2, 13 };  
  21.    
  22.              string[] alphabet = { "A""B""C""D" };  
  23.    
  24.              string testCode = "DBDBDABDCDADBDADBDADACDBDBD";  
  25.    
  26.              //赫夫曼树用数组来保存,每个赫夫曼都作为一个实体存在  
  27.              HuffmanTree[] huffman = new HuffmanTree[huffmanNodes].Select(i => new HuffmanTree() { }).ToArray();  
  28.    
  29.              HuffmanTreeManager manager = new HuffmanTreeManager();  
  30.    
  31.              manager.CreateTree(huffman, leafNum, weight);  
  32.    
  33.              string[] huffmanCode = manager.HuffmanCoding(huffman, leafNum);  
  34.    
  35.              for (int i = 0; i < leafNum; i++)  
  36.              {  
  37.                  Console.WriteLine("字符:{0},权重:{1},编码为:{2}", alphabet[i], huffman[i].weight, huffmanCode[i]);  
  38.              }  
  39.    
  40.              Console.WriteLine("原始的字符串为:" + testCode);  
  41.    
  42.              string encode = manager.Encode(huffmanCode, alphabet, testCode);  
  43.    
  44.              Console.WriteLine("被编码的字符串为:" + encode);  
  45.    
  46.              string decode = manager.Decode(huffman, huffmanNodes, alphabet, encode);  
  47.    
  48.              Console.WriteLine("解码后的字符串为:" + decode);  
  49.          }  
  50.      }  
  51.   
  52.      #region 赫夫曼树结构  
  53.      /// <summary>  
  54.  /// 赫夫曼树结构  
  55.  /// </summary>  
  56.      public class HuffmanTree  
  57.      {  
  58.          public int weight { getset; }  
  59.    
  60.          public int parent { getset; }  
  61.    
  62.          public int left { getset; }  
  63.    
  64.          public int right { getset; }  
  65.      }  
  66.      #endregion  
  67.    
  68.      /// <summary>  
  69.  /// 赫夫曼树的操作类  
  70.  /// </summary>  
  71.      public class HuffmanTreeManager  
  72.      {  
  73.          #region 赫夫曼树的创建  
  74.          /// <summary>  
  75.  /// 赫夫曼树的创建  
  76.  /// </summary>  
  77.  /// <param name="huffman">赫夫曼树</param>  
  78.  /// <param name="leafNum">叶子节点</param>  
  79.  /// <param name="weight">节点权重</param>  
  80.          public HuffmanTree[] CreateTree(HuffmanTree[] huffman, int leafNum, int[] weight)  
  81.          {  
  82.              //赫夫曼树的节点总数  
  83.              int huffmanNode = 2 * leafNum - 1;  
  84.    
  85.              //初始化节点,赋予叶子节点值  
  86.              for (int i = 0; i < huffmanNode; i++)  
  87.              {  
  88.                  if (i < leafNum)  
  89.                  {  
  90.                      huffman[i].weight = weight[i];  
  91.                  }  
  92.              }  
  93.    
  94.              //这里面也要注意,4个节点,其实只要3步就可以构造赫夫曼树  
  95.              for (int i = leafNum; i < huffmanNode; i++)  
  96.              {  
  97.                  int minIndex1;  
  98.                  int minIndex2;  
  99.                  SelectNode(huffman, i, out minIndex1, out minIndex2);  
  100.    
  101.                  //最后得出minIndex1和minindex2中实体的weight最小  
  102.                  huffman[minIndex1].parent = i;  
  103.                  huffman[minIndex2].parent = i;  
  104.    
  105.                  huffman[i].left = minIndex1;  
  106.                  huffman[i].right = minIndex2;  
  107.    
  108.                  huffman[i].weight = huffman[minIndex1].weight + huffman[minIndex2].weight;  
  109.              }  
  110.    
  111.              return huffman;  
  112.          }  
  113.          #endregion  
  114.   
  115.          #region 选出叶子节点中最小的二个节点  
  116.          /// <summary>  
  117.  /// 选出叶子节点中最小的二个节点  
  118.  /// </summary>  
  119.  /// <param name="huffman"></param>  
  120.  /// <param name="searchNodes">要查找的结点数</param>  
  121.  /// <param name="minIndex1"></param>  
  122.  /// <param name="minIndex2"></param>  
  123.          public void SelectNode(HuffmanTree[] huffman, int searchNodes, out int minIndex1, out int minIndex2)  
  124.          {  
  125.              HuffmanTree minNode1 = null;  
  126.    
  127.              HuffmanTree minNode2 = null;  
  128.    
  129.              //最小节点在赫夫曼树中的下标  
  130.              minIndex1 = minIndex2 = 0;  
  131.    
  132.              //查找范围  
  133.              for (int i = 0; i < searchNodes; i++)  
  134.              {  
  135.                  ///只有独根树才能进入查找范围  
  136.                  if (huffman[i].parent == 0)  
  137.                  {  
  138.                      //如果为null,则认为当前实体为最小  
  139.                      if (minNode1 == null)  
  140.                      {  
  141.                          minIndex1 = i;  
  142.    
  143.                          minNode1 = huffman[i];  
  144.    
  145.                          continue;  
  146.                      }  
  147.    
  148.                      //如果为null,则认为当前实体为最小  
  149.                      if (minNode2 == null)  
  150.                      {  
  151.                          minIndex2 = i;  
  152.    
  153.                          minNode2 = huffman[i];  
  154.    
  155.                          //交换一个位置,保证minIndex1为最小,为后面判断做准备  
  156.                          if (minNode1.weight > minNode2.weight)  
  157.                          {  
  158.                              //节点交换  
  159.                              var temp = minNode1;  
  160.                              minNode1 = minNode2;  
  161.                              minNode2 = temp;  
  162.    
  163.                              //下标交换  
  164.                              var tempIndex = minIndex1;  
  165.                              minIndex1 = minIndex2;  
  166.                              minIndex2 = tempIndex;  
  167.    
  168.                              continue;  
  169.                          }  
  170.                      }  
  171.                      if (minNode1 != null && minNode2 != null)  
  172.                      {  
  173.                          if (huffman[i].weight <= minNode1.weight)  
  174.                          {  
  175.                              //将min1临时转存给min2  
  176.                              minNode2 = minNode1;  
  177.                              minNode1 = huffman[i];  
  178.    
  179.                              //记录在数组中的下标  
  180.                              minIndex2 = minIndex1;  
  181.                              minIndex1 = i;  
  182.                          }  
  183.                          else  
  184.                          {  
  185.                              if (huffman[i].weight < minNode2.weight)  
  186.                              {  
  187.                                  minNode2 = huffman[i];  
  188.    
  189.                                  minIndex2 = i;  
  190.                              }  
  191.                          }  
  192.                      }  
  193.                  }  
  194.              }  
  195.          }  
  196.          #endregion  
  197.   
  198.          #region 赫夫曼编码  
  199.          /// <summary>  
  200.  /// 赫夫曼编码  
  201.  /// </summary>  
  202.  /// <param name="huffman"></param>  
  203.  /// <param name="leafNum"></param>  
  204.  /// <param name="huffmanCode"></param>  
  205.          public string[] HuffmanCoding(HuffmanTree[] huffman, int leafNum)  
  206.          {  
  207.              int current = 0;  
  208.    
  209.              int parent = 0;  
  210.    
  211.              string[] huffmanCode = new string[leafNum];  
  212.    
  213.              //四个叶子节点的循环  
  214.              for (int i = 0; i < leafNum; i++)  
  215.              {  
  216.                  //单个字符的编码串  
  217.                  string codeTemp = string.Empty;  
  218.    
  219.                  current = i;  
  220.    
  221.                  //第一次获取最左节点  
  222.                  parent = huffman[current].parent;  
  223.    
  224.                  while (parent != 0)  
  225.                  {  
  226.                      //如果父节点的左子树等于当前节点就标记为0  
  227.                      if (current == huffman[parent].left)  
  228.                          codeTemp += "0";  
  229.                      else  
  230.                          codeTemp += "1";  
  231.    
  232.                      current = parent;  
  233.                      parent = huffman[parent].parent;  
  234.                  }  
  235.    
  236.                  huffmanCode[i] = new string(codeTemp.Reverse().ToArray());  
  237.              }  
  238.              return huffmanCode;  
  239.          }  
  240.          #endregion  
  241.   
  242.          #region 对指定字符进行压缩  
  243.          /// <summary>  
  244.  /// 对指定字符进行压缩  
  245.  /// </summary>  
  246.  /// <param name="huffmanCode"></param>  
  247.  /// <param name="alphabet"></param>  
  248.  /// <param name="test"></param>  
  249.          public string Encode(string[] huffmanCode, string[] alphabet, string test)  
  250.          {  
  251.              //返回的0,1代码  
  252.              string encodeStr = string.Empty;  
  253.    
  254.              //对每个字符进行编码  
  255.              for (int i = 0; i < test.Length; i++)  
  256.              {  
  257.                  //在模版里面查找  
  258.                  for (int j = 0; j < alphabet.Length; j++)  
  259.                  {  
  260.                      if (test[i].ToString() == alphabet[j])  
  261.                      {  
  262.                          encodeStr += huffmanCode[j];  
  263.                      }  
  264.                  }  
  265.              }  
  266.    
  267.              return encodeStr;  
  268.          }  
  269.          #endregion  
  270.   
  271.          #region 对指定的二进制进行解压  
  272.          /// <summary>  
  273.  /// 对指定的二进制进行解压  
  274.  /// </summary>  
  275.  /// <param name="huffman"></param>  
  276.  /// <param name="leafNum"></param>  
  277.  /// <param name="alphabet"></param>  
  278.  /// <param name="test"></param>  
  279.  /// <returns></returns>  
  280.          public string Decode(HuffmanTree[] huffman, int huffmanNodes, string[] alphabet, string test)  
  281.          {  
  282.              string decodeStr = string.Empty;  
  283.    
  284.              //所有要解码的字符  
  285.              for (int i = 0; i < test.Length; )  
  286.              {  
  287.                  int j = 0;  
  288.                  //赫夫曼树结构模板(用于循环的解码单个字符)  
  289.                  for (j = huffmanNodes - 1; (huffman[j].left != 0 || huffman[j].right != 0); )  
  290.                  {  
  291.                      if (test[i].ToString() == "0")  
  292.                      {  
  293.                          j = huffman[j].left;  
  294.                      }  
  295.                      if (test[i].ToString() == "1")  
  296.                      {  
  297.                          j = huffman[j].right;  
  298.                      }  
  299.                      i++;  
  300.                  }  
  301.                  decodeStr += alphabet[j];  
  302.              }  
  303.              return decodeStr;  
  304.          }  
  305.   
  306.          #endregion  
  307.      }  
  308.  }  


 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值