#头歌 数据结构 实验三 线性表综合应用

第1关:循环链表

任务描述

本关任务:根据所学循环链表的基础知识,完成循环链表删除数据功能的程序编写并通过所有测试用例。

相关知识

为了完成本关任务,你需要掌握:1.如何获取数组的长度,2.如何遍历数组。

循环链表简介

简单来说,单链表像一个小巷,无论怎么样最终都能从一端走到另一端,循环链表则像一个有传送门的小巷,因为循环链表当你以为你走到结尾的时候,其实你又回到了开头。循环链表和非循环链表其实创建的过程以及思路几乎完全一样,唯一不同的是,非循环链表的尾结点指向空(NULL),而循环链表的尾指针指向的是链表的开头。通过将单链表的尾结点指向头结点的链表称之为循环单链表(Circular linkedlist)。

图 1 循环链表

如图1所示,循环链表将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环。循环链表与单链表的主要差异在于循环的判断上,原来是判断p->next是否为空,现在则是p->next不等于头结点,则循环未结束。

循环链表的实现
1、创建链表

如同单链表的创建,我们需要先创建一个头结点并且给其开辟内存空间,但与单链表不同的是,我们需要在开辟内存空间成功之后将头结点的next指向head自身。当需要进行插入时,我们首先创建一个新的节点,将原有链表尾结点的next指针修改指向到新的结点,新结点的next指针再重新指向头部结点,然后逐步进行这样的插入操作,最终完成整个单项循环链表的创建。代码示例如下:

 
  1. int insert_list(list *head){
  2. int data; //插入的数据类型
  3. printf("请输入要插入的元素:");
  4. scanf("%d",&data);
  5. list *node=initlist();
  6. node->data=data; //初始化一个新的结点,准备进行链接
  7. if(head!=NULL){
  8. list *p=head;
  9. //找到最后一个数据
  10. while(p->next!=head){
  11. p=p->next;
  12. }
  13. p->next=node;
  14. node->next=head;
  15. return 1;
  16. }else{
  17. printf("头结点已无元素\n");
  18. return 0;
  19. }
  20. }
2、删除操作

如图2所示,循环单链表的删除操作可以参考单链表的删除操作,其都是找到需要删除的结点,将其前一个结点的next指针直接指向删除结点的下一个结点即可,但需要注意的是尾节点和头结点的特判,尤其是尾结点,因为删除尾节点后,尾节点前一个结点就成了新的尾节点,这个新的尾节点需要指向的是头结点而不是空,其重点可以记录为当前的前一节点.next=自身结点.next这样的操作可以省去头尾结点的特判。

图 2 循环链表的删除操作

示例代码:

 
  1. int delete_list(list *head) {
  2. if(head == NULL) {
  3. printf("链表为空!\n");
  4. return 0;
  5. }
  6. list *temp = head;
  7. list *ptr = head->next;
  8. int del;
  9. printf("请输入你要删除的元素:");
  10. scanf("%d",&del);
  11. while(ptr != head) {
  12. if(ptr->data == del) {
  13. if(ptr->next == head) {
  14. temp->next = head;
  15. free(ptr);
  16. return 1;
  17. }
  18. temp->next = ptr->next;//核心删除操作代码
  19. free(ptr);
  20. //printf("元素删除成功!\n");
  21. return 1;
  22. }
  23. temp = temp->next;
  24. ptr = ptr->next;
  25. }
  26. printf("没有找到要删除的元素\n");
  27. return 0;
  28. }

编程要求

在右侧编辑器中的 Begin-End 之间补充 C 语言代码,完成对循环链表删除功能的实现,其数据内容通过 scanf 从后台获取。

测试说明

平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。

测试输入:

 
  1. 9 8 10 2 0 // 0是结束输入的信号

预期输出:

 
  1. 输入结点数据中...
  2. --------循环链表初始元素------
  3. 9 8 10 2
  4. --------删除第二个结点后------
  5. 9 10 2

开始你的任务吧,祝你成功!

截止后通关代码

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include<stdlib.h>

#define ERROR 0

#define OK 1

typedef int EleType;

typedef struct CLinkNode

{

    EleType data;

    struct CLinkNode *next;

}CLinkNode,*CLinkList;

/*

初始化循环链表

*/

int InitCLinkList(CLinkList *list)

{

    if (list == NULL)

    {

        return ERROR;

    }

    int data = 0;

    CLinkNode* target = NULL;

    CLinkNode* head_node = NULL;

    printf("输入结点数据中...\n");

    while (1)

    {

        scanf("%d", &data);

        if (data == 0)

        {

            //退出循环标志,用户输入0 表示结束输入数据

            break;

        }

        if (*list == NULL)

        {

            CLinkNode* head= (CLinkNode*)malloc(sizeof(CLinkNode));

            //分配结点空间失败

            if (head == NULL)

            {

                exit(0);

            }

            *list = head;//链表指向头结点

            CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));

            if (node == NULL)

            {

                exit(0);

            }

            node->data = data;

            node->next = head;

            head->next = node;

        }

        else

        {

            for (target = (*list)->next; target->next != *list; target = target->next);

            head_node = target->next;

            CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));

            if (node == NULL)

            {

                exit(0);

            }

            node->data = data;

            node->next = head_node;

            target->next = node;//将新结点插入尾部

        }

    }

    return OK;

}

/*

往链表指定位置插入数据

list 循环链表

loc 第loc位置插入元素,loc 从1 开始计数

data 插入元素的数据域

*/

int InsertCLinkNode(CLinkList list,int loc, EleType data)

{

    if (list == NULL || loc < 1)

        return ERROR;

    /*

    循环目的:找到第loc-1位置结点

    */

    int i = 1;

    CLinkNode* node = list;//刚开始node指向头结点

    while (node->next!=list && i < loc)

    {

        node = node->next;

        i++;

    }

    if (i == loc)

    {

        CLinkNode* new_node = (CLinkNode*)malloc(sizeof(CLinkNode));

        if (new_node == NULL)

        {

            exit(0);

        }

        new_node->data = data;

        new_node->next = node->next;//新结点指针域 指向前驱结点的后继结点

        node->next = new_node;//将新结点加入链表

    }

    else

    {

        return  ERROR;

    }

    return OK;

}

/*

删除指定结点,通过指针返回删除结点的数据,并保存至data

*/

int DelCLinkNode(CLinkList list,int loc, EleType* data)

{

    if (list == NULL || loc < 1)

        return ERROR;

    /*

    循环目的:找到第loc-1位置结点

    */

    int i = 1;// 按人类的读法 i表示第i个位置 和 loc 表达意思一致

    CLinkNode* node = list;//刚开始node指向头结点

    while (node->next != list && i < loc)

    {

        node = node->next;

        i++;

    }

    //循环结束 node 指向 loc-1 位置 且 node 不能为尾结点,为什么不能为尾结点?因为不能删除 位置上没有元素的结点!

    if (i == loc && node->next != list)

    {

        // 请在下面的Begin-End之间补充代码,完成对结点的删除。

        /********** Begin *********/

    CLinkNode *r;

    r=node->next;

    node->next=r->next;

    free(r);

        /********** End **********/

    }

    return OK;

}

/*

展示循环链表元素

*/

int ShowCLinkList(CLinkList list)

{

    if (list == NULL)

    {

        return ERROR;

    }

    CLinkNode* target = NULL;

   

    for (target = list->next; target != list; target = target->next)

        printf("%d \t",target->data);

    printf("\n");

    return OK;

}

int main(int argc, char *argv[])

{

    int flag = 0;

    CLinkList list = NULL;

    list = NULL;

    InitCLinkList(&list);

    printf("--------循环链表初始元素------\n");

    ShowCLinkList(list);

    int loc = 2;

    int data = 0;

    DelCLinkNode(list, loc, &data);

    printf("--------删除第二个结点后------\n");

    ShowCLinkList(list);

    return 0;

}

第2关:双向链表

任务描述

本关任务:根据所学双向链表的基础知识,完成双向链表插入结点功能的程序编写并通过所有测试用例。

相关知识

为了完成本关任务,你需要掌握:

1、双向链表的基本概念;

2、双向链表的实现。

双向链表简介

双向链表可以简称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。使用这种数据结构,我们可以不再拘束于单链表的单向创建于遍历等操作,大大减少了在使用中存在的问题。

图 1 双链表结点

在单链表中,我们有一个数据域,还有一个指针域,数据域用来存储相关数据,而指针域则负责链表之间的“联系”。而在双向链表中,如图1所示,我们需要有两个指针域,一个负责向后连接,一个负责向前连接。一个完整的双向链表中应该是头结点的pre指针指为空,尾结点的next指针指向空,其余结点前后相链。双向链表中的结点可用代码表示为:

 
  1. typedef struct List{
  2. int data; // 数据域
  3. struct List *next; // 向后的指针
  4. struct List *front; // 向前的指针
  5. };
双链表的实现
1、创建双链表

对于创建双向链表,我们需要先创建头结点再逐步的进行添加,请注意,双向链表的头结点是有数据元素的,也就是头结点的data域中是存有数据的,这与一般的单链表是不同的。对于逐步添加数据,我们采取的做法是,开辟一段新的内存空间作为新的结点,为这个结点的data进行赋值,然后将已有链表的上一个结点的next指针指向自身,自身的pre指针指向上一个结点。参考代码如下:

 
  1. //创建双链表
  2. line* initLine(line * head){
  3. int number,pos=1,input_data;
  4. //三个变量分别代表结点数量,当前位置,输入的数据
  5. printf("请输入创建结点的大小\n");
  6. scanf("%d",&number);
  7. if(number<1){
  8. return NULL;
  9. } //输入非法直接结束
  10. head=(line*)malloc(sizeof(line)); //头结点创建
  11. head->pre=NULL;
  12. head->next=NULL;
  13. printf("输入第%d个数据\n",pos++);
  14. scanf("%d",&input_data);
  15. head->data=input_data;
  16. line * list=head;
  17. while (pos<=number) {
  18. line * body=(line*)malloc(sizeof(line));
  19. body->pre=NULL;
  20. body->next=NULL;
  21. printf("输入第%d个数据\n",pos++);
  22. scanf("%d",&input_data);
  23. body->data=input_data;
  24. list->next=body;
  25. body->pre=list;
  26. list=list->next;
  27. }
  28. return head;
  29. }
2、插入操作

对于每一次双向链表的插入操作,我们首先需要创建一个独立的结点并通过malloc操作开辟相应的空间,其次我们选中这个新创建的独立节点,将其的pre指针指向所需插入位置的前一个结点,同时,其所需插入的前一个结点的next指针修改指向为该新的结点,同理,该新的结点的next指针将会指向一个原本的下一个结点,而修改下一个结点的pre指针为指向新结点自身,这样的一个操作我们称之为双向链表的插入操作。

图 2 双链表的插入

3、删除操作

如图3所示,双链表的删除操作过程为:选择需要删除的结点,选中这个结点的前一个结点,将前一个结点的next指针指向自己的下一个结点,同时,选中该节点的下一个结点,将下一个结点的pre指针修改指向为自己的上一个结点,这样产生的效果就是在进行遍历的时候直接将这一个结点给跳过了。在这样的指针修改操作之后,我们释放删除结点,归还空间给内存,这样的操作我们称之为双链表的删除操作。

图 3 双链表的删除

4、遍历

如同单链表的遍历一样,利用next指针逐步向后进行索引即可,注意判断这里,我们既可以用while(list)的操作直接判断是否链表为空,也可以使用while(list->next)的操作判断该链表是否为空,其下一节点为空和本结点是否为空的判断条件是一样的效果,当然了,善用双向链表的pre指针进行有效的遍历也是值得去尝试的。

编程要求

在右侧编辑器中的 Begin-End 之间补充 C 语言代码,完成对双向链表插入结点功能的实现,其数据内容通过 scanf 从后台获取。

测试说明

平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。

测试输入:

 
  1. 31 32 1 7 3 0

预期输出:

 
  1. 输入数据中...
  2. 链表结构为:31 <-> 32 <-> 1 <-> 7 <-> 3 <-> 0
  3. 链表中第 4 个节点的直接前驱是:1

开始你的任务吧,祝你成功!

截止后通关代码:

#include <stdio.h>

#include <stdlib.h>

//节点结构

typedef struct line {

    struct line * prior;

    int data;

    struct line * next;

}line;

//双链表的创建函数

line* initLine(line * head);

//输出双链表的函数

void display(line * head);

int main() {

    //创建一个头指针

    line * head = NULL;

    //调用链表创建函数

    head = initLine(head);

    printf("链表结构为:");

    //输出创建好的链表

    display(head);

    //显示双链表的优点

    printf("链表中第 4 个节点的直接前驱是:%d", head->next->next->next->prior->data);

    return 0;

}

line* initLine(line * head) {

    printf("输入数据中...\n");

    int data[6]={0};

    for(int i=0;i<6;i++){

        scanf("%d",&data[i]);

    }

    line * list = NULL;

    //创建一个首元节点,链表的头指针为head

    head = (line*)malloc(sizeof(line));

    //对节点进行初始化

    head->prior = NULL;

    head->next = NULL;

    head->data = data[0];

    //声明一个指向首元节点的指针,方便后期向链表中添加新创建的节点

    list = head;

    for (int i = 1; i <= 5; i++) {

        // 请在下面的Begin-End之间补充代码,插入结点,其中结点数据为data[i]。

        /********** Begin *********/

    line *s =(line*)malloc(sizeof(line));

    s->prior = NULL;

    s->next = NULL;

    s->data=data[i];

    if(list==NULL){

        list=s;

    }

    else{

        list->next=s;

        s->prior=list;

        list=s;

    }

        /********** End **********/

    }

    //返回新创建的链表

    return head;

}

void display(line * head) {

    line * temp = head;

    while (temp) {

        //如果该节点无后继节点,说明此节点是链表的最后一个节点

        if (temp->next == NULL) {

            printf("%d\n", temp->data);

        }

        else {

            printf("%d <-> ", temp->data);

        }

        temp = temp->next;

    }

}

第3关:线性表综合应用

任务描述

本关任务:根据所学链表的基础知识,完成基于链表进行一元多项式相加的程序编写并通过所有测试用例。

相关知识

为了完成本关任务,你需要掌握:

1、如何表示一元多项式;

2、一元多项式相加。

一元多项式相加
1、任务描述

求两个一元多项式 A(x)=a0​+a1​x+a2​x2+…+an​xn 和 B(x)=b0​+b1​x+b2​x2+…+bm​xm 的和。一元多项式相加的运算规则非常简单,两个多项式中指数相同的项对应系数相加,若相加的和不为零,则构成相加结果多项式中的一项,所有指数不相同的项均复制到相加结果多项式中。

2、实现思路

通过链表实现,会更为简单直观。用链表中的每个结点表示多项式中的每一项,多项式每一项都是由数据域(包含系数和指数)和指针域构成的,所以在定义表示结点的结构体时,可如下所示进行定义:

 
  1. typedef struct PLnode{
  2. //数据域,coef 表示系数,expn 表示指数
  3. float coef;
  4. int expn;
  5. //指针域
  6. struct PLnode *next;
  7. }PLnode,*PLinkList;

如图1所示,为一元多项式 A(x)=7+3x+9x8+5x17 和 B(x)=8x+22x7−9x8 的链表示意图。假设指针qaqb分别指向多项式 A 和多项式 B 中当前进行比较的某个结点,则比较两个结点的指数项,有以下3种情况:

  1. 指针 qa 所指结点的指数值小于指针qb所指结点的指数值,则应摘除qa所指结点插入到“和多项式”链表中去;

  2. 指针qa所指结点的指数值大于指针qb所指结点的指数值,则应摘除 qb 所指结点插入到“和多项式”链表中去;

  3. 指针 qa 所指结点的指数值等于指针qb所指结点的指数值,则将两个结点的系数相加:若和不为0,则修改qa所指结点的系数值,同时释放qb所指结点;若和为0,则应从多项式 A 的链表中删除相应结点,并释放指针 qaqb 所指结点。

图 1 一元多项式

编程要求

在右侧编辑器中的 Begin-End 之间补充 C 语言代码,完成基于链表的一元多项式相加功能的实现,其数据内容通过 scanf 从后台获取。

测试说明

平台将使用测试集运行你编写的程序代码,若全部的运行结果正确,则通关。

测试输入:

 
  1. 4
  2. 1 9
  3. 2 4
  4. 9 1
  5. 7 4
  6. 1
  7. 9 2

预期输出:

 
  1. La=x^9+2x^4+9x+7x^4
  2. Lb=9x^2
  3. 计算结果为:
  4. Lc=9x^2+x^9+2x^4+9x+7x^4

开始你的任务吧,祝你成功!

截止后通关代码

 #include <stdio.h>

#include <stdlib.h>

typedef struct PLnode{

    //数据域,coef 表示系数,expn 表示指数

    float coef;

    int expn;

    //指针域

    struct PLnode *next;

}PLnode,*PLinkList;

//一元多项式的链表表示创建函数,输入 m 项的系数和指数,建立表示一元多项式的有序链表L

void creatpolyn(PLinkList L, int m){

    int i;

    float coef;

    int expn;

    PLinkList tail,n;

    L->coef = m;

    L->expn = -1;

    tail = L;

    for(i=1 ; i<=m ; i++){

         n = (PLinkList)malloc(sizeof(PLnode));

         scanf("%f",&coef);

         scanf("%d",&expn);

         n->coef = coef;

         n->expn = expn;

         n->next = NULL;

         tail->next = n;

         tail = n;

    }

}

//完成多项式相加运算,即 Lc = La + Lb,并销毁一元多项式 Lb

PLinkList addpolyn(PLinkList La , PLinkList Lb){

    int x,len;

    float y;

    PLinkList Lc,pa,pb,pc,u;

    Lc = La;

    len = 0;

    pc = Lc;

    //另pa,pb 指向La 、Lb 的首元结点

    pa = La->next;

    pb = Lb->next;

    //通过 pa,pb 遍历链表 La、Lb,只有两指针同时存在时,才需要讨论

    while(pa && pb){

        x = pa->expn-pb->expn;

        //判断pa 所指结点的指数与pb 所指结点指数的大小关系

        if(x<0){

            //如果小,则找去 qa 结点到Lc 上

            pc = pa;

            len++;

            pa = pa->next;

        }

        //如果相等,则判断两结点的系数和是否为0

        else if(x == 0){

            // 请在下面的Begin-End之间补充代码,完成一元多项式的相加。

            /********** Begin *********/

y=pa-> coef +pb ->coef;

    if(y != 0)  

    {pa -> coef=y;  

    pc = pa;    

    len++;  

    }else{  

    pc -> next=pa-> next;  

    free(pa);  

    }  

    pa =pc -> next;

    u= pb;  

    pb=pb->next;    

    free(u);


 

            /********** End **********/

        }

        //如果pb 所指结点指数值小,则摘取pb所指结点到 LC链表上

        else{

            u = pb->next;

            pb->next= pa;

            pc->next=pb;

            pc = pb;

            len++;

            pb = u;

        }

    }

    //由于是在 La 上进行一元多项式的加和,所以如果运行过程 pa 不再有结点,而pb 上有,则需要将pb剩余结点链接到 Lc 上

    if(pb){

        pc->next = pb;

    }

    //计算 Lc 的长度

    while(pc){

        pc = pc->next;

        if(pc){

            len++;

        }

    }

    //Lc 的头结点中记录Lc 链表的长度

    Lc->coef = len;

    //加和完成的同时,释放Lb 结点

    free(Lb);

    return Lc;

}

//根据链表存储信息。输出结点 q

void printpoly(PLinkList q){

    if(q->expn == 0){

        printf("%.0f",q->coef);

    }

    else if(q->expn == 1){

        if(q->coef == 1){

            printf("x");

        }

        else if (q->coef == -1){

            printf("-x");

        }

        else{

            printf("%.0f",q->coef);

            printf("x");

        }

    }

    else if (q->coef == 1){

        printf("x^%d",q->expn);

    }

    else if(q->coef == -1){

        printf("-x^%d",q->expn);

    }

    else{

        printf("%.0fx^%d",q->coef,q->expn);

    }

}

//输出一元多项式L

void printpolyn(PLinkList L){

    int n;

    PLinkList p;

    p = L->next;

    n = 0;

    while(p){

        n++;

        if(n == 1){

            printpoly(p);

        }else if(p->coef>0){

            printf("+");

            printpoly(p);

        }else{

            printpoly(p);

        }

        p = p->next;

    }

}

int main(){

    PLinkList La,Lb,Lc;

    int m,n;

    //根据 n 的值,创建链表La

    scanf("%d",&n);

    La = (PLinkList)malloc(sizeof(PLnode));

    creatpolyn(La,n);

    //根据 m 的值,创建 Lb

    scanf("%d",&m);

    Lb = (PLinkList)malloc(sizeof(PLnode));

    creatpolyn(Lb,m);

    //输出La和Lb

    printf("La=");

    printpolyn(La);

    printf("\nLb=");

    printpolyn(Lb);

    //计算La+Lb,结果保存在 Lc中

    printf("\n计算结果为:");

    Lc = addpolyn(La,Lb);

    printf("\nLc=");

    printpolyn(Lc);

    return 0;

}

  • 14
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <stdio.h> #include <stdlib.h> #define MAXSIZE 100 // 线性表的最大长度 typedef struct { int data[MAXSIZE]; // 存储数据元素 int length; // 线性表的当前长度 } SqList; // 初始化线性表 void InitList(SqList* L) { L->length = 0; } // 向线性表中插入元素 int ListInsert(SqList* L, int i, int e) { if (i < 1 || i > L->length + 1) { // 判断 i 的范围是否有效 return 0; } if (L->length >= MAXSIZE) { // 判断线性表是否已满 return 0; } for (int j = L->length; j >= i; j--) { // 将 i 及其之后的元素后移 L->data[j] = L->data[j - 1]; } L->data[i - 1] = e; // 插入新元素 L->length++; // 线性表长度加 1 return 1; } // 从线性表中删除元素 int ListDelete(SqList* L, int i, int* e) { if (i < 1 || i > L->length) { // 判断 i 的范围是否有效 return 0; } *e = L->data[i - 1]; // 将被删除的元素赋值给 e for (int j = i; j < L->length; j++) { // 将 i 之后的元素前移 L->data[j - 1] = L->data[j]; } L->length--; // 线性表长度减 1 return 1; } // 读取线性表元素 void ReadList(SqList* L) { int n, e; printf("请输入线性表的长度:"); scanf("%d", &n); printf("请依次输入线性表的元素:"); for (int i = 1; i <= n; i++) { scanf("%d", &e); ListInsert(L, i, e); } } // 显示线性表元素 void DisplayList(SqList* L) { printf("线性表的元素为:"); for (int i = 0; i < L->length; i++) { printf("%d ", L->data[i]); } printf("\n"); } // 保存线性表到文件中 void SaveList(SqList* L, char* filename) { FILE* fp = fopen(filename, "wb"); // 以二进制写方式打开文件 if (fp == NULL) { printf("打开文件失败!\n"); return; } fwrite(&L->length, sizeof(int), 1, fp); // 写入线性表长度 fwrite(L->data, sizeof(int), L->length, fp); // 写入线性表元素 fclose(fp); // 关闭文件 printf("保存成功!\n"); } // 从文件中读取线性表 void LoadList(SqList* L, char* filename) { FILE* fp = fopen(filename, "rb"); // 以二进制读方式打开文件 if (fp == NULL) { printf("打开文件失败!\n"); return; } fread(&L->length, sizeof(int), 1, fp); // 读取线性表长度 fread(L->data, sizeof(int), L->length, fp); // 读取线性表元素 fclose(fp); // 关闭文件 printf("读取成功!\n"); } int main() { SqList L; InitList(&L); ReadList(&L); DisplayList(&L); SaveList(&L, "list.dat"); InitList(&L); LoadList(&L, "list.dat"); DisplayList(&L); return 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值