Linux下实现Huffman编码压缩算法

//stack.h

  1. /************************************************************* 
  2.     FileName : stack.h  
  3.     FileFunc : 定义栈头文件   
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 09:33:48  
  7.     Descp    : Linux下栈头文件  
  8. *************************************************************/  
  9. #ifndef   __STACK_H__  
  10. #define   __STACK_H__  
  11.   
  12. #ifdef __cplusplus  
  13. extern "C" {  
  14. #endif  
  15.   
  16. #include "tree.h"  
  17.   
  18. #define STACK_SIZE 128  
  19. #define STACK_INCREMENT_SIZE 128  
  20.   
  21. typedef pTree ElemType;  
  22.   
  23. typedef struct stack  
  24. {  
  25.     ElemType *bottom;  
  26.     int top;  
  27.     int size;  
  28. }sStack,*pStack;  
  29.   
  30. void init_stack(pStack *p);  
  31. int isEmpty(pStack p);  
  32. int isFull(pStack p);  
  33. int push(pStack,ElemType e);  
  34. int pop(pStack p,ElemType *e);  
  35. int getTop(pStack p,ElemType *e);  
  36.   
  37. #ifdef __cplusplus  
  38. }  
  39. #endif  
  40.   
  41. #endif  


 

 

//stack.c

  1. /************************************************************* 
  2.     FileName : stack.c  
  3.     FileFunc : 定义实现栈函数  
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 09:33:29  
  7.     Descp    : Linux下实现栈函数 
  8. *************************************************************/  
  9. #include <stdlib.h>  
  10. #include "stack.h"  
  11.   
  12. /*栈先进后出*/  
  13. void init_stack(pStack *p)  
  14. {  
  15.     *p = malloc(sizeof(sStack));  
  16.     (*p)->bottom = malloc(sizeof(ElemType)*STACK_SIZE);  
  17.     (*p)->top = -1;  
  18.     (*p)->size = STACK_SIZE;  
  19. }  
  20.   
  21. /*判断栈是否为空*/  
  22. int isEmpty(pStack p)  
  23. {  
  24.     if( -1==p->top )  
  25.         return 1;  
  26.   
  27.     return 0;  
  28.   
  29. }  
  30.   
  31. /*判断栈是否已满*/  
  32. int isFull(pStack p)  
  33. {  
  34.     if( (p->size-1)==p->top )  
  35.         return 1;  
  36.           
  37.     return 0;  
  38. }  
  39.   
  40. /*入栈*/  
  41. int push(pStack p,ElemType e)  
  42. {  
  43.     if( isFull(p) )  
  44.     {  
  45.         p->bottom = realloc(p->bottom,(p->size+STACK_INCREMENT_SIZE)*sizeof(ElemType));  
  46.         p->size += STACK_INCREMENT_SIZE;  
  47.     }  
  48.       
  49.     p->top++;  
  50.     p->bottom[p->top] = e;  
  51.       
  52.     return 1;  
  53. }  
  54.   
  55. /*出栈*/  
  56. int pop(pStack p,ElemType *e)  
  57. {  
  58.     if(isEmpty(p))  
  59.     {  
  60.         return 0;  
  61.     }  
  62.   
  63.     *e = p->bottom[p->top];  
  64.     p->top--;  
  65.       
  66.     return 1;  
  67. }  
  68.   
  69. /*取栈顶数据*/  
  70. int getTop(pStack p,ElemType *e)  
  71. {  
  72.     if( isEmpty(p) )  
  73.         return -1;  
  74.           
  75.     *e = p->bottom[p->top];  
  76.   
  77.     return 1;  
  78. }  


 

//queue.h

  1. /************************************************************* 
  2.     FileName : queue.h  
  3.     FileFunc : 定义队列头文件   
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 09:51:11  
  7.     Descp    : Linux下队列头文件  
  8. *************************************************************/  
  9. #ifndef   __QUEUE_H__  
  10. #define   __QUEUE_H__  
  11.   
  12. #ifdef __cplusplus  
  13. extern "C" {  
  14. #endif  
  15.   
  16. #include "tree.h"  
  17.   
  18. typedef pTree QueueElem;  
  19.   
  20. typedef struct queue  
  21. {  
  22.     QueueElem data;  
  23.     struct queue *next;  
  24. }sQueue, *pQueue;  
  25.   
  26. void init_queue(pQueue *p, QueueElem data);  
  27. int push_queue(pQueue pq, QueueElem data);  
  28. int pop_queue(pQueue pq, QueueElem *data);  
  29.   
  30.   
  31. #ifdef __cplusplus  
  32. }  
  33. #endif  
  34.   
  35. #endif  


 

//queue.c

  1. /************************************************************* 
  2.     FileName : queue.c  
  3.     FileFunc : 定义实现队列函数   
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 09:51:14  
  7.     Descp    : Linux下实现队列函数 
  8. *************************************************************/  
  9. #include <stdio.h>  
  10. #include <stdlib.h>  
  11. #include "queue.h"  
  12.   
  13. /*队列先进先出*/  
  14. void init_queue(pQueue *p, QueueElem data)  
  15. {  
  16.     *p = malloc(sizeof(sQueue));  
  17.     (*p)->data = data;  
  18.     (*p)->next = NULL;  
  19. }  
  20.   
  21. /*进队列,进来的数据放入队列最后*/  
  22. int push_queue(pQueue pq, QueueElem ptree)  
  23. {  
  24.     pQueue ptrav = pq, pnew;  
  25.     if ( NULL==pq )  
  26.     {  
  27.         return 0;  
  28.     }  
  29.     while ( NULL!=ptrav->next )  
  30.     {  
  31.         ptrav = ptrav->next;  
  32.     }  
  33.       
  34.     init_queue(&pnew, ptree);  
  35.     ptrav->next = pnew;  
  36.       
  37.     return 1;  
  38. }  
  39.   
  40. /*出队列,把队列中第一个数据出队列*/  
  41. int pop_queue(pQueue pq, QueueElem *data)  
  42. {  
  43.     pQueue pdel;  
  44.       
  45.     if ( pq == NULL )  
  46.     {  
  47.         return -1;  
  48.     }  
  49.       
  50.     if ( pq->next == NULL )  
  51.     {  
  52.         return 0;  
  53.     }  
  54.     pdel = pq->next;  
  55.     *data = pdel->data;  
  56.     pq->next = pdel->next;  
  57.     free(pdel);  
  58.       
  59.     return 1;  
  60. }  


 

 

//tree.h

  1. /************************************************************* 
  2.     FileName : tree.h  
  3.     FileFunc : 定义二叉树头文件   
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 09:58:03  
  7.     Descp    : Linux下二叉树头文件  
  8. *************************************************************/  
  9. #ifndef   __TREE_H__  
  10. #define   __TREE_H__  
  11.   
  12. #ifdef __cplusplus  
  13. extern "C" {  
  14. #endif  
  15.   
  16. #include <stdio.h>  
  17.   
  18. typedef unsigned char etype;  
  19. typedef int type;  
  20.   
  21. typedef struct TreeNode  
  22. {  
  23.     etype data;  
  24.     type count;  
  25.     struct TreeNode *next;  
  26.     struct TreeNode *left;  
  27.     struct TreeNode *right;  
  28. }Tree,*pTree;  
  29.   
  30. void Init_TreeNode(pTree *p);  
  31. void Init_eTreeNode(pTree *p,etype data);  
  32. int Read_File(pTree proot,FILE *pr,FILE *pw);  
  33. pTree Get_Frequency(pTree proot);  
  34. void Huffman(pTree *proot);  
  35. void Read_Huffman(pTree proot,int n,FILE *pr,FILE *pw);  
  36. void Create_Huffman(pTree proot,int ch,FILE *pr);  
  37. void ReHuffman(pTree proot,FILE *pr,FILE *pw,int count,int Num_Byte);  
  38.   
  39. #ifdef __cplusplus  
  40. }  
  41. #endif  
  42.   
  43. #endif  


 

 

//tree.c

  1. /************************************************************* 
  2.     FileName : tree.c  
  3.     FileFunc : 定义实现二叉树函数   
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 09:58:00  
  7.     Descp    : Linux下实现二叉树函数 
  8. *************************************************************/  
  9. #include <stdio.h>  
  10. #include <stdlib.h>  
  11. #include "tree.h"  
  12. #include "stack.h"  
  13. #include "queue.h"  
  14.   
  15. /*初始化树的结点*/  
  16. void Init_TreeNode(pTree *p)  
  17. {  
  18.     *p=malloc(sizeof(Tree));  
  19.     (*p)->data = 0;  
  20.     (*p)->count = 0;  
  21.     (*p)->left = NULL;  
  22.     (*p)->right = NULL;  
  23.     (*p)->next = NULL;  
  24. }  
  25.   
  26. /*初始化树的结点数据*/  
  27. void Init_eTreeNode(pTree *p,etype data)  
  28. {  
  29.     *p = malloc(sizeof(Tree));  
  30.     (*p)->data = data;  
  31.     (*p)->count = 1;;  
  32.     (*p)->left = NULL;  
  33.     (*p)->right = NULL;  
  34.     (*p)->next = NULL;  
  35. }  
  36.   
  37. /*取原文件数据构造树型链表*/  
  38. int Read_File(pTree proot,FILE *pr,FILE *pw)  
  39. {  
  40.     pTree p,pnew;  
  41.     unsigned char ch;  
  42.       
  43.     if( NULL==proot )  
  44.         return 0;  
  45.           
  46.     /*静态统计模型*/  
  47.     /*统计原始数据中各字符出现的频率(即个数)*/  
  48.     while( fread(&ch,sizeof(unsigned char),1,pr)>0 )  
  49.     {  
  50.         printf("%c",ch);  
  51.           
  52.         for(p=proot; p->next!=NULL; p=p->next)  
  53.         {  
  54.             if(p->next->data==ch)  
  55.             {  
  56.                 (p->next->count)++;  
  57.                 break;  
  58.             }  
  59.         }     
  60.               
  61.         if( ( NULL==p->next) && (ch!=p->data) )  
  62.         {  
  63.             Init_eTreeNode(&pnew,ch);  
  64.             p->next = pnew;  
  65.         }  
  66.     }  
  67.   
  68.     printf("\n");  
  69.     int total = 0,num = 0;  
  70.       
  71.     /*统计原始数据中不同字符出现的个数以及所有字符出现的总的次数*/  
  72.     for(p=proot->next; p!=NULL; p=p->next)  
  73.     {  
  74.         fwrite(&p->data,sizeof(char),1,pw);        
  75.         fwrite(&p->count,sizeof(int),1,pw);        
  76.         printf("%c:%d\n",p->data,p->count);  
  77.         total += p->count;  
  78.         num++;  
  79.     }  
  80.     printf("total:%d num:%d\n",total,num);  
  81.     return num;  
  82. }  
  83.   
  84. /*从树型链表中找出字符频率出现最小的结点*/  
  85. pTree Get_Frequency(pTree proot)  
  86. {  
  87.     if( NULL==proot->next )   
  88.         return NULL;  
  89.           
  90.     pTree p,ps = proot,min = proot->next,prev;  
  91.     for(prev=proot; prev->next!=NULL; prev=prev->next)  
  92.     {  
  93.         p = prev->next;  
  94.         if( p->count<min->count )  
  95.         {  
  96.             min = p;  
  97.             ps = prev;  
  98.         }  
  99.     }  
  100.   
  101.     ps->next = min->next;  
  102.     printf("huffman:%d",min->count);  
  103.     return min;   
  104. }  
  105.   
  106. /*构造最小二叉树*/  
  107. void Huffman(pTree *proot)  
  108. {  
  109.     pTree min1,min2;  
  110.     pTree pnew,p;  
  111.   
  112.     while( ((min1=Get_Frequency(*proot))!=NULL) && ((min2=Get_Frequency(*proot))!=NULL) )  
  113.     {     
  114.         Init_TreeNode(&pnew);  
  115.         puts("*");  
  116.         pnew->left = min1;  
  117.         pnew->right = min2;  
  118.         pnew->count = min1->count+min2->count;  
  119.         min1->next = pnew;  
  120.         min2->next = pnew;  
  121.         p = (*proot)->next;  
  122.         (*proot)->next = pnew;  
  123.         pnew->next = p;  
  124.     }  
  125.   
  126.     free(*proot);  
  127.     *proot = min1;  
  128.     puts("----");  
  129. }  
  130.   
  131. /*对二叉树进行编码,得到各个字符的编码格式写到压缩后的文件中*/  
  132. void Read_Huffman(pTree proot,int n,FILE *pr,FILE *pw)  
  133. {  
  134.     unsigned char bigcode = 0;  
  135.     pTree pnew,pp,pc;  
  136.     Init_eTreeNode(&pnew,0);  
  137.       
  138.     pStack ps;  
  139.     init_stack(&ps);  
  140.       
  141.     pQueue p;  
  142.     init_queue(&p,NULL);  
  143.   
  144.     int count = 0,Num_Byte = 1;  
  145.     unsigned char ch;  
  146.       
  147.     while( fread(&ch,sizeof(char),1,pr)>0 )  
  148.     {  
  149.         push_queue(p,proot);  
  150.           
  151.         while( pop_queue(p,&pnew) )  
  152.         {  
  153.             if( NULL==pnew->left )  
  154.             {  
  155.                 if( ch==pnew->data )/*找到队列中的匹配字符*/  
  156.                 {  
  157.                     /*printf("ch = %c \n",ch);*/  
  158.                     while( NULL!=pnew )/*父结点全部压栈,以便编码*/  
  159.                     {  
  160.                         push(ps,pnew);  
  161.                         pnew=pnew->next;  
  162.                     }  
  163.                       
  164.                     pop(ps,&pp);  
  165.                     while( pop(ps,&pc) )  
  166.                     {  
  167.                         if( 8==count )  
  168.                         {     
  169.                             fwrite(&bigcode,sizeof(char),1,pw);  
  170.                             count = 0;  
  171.                             bigcode = 0;Num_Byte++;       
  172.                         }  
  173.                         if( pp->left==pc )/*判断是左结点还是右结点,左结点上为0,右结点上为1*/  
  174.                         {  
  175.                                 bigcode = (bigcode<<1)+0;  
  176.                                 count++;  
  177.                         }  
  178.                         else  
  179.                         {  
  180.                                 bigcode = (bigcode<<1)+1;  
  181.                                 count++;              
  182.                         }  
  183.   
  184.                         pp = pc;  
  185.                     }  
  186.                       
  187.                     while( pop_queue(p,&pnew) );/*其他字符全部出队列*/  
  188.   
  189.                 }  
  190.             }  
  191.             else   
  192.             {  
  193.                 push_queue(p,pnew->right);  
  194.                 push_queue(p,pnew->left);  
  195.             }  
  196.         }  
  197.     }  
  198.       
  199.     bigcode = bigcode<<(8-count);  
  200.     fwrite(&bigcode,sizeof(char),1,pw);  
  201.     printf("bigcode=%d\n",bigcode);  
  202.       
  203.     int info0 = n;  
  204.     int info1 = count;  
  205.     int info2 = Num_Byte;  
  206.     fwrite(&info0,sizeof(int),1,pw);  
  207.     fwrite(&info1,sizeof(int),1,pw);  
  208.     fwrite(&info2,sizeof(int),1,pw);  
  209. }  
  210.   
  211. /*取压缩文件的数据构造树型链表*/  
  212. void Create_Huffman(pTree proot,int ch,FILE *pr)  
  213. {  
  214.   
  215.     if( NULL==proot )  
  216.         return ;  
  217.           
  218.     etype data;type count;  
  219.   
  220.     printf("ch=%d\n",ch);  
  221.     pTree p = proot,pnew;  
  222.       
  223.     while( ch )  
  224.     {  
  225.         fread(&data,sizeof(etype),1,pr);  
  226.         fread(&count,sizeof(type),1,pr);  
  227.       
  228.         Init_eTreeNode(&pnew,data);  
  229.         pnew->data = data;  
  230.         pnew->count = count;  
  231.         p->next = pnew;  
  232.         p = pnew;  
  233.         ch--;  
  234.     }  
  235.       
  236.     int total = 0,num = 0;  
  237.     for(p=proot->next; p!=NULL; p=p->next)  
  238.     {  
  239.         total += p->count;  
  240.         num++;  
  241.     }  
  242.       
  243.     printf("total:%d num:%d\n",total,num);  
  244.       
  245. }  
  246.   
  247. /*取压缩的文件二叉树编码,对其解压数据*/  
  248. void ReHuffman(pTree proot,FILE *pr,FILE *pw,int count ,int Num_Byte)  
  249. {  
  250.     pTree p = proot;  
  251.       
  252.     unsigned char ch,chcpy[8];  
  253.     int n;  
  254.     while( --Num_Byte&&fread(&ch,sizeof(unsigned char),1,pr)>0 )  
  255.     {  
  256.         printf("0x%x\n",ch);  
  257.         chcpy[0] = ch&128;  
  258.         chcpy[1] = ch&64;  
  259.         chcpy[2] = ch&32;  
  260.         chcpy[3] = ch&16;  
  261.         chcpy[4] = ch&8;  
  262.         chcpy[5] = ch&4;  
  263.         chcpy[6] = ch&2;  
  264.         chcpy[7] = ch&1;  
  265.           
  266.         for(n=0; n<8; n++)     
  267.             printf("%d--",chcpy[n]);  
  268.               
  269.         n = 0;  
  270.         while( n<8 )  
  271.         {  
  272.             if( NULL==p->left )  
  273.             {  
  274.                 printf("\n%d\n",n);  
  275.                 printf("%d\n",chcpy[n]);  
  276.                 printf("%c\n",p->data);  
  277.                 fwrite(&p->data,sizeof(unsigned char ),1,pw);  
  278.                 p = proot;  
  279.                 continue;  
  280.             }  
  281.               
  282.             if( chcpy[n] )  
  283.             {  
  284.                 p = p->right;  
  285.             }  
  286.             else   
  287.             {  
  288.                 p = p->left;  
  289.             }  
  290.               
  291.             n++;  
  292.         }  
  293.     }  
  294.   
  295.     fread(&ch,sizeof(unsigned char),1,pr);  
  296.     chcpy[0] = ch&128;  
  297.     chcpy[1] = ch&64;  
  298.     chcpy[2] = ch&32;  
  299.     chcpy[3] = ch&16;  
  300.     chcpy[4] = ch&8;  
  301.     chcpy[5] = ch&4;  
  302.     chcpy[6] = ch&2;  
  303.     chcpy[7] = ch&1;  
  304.       
  305.     for(n=0; n<8; n++)     
  306.         printf("%d--",chcpy[n]);  
  307.       
  308.     n = 0;  
  309.     while( n<count )  
  310.     {  
  311.         if( NULL==p->left )  
  312.         {  
  313.             printf("%c:\n",p->data);  
  314.             fwrite(&p->data,sizeof(char),1,pw);  
  315.             p = proot;  
  316.             continue;  
  317.         }  
  318.               
  319.         if(chcpy[n])  
  320.         {  
  321.             p = p->right;  
  322.         }  
  323.         else   
  324.         {  
  325.             p = p->left;  
  326.         }  
  327.         n++;  
  328.     }  
  329.       
  330. }  


 

 

//demo.c

  1. /************************************************************* 
  2.     FileName : demo.c  
  3.     FileFunc : 定义实现Huffman算法   
  4.     Version  : V0.1   
  5.     Author   : Sunrier   
  6.     Date     : 2012-07-09 10:52:17  
  7.     Descp    : Linux下实现Huffman算法压缩/解压文件  
  8. *************************************************************/  
  9. #include <stdio.h>  
  10. #include "tree.h"  
  11. #include "queue.h"  
  12.   
  13. int main(int argc,char *argv[])  
  14. {  
  15.     FILE *pr,*pw;  
  16.     pTree proot;  
  17.       
  18.     Init_TreeNode(&proot);  
  19.       
  20.     int num = 0;  
  21.       
  22.     if( argc<4 )  
  23.     {  
  24.         fprintf(stderr,"Usage: \n ");  
  25.         fprintf(stderr," Compress : %s c sourcefile destfile \n", argv[0]);  
  26.         fprintf(stderr," Decompress : %s d sourcefile destfile \n", argv[0]);  
  27.         return 1;  
  28.     }  
  29.       
  30.     if'c'==*argv[1] )/*表示压缩文件*/  
  31.     {  
  32.         pr = fopen(argv[2],"r");  
  33.         if( NULL==pr )  
  34.         {  
  35.             perror("Read file failed !\n");  
  36.             return -1;  
  37.         }  
  38.           
  39.         pw = fopen(argv[3],"w");  
  40.         if( NULL==pw )  
  41.         {  
  42.             perror("Write file failed !\n");  
  43.             return 1;  
  44.         }  
  45.           
  46.         num = Read_File(proot,pr,pw);  
  47.         Huffman(&proot);  
  48.         fseek(pr,0,SEEK_SET);  
  49.         Read_Huffman(proot,num,pr,pw);  
  50.     }  
  51.     else if('d'==*argv[1])/*表示解压文件*/  
  52.     {  
  53.         int count,Num_Byte,ch;  
  54.           
  55.         pr = fopen(argv[2],"r");  
  56.         if( NULL==pr )  
  57.         {  
  58.             perror("Read file failed !\n");  
  59.             return 1;  
  60.         }  
  61.           
  62.         fseek(pr,-12,SEEK_END);  
  63.         fread(&ch,sizeof(int),1,pr);  
  64.         fread(&count,sizeof(int),1,pr);  
  65.         fread(&Num_Byte,sizeof(int),1,pr);  
  66.         printf("%d/%d/%d\n",ch,count,Num_Byte);  
  67.           
  68.         fseek(pr,0,SEEK_SET);  
  69.         Create_Huffman(proot,ch,pr);  
  70.         Huffman(&proot);  
  71.         fseek(pr,(sizeof(int)+sizeof(char))*ch,SEEK_SET);  
  72.         pw = fopen(argv[3],"w");  
  73.         if( NULL==pw )  
  74.         {  
  75.             perror("Write file failed !\n");  
  76.             return 1;  
  77.         }  
  78.           
  79.         ReHuffman(proot,pr,pw,count,Num_Byte);  
  80.     }  
  81.     else  
  82.     {  
  83.         fprintf(stderr,"Usage: \n ");  
  84.         fprintf(stderr," Compress : %s c sourcefile destfile \n", argv[0]);  
  85.         fprintf(stderr," Decompress : %s d sourcefile destfile \n", argv[0]);  
  86.         return 1;  
  87.     }  
  88.   
  89.     return 0;  
  90. }  


 

 

//makefile

  1. #makefile    
  2. OBJS = demo      
  3. all:$(OBJS)      
  4. #CFLAGS = -O -w -ansi         
  5. #CFLAGS = -O -Wall -ansi   
  6. CFLAGS = -g -Wall -ansi         
  7. CC = gcc $(CFLAGS)    
  8. #SRCS = *.c  
  9. SRCS = demo.c tree.c stack.c queue.c  
  10.   
  11. demo:$(SRCS)  
  12.     @$(CC) -o $@ $?   
  13. clean   :  
  14.     @ls | grep -v ^makefile$$ | grep -v [.]c$$ | grep -v [.]h$$ | grep -v [.]sql$$ | grep -v [.]sh$$ | xargs rm -rf  
  15. #makefile     


 

[Sunrier@localhost Huffman]$ ls
demo.c  makefile  queue.c  queue.h  stack.c  stack.h  tree.c  tree.h
[Sunrier@localhost Huffman]$ make
[Sunrier@localhost Huffman]$ ls
demo  demo.c  makefile  queue.c  queue.h  stack.c  stack.h  tree.c  tree.h
[Sunrier@localhost Huffman]$ ./demo c demo.c 1
.................................
.................................
.................................
[Sunrier@localhost Huffman]$ ls
1  demo  demo.c  makefile  queue.c  queue.h  stack.c  stack.h  tree.c  tree.h
[Sunrier@localhost Huffman]$
[Sunrier@localhost Huffman]$ ./demo d 1 1.c
.................................
.................................
.................................
[Sunrier@localhost Huffman]$ ls
1  1.c  demo  demo.c  makefile  queue.c  queue.h  stack.c  stack.h  tree.c  tree.h
[Sunrier@localhost Huffman]$

 

注:此程序功能对于大文件的压缩和解压还无法实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值