数据结构与算法—线性表(C++描述)

目录

一、线性表的类型定义

二、线性表的顺序存储结构及实现

顺序表基本操作的具体代码:

三、线性表的链式存储结构及实现

单链表基本操作的具体代码:


一、线性表的类型定义

线性表是一种线性结构,是n(n≥0)个具有相同属性的数据元素所组成的有限序列
        (a₁,a₂,...,aᵢ₋1,aᵢ,aᵢ₊1,...aₙ) 
        其中n为线性表中数据元素的个数(也为线性表的长度),当n=0时线性表为空表,当n>0时线性表为非空表
        一个数据元素可以由多个数据项组成,数据元素可以是各种类型,但同一张线性表中的所有数据元素类型必须相同

线性表的抽象数据类型定义:
ADT List{
数据对象:D={aᵢ|aᵢ∈DataType, i=0, 1,..., n-1}
数据关系:R={<aᵢ,aᵢ₊1>|aᵢ,aᵢ₊1∈D}
基本操作:
                ListInit(L):创建一个空线性表L
                ListClear(L):清空线性表L中的数据元素
                ListEmpty(L):判断线性表L是否为空表
                ListLength(L):求线性表L中所含数据元素的个数(线性表的长度)
                ListPrint(L):在线性表L不为空表时,按顺序依次输出线性表中的所有数据元素
                ListInsert(L,i,x):插入数据元素(线性表L的第i个数据元素前插入数据元素x)
                ListDelete(L,i,x):删除数据元素(删除线性表L的第i个数据元素,并将值通过x返回)
                ListGet(L,i,x):按位查找(查询线性表L的第i个数据元素的值,并通过x返回)
                ListLocate(L,x):按值查找(查询线性表L中第一个与x值相同的数据元素)
}ADT List

二、线性表的顺序存储结构及实现

顺序存储方式:在内存中用地址连续的有限的一块存储空间顺序存放各个元素
描述顺序结构:①存储空间的起始位置 ②顺序表的当前长度 ③顺序表的容量
优点:①不用为数据元素间的逻辑关系提供额外的存储空间 ②按位查找数据元素效率高
缺点:①执行插入和删除操作时效率低 ②静态存储方式导致存储空间会浪费或不够使用

线性表的顺序存储结构:
内存中的地址空间是线性的,若知道第一个元素的地址(基地址),则可知第i个元素的地址

​​​​​​

顺序存储结构的线性表的类型定义:
使用静态数组定义:

#define MAXSIZE 100 //定义顺序表的最大容量
typedef struct
{
DataType data[MAXSIZE]; //DataType为数据元素的数据类型,data为存放顺序表的数组名
int length; //顺序表的长度,length≤MAXSIZE
}SeqList; //顺序表的名称

顺序表基本操作实现:

①初始化操作:算法的时间复杂度是O(1)

void ListInit(SeqList *L)
{
    L->length=0; //构造一个空的顺序表,长度为0
}

②清空操作
顺序表中变量退出作用域将自动释放变量存储单元

③判空操作:算法的时间复杂度是O(1)

bool ListEmpty(SeqList L)
{
    if(L.length==0) //通过顺序表的长度判断表是否为空
        return true; //返回布尔值
    else
        return false;
}

④求表长操作:算法的时间复杂度是O(1)

int ListLength(SeqList L)
{
    return L.length; //返回顺序表长度
}

⑤遍历操作:算法的时间复杂度是O(n)

void ListPrint(SeqList L)
{
    for(int i=0; i<L.length; i++) //依次输出顺序表中的数据元素
        printf("%d", L.data[i]);
}

⑥插入操作:算法的时间复杂度是O(n)
在顺序表的第i个位置上插入一个值为X的新数据元素

顺序表长由n变为n+1,i的取值范围为1 ≤ i ≤ n+1
当i=n+1时,直接在aₙ后插入新数据元素X
当1≤i≤n时,需要将aᵢ~aₙ的所有数据元素依次后移,为新的数据元素让出位置

bool ListInsert(SeqList *L, int i, DataType x)
{
    int j;
    if (L->length>=MAXSIZE) //检查顺序表是否已满
        return false;
    if(i<0 || i>L->length) //检查插入位置合法性
        return false;
    for(int j=L->length-1; j>=i; j--)
        L->data[j+1]=L->data[j]; //第i个位置后的数组元素依次后移
    L->data[i]=x; //新数据元素插入第i个位置
    L->length++;//顺序表长度+1
    return true;
}

⑦删除操作:算法的时间复杂度是O(n)
将顺序表中第i个数据元素删除

顺序表长由n变为n-1,i的取值范围为1 ≤ i ≤ n
当i<n时,删除数据元素aᵢ需要将aᵢ₊₁~aₙ的所有数据元素依次前移,并修改顺序表长L->length

bool ListDelete(SeqList *L, int i, DataType *x)
{
    if(i<1 || i>L->length) //检查顺序表是否为空表和删除位置合法性
        return false;
    *x=L->data[i-1]; //取得被删除数据元素值
    for(int j=i; j<=L->length-1; j++) //数据元素依次前移
        L->data[j-1]=L->data[j];
    L->length--; //顺序表长度-1
    return true;
}

⑧按位查找操作:算法的时间复杂度是O(1)

bool ListGet(SeqList L, int i, DataType *x)
{
    if(i<1 || i>L.length) //检查顺序表是否为空表和删除位置合法性
        return false;
    else{
        *x=L.data[i-1];
        return true;
    }
}

⑨按值查找操作:算法的时间复杂度是O(n)

int ListLocate(SeqList L, DataType x)
{
    int i=1;
    while(i<=L.length && L.data[i-1]!=x) //遍历顺序表查找数据元素x
        i++;
    if(i<=L.length)
        return i; //返回数据元素的位序
    else
        return 0; //查找失败
}

将两张非递减有序的顺序表La和Lb合并得到一张新非递减有序的顺序表Lc
算法的时间复杂度是O(m+n)

void SeqListMerge(SeqList La, SeqList Lb, SeqList &Lc)
{
    int m=La.length;int n=Lb.length;Lc.length=m+n;
    int i,j,k; i=j=k=0; //初始化
    while(i<m && j<n) //La和Lb均非空
        if(La.data[i]<=Lb.data[j]) //La数据元素值≤Lb数据元素值
            Lc.data[k++]=La.data[i++]; //La中的数据元素插入Lc
        else
            Lc.data[k++]=Lb.data[j++]; //Lb中的数据元素插入Lc
    while(i<m)
        Lc.data[k++]=La.data[i++]; //Lb已空,将La中所有剩余数据元素都插入Lc
    while(j<n)
        Lc.data[k++]=Lb.data[j++]; //La已空,将Lb中所有剩余数据元素都插入Lc
}

顺序表基本操作的具体代码:

#include<stdio.h>
#include<iostream>
using namespace std;

//顺序表的数据元素类型设置为整数
typedef int DataType;

//顺序表存储结构
#define MAXSIZE 100
typedef struct
{
DataType data[MAXSIZE];
int length;
}SeqList;

//初始化空顺序表
void ListInit(SeqList *L)
{
    L->length=0;
}

//判断顺序表是否为空表
bool ListEmpty(SeqList L)
{
    if(L.length==0)
        return true;
    else
        return false;
}

//求顺序表的长度
int ListLength(SeqList L)
{
    return L.length;
}

//遍历顺序表
void ListPrint(SeqList L)
{
    for(int i=0; i<L.length; i++)
        printf("%d", L.data[i]);
}

//顺序表中插入新的数据元素
bool ListInsert(SeqList *L, int i, DataType x)
{
    int j;
    if (L->length>=MAXSIZE)
        return false;
    if(i<0 || i>L->length)
        return false;
    for(int j=L->length-1; j>=i; j--)
        L->data[j+1]=L->data[j];
    L->data[i]=x;
    L->length++;
    return true;
}

//删除顺序表中的数据元素
bool ListDelete(SeqList *L, int i, DataType *x)
{
    if(i<1 || i>L->length)
        return false;
    *x=L->data[i-1];
    for(int j=i; j<=L->length-1; j++)
        L->data[j-1]=L->data[j];
    L->length--;
    return true;
}

//按位查找顺序表中数据元素
bool ListGet(SeqList L, int i, DataType *x)
{
    if(i<1 || i>L.length)
        return false;
    else{
        *x=L.data[i-1];
        return true;
    }
}

//按值查找顺序表中数据元素
int ListLocate(SeqList L, DataType x)
{
    int i=1;
    while(i<=L.length && L.data[i-1]!=x)
        i++;
    if(i<=L.length)
        return i;
    else
        return 0;
}

//将两张非递减有序的顺序表La和Lb合并得到一张新非递减有序的顺序表Lc
void SeqListMerge(SeqList La, SeqList Lb, SeqList &Lc)
{
    int m=La.length;int n=Lb.length;Lc.length=m+n;
    int i,j,k; i=j=k=0;
    while(i<m && j<n)
        if(La.data[i]<=Lb.data[j])
            Lc.data[k++]=La.data[i++];
        else
            Lc.data[k++]=Lb.data[j++];
    while(i<m)
        Lc.data[k++]=La.data[i++];
    while(j<n)
        Lc.data[k++]=Lb.data[j++];
}

int main(){
    SeqList La; //定义一个顺序表La
    ListInit(&La); //初始化顺序表La
    cout<<"判断顺序表La是否为空表(1为空表,0为非空表):"<<ListEmpty(La)<<endl;
    ListInsert(&La,0,1); //在顺序表La中插入数据元素 1
    ListInsert(&La,1,3); //在顺序表La中插入数据元素 3
    ListInsert(&La,2,5); //在顺序表La中插入数据元素 5
    cout<<"插入数据元素后判断顺序表La是否为空表(1为空表,0为非空表):"<<ListEmpty(La)<<endl;
    cout<<"顺序表La中所含数据元素的个数:"<<ListLength(La)<<endl;
    cout<<"输出顺序表La中所有的数据元素:"; ListPrint(La);
    int x; ListGet(La,1,&x); cout<<endl<<"查询顺序表La的第一个数据元素的值:"<<x<<endl;
    cout<<"查询顺序表La中第一个与值为3的数据元素的位置:"<<ListLocate(La,3)<<endl;
    int y; ListDelete(&La,3,&y); cout<<"删除顺序表La中的第三个数据元素,被删除数据元素的值:"<<y<<endl;

    SeqList Lb;
    ListInit(&Lb);
    ListInsert(&Lb,0,1); ListInsert(&Lb,1,2); ListInsert(&Lb,2,3); ListInsert(&Lb,3,4);
    SeqList Lc;
    ListInit(&Lc);

    cout<<"输出顺序表La中所有的数据元素:"; ListPrint(La); cout<<endl;
    cout<<"输出顺序表Lb中所有的数据元素:"; ListPrint(Lb); cout<<endl;
    SeqListMerge(La,Lb,Lc);
    cout<<"输出顺序表Lc中所有的数据元素:"; ListPrint(Lc);

    return 0;
}

三、线性表的链式存储结构及实现

链式存储方式:数据元素用任意的存储单元来存储,逻辑相邻的两个数据元素的存储空间可以连续,也可以不连续
优点:①执行插入和删除操作时效率高 ②动态分配存储空间
缺点:①存储密度不高 ②执行查询操作时效率低
常用的链式存储结构包括:单链表、循环链表和双向链表

线性表的链式存储结构:
指针变量L存放第一个结点的地址,标志线性链表开始
最后一个结点没有后继,指针域为NULL,标志链表结束

链式存储结构的线性表的类型定义:

typedef struct LNode
{
    DataType data; //存储数据元素
    struct LNode *next; //指向后继结点的地址
}LNode, *LinkedList; //LNode是结点的类型,LinkedList是指向LNode类型结点的指针类型

单链表(线性链表(Linear Linked List))的每个数据元素被称为“结点”,每个结点中只有一个指向后继的指针
每个结点至少包括数据域(data存储数据元素信息)指针域(next存储直接后继的存储位置)

线性链表的逻辑表示:

带头结点的单链表:
为了运算方便,在线性链表的第一个结点之前加入一个结点(头结点)
①空单链表:

②非空单链表:

单链表基本操作实现:

采用动态存储表示时,链表结点的存储空间需要在运行中根据需要申请
利用C的内存分配函数malloc()完成,需要包含标准库头文件<stdlib.h>
p = (LNode*)malloc(sizeof(LNode));

        ①申请一块LNode类型的存储单元
        ②将这块存储单元的首地址赋值给变量p

回收内存函数free()能够删除结点

​①初始化操作

void ListInit(LinkedList *L)
{
    *L=(LNode*)malloc(sizeof(LNode)); //申请空间
    (*L)->next=NULL; //置指针域为空指针标识链表结束
}

使用尾插法建立单链表
读入的数据元素的顺序与生成的链表中的数据元素的顺序相同

LinkedList CreatTail(LinkedList &L, DataType a[], int n)
{
	LNode *p, *r;
	int i;
	L = (LNode *)malloc(sizeof(LNode)); //申请头结点
	r = L; //初始化,尾指针指向头结点
	for (i = 0; i < n; i++) //n为要建立的单链表数据元素个数
	{
		p = (LNode *)malloc(sizeof(LNode)); //申请新结点
		p->data = a[i]; //结点数据域赋值
		r->next = p; //在尾部插入新结点
		r = p; //r指向新的尾结点
	}
	r->next = NULL;
	return L;
}

使用头插法建立单链表
读入的数据元素的顺序与生成的链表中的数据元素的顺序相反

LinkedList CreatHead(LinkedList &L,DataType a[], int n)
{
    L=(LNode *)malloc(sizeof(LNode)); //申请头结点
    L->next=NULL; //初始化一个空链表,L为头指针
    for(int i=0;i<n;i++)
    {
        LNode *p=(LNode *)malloc(sizeof(LNode)); //申请新的结点
        p->data=a[i]; //结点数据域赋值
        p->next=L->next; L->next=p; //插入表头
    }
    return L;
}

②清空操作:算法的时间复杂度是O(n)

void ListClear(LinkedList L)
{
    LNode *p=L->next,*q; //p指向第一个结点
    while(p!=NULL)
    {
        q=p->next; //记住后继结点
        free(p); //释放p结点
        p=q; //移至待处理结点
    }
    L->next=NULL; //置表尾为空
}

③判空操作:算法的时间复杂度是O(1)

bool ListEmpty(LinkedList L)
{
    if(L->next==NULL) //通过头结点的指针域判断单链表是否为空
  	    return true;
    else
  	    return false;
}

④求表长操作:算法的时间复杂度是O(n)

int ListLength(LinkedList L)
{
    LinkedList p=L->next; //p指向第一个数据元素结点
    int len=0; //计数器初始化
    while(p)
    {  
        len++;
        p=p->next; //计数器+1,指针p后移
    }
    return len;
}

⑤遍历操作:算法的时间复杂度是O(n)

void ListPrint(LinkedList L)
{
	LNode *p = L->next;
	while (p != NULL)
	{
		printf("%d", p->data); //输出结点的值
		p = p->next; //指针p后移
	}
}

⑥插入操作:算法的时间复杂度是O(n)
因为单链表带头结点,在表头、表中、表尾插入数据元素的操作语句相同
在单链表中的第i个结点之前插入一个结点*s

先找到第i-1个结点,改变指针之间的逻辑关系
s指向指针p的后继结点(第i个结点)
然后将s的值存入结点*p的next域中

bool ListInsert(LinkedList L, int i, DataType x)
{
	LinkedList p, s;
    int count;
    p = L;
    count = 0; //初始化计数器
	if (p == NULL){
		printf("p为空 ");exit(0);
	}
	while (p != NULL && count < i - 1){ //查找第i-1个结点
		p = p->next;count++;
	}
	if (p == NULL)
		return false;
	else{
		s = (LNode *)malloc(sizeof(LNode));
		s->data = x;s->next = p->next;p->next = s; //将结点s插入结点p之后
		return true;
	}
}

⑦删除操作:算法的时间复杂度是O(n)
将单链表中第i个结点删除

找到*q的前驱结点*p,改变指针之间的逻辑关系

bool ListDelete(LinkedList L, int i, DataType *x)
{
	LNode *pre = L,*p;   int count = 0;
	while (pre != NULL && count < i - 1) //查找第i-1个结点
	{
		pre = pre->next;
        count++;
	}
	if (pre == NULL || pre->next == NULL) //若参数不合法
		return false;
	else
	{
		p = pre->next; *x = p->data; //存储被删数据元素值
		pre->next = p->next; //修改指针指向
		free(p); //释放被删数据元素空间
		return true;
	}
}

⑧按位查找操作:算法的时间复杂度是O(n)

bool ListGet(LinkedList L, int i, DataType *x) //DataType *x存放查找的值
{
	if (i < 1)
		return false;
	LNode *p = L->next; //p指向第一元素结点
	int j = 1; //计数器初始化
	while (p != NULL && j < i) //后移指针
	{
		p = p->next;  j++;
	}
	if (p != NULL)
	{
		*x = p->data; //查找成功
		return true;
	}
	else
		return false; //查找失败
}

⑨按值查找操作:算法的时间复杂度是O(n)

int ListLocate(LinkedList L, DataType x) //DataType x存放查找数据元素的值
{
	LNode *p = L->next; //p指向第一个结点
	int j = 1; //计数器初始化
	while (p != NULL && p->data != x)
	{
		p = p->next;  j++;
	}
	if (p!=NULL && p->data == x)
		return j; //查找成功,返回数据元素的位序
	else
		return 0; //查找失败
}

将两张非递减有序的单链表La和Lb合并得到一张新非递减有序的单链表Lc
算法的时间复杂度是O(m+n)

LinkedList Union(LinkedList La, LinkedList Lb)
{
	LNode *Lc, *pa, *pb, *pc;
	Lc = (LNode *)malloc(sizeof(LNode)); //申请结点
	Lc->next = NULL; //初始化链表Lc
	pa = La->next; //pa是链表La的工作指针
	pb = Lb->next; //pb是链表Lb的工作指针
	pc = Lc; //pc是链表Lc的工作指针
	while (pa && pb) //La和Lb均非空
		if (pa->data <= pb->data)
		{
			pc->next = pa; //La中元素插入Lc
			pc = pa;
			pa = pa->next;
		}
		else
		{
			pc->next = pb; //Lb中元素插入Lc
			pc = pb;
			pb = pb->next;
		}
	if (pa)
		pc->next = pa; //若pa未结束,将pc指向pa
	else
		pc->next = pb; //若pb未结束,将pc指向pb
	return Lc;
}

单链表基本操作的具体代码:

#include<stdlib.h>
#include<cstdio>
#include<iostream>
using namespace std;

//单链表的数据元素类型设置为整数
typedef int DataType;

//单链表存储结构
typedef struct LNode
{
    DataType data;
    struct LNode *next;
}LNode, *LinkedList;

//初始化空单链表
void ListInit(LinkedList *L)
{
    *L=(LNode*)malloc(sizeof(LNode));
    (*L)->next=NULL;
}

//尾插法建立单链表
LinkedList CreatTail(LinkedList &L, DataType a[], int n)
{
	LNode *p, *r;
	int i;
	L = (LNode *)malloc(sizeof(LNode));
	r = L;
	for (i = 0; i < n; i++)
	{
		p = (LNode *)malloc(sizeof(LNode));
		p->data = a[i];
		r->next = p;
		r = p;
	}
	r->next = NULL;
	return L;
}

//头插法建立单链表
LinkedList CreatHead(LinkedList &L,DataType a[], int n)
{
    L=(LNode *)malloc(sizeof(LNode));
    L->next=NULL;
    for(int i=0;i<n;i++)
    {
        LNode *p=(LNode *)malloc(sizeof(LNode));
        p->data=a[i];
        p->next=L->next; L->next=p;
    }
    return L;
}

//清空单链表中的所有数据元素
void ListClear(LinkedList L)
{
    LNode *p=L->next,*q;
    while(p!=NULL)
    {
        q=p->next;
        free(p);
        p=q;
    }
    L->next=NULL;
}

//判断单链表是否为空表
bool ListEmpty(LinkedList L)
{
    if(L->next==NULL)
  	    return true;
    else
  	    return false;
}

//求单链表的长度
int ListLength(LinkedList L)
{
    LinkedList p=L->next;
    int len=0;
    while(p)
    {  
        len++;
        p=p->next;
    }
    return len;
}

//遍历单链表
void ListPrint(LinkedList L)
{
	LNode *p = L->next;
	while (p != NULL)
	{
		printf("%d", p->data);
		p = p->next;
	}
}

//单链表中插入新的数据元素
bool ListInsert(LinkedList L, int i, DataType x)
{
	LinkedList p, s;int count;p = L;count = 0;
	if (p == NULL){
		printf("p为空 ");exit(0);
	}
	while (p != NULL && count < i - 1){
		p = p->next;count++;
	}
	if (p == NULL)
		return false;
	else{
		s = (LNode *)malloc(sizeof(LNode));
		s->data = x;s->next = p->next;p->next = s;
		return true;
	}
}

//删除单链表中的数据元素
bool ListDelete(LinkedList L, int i, DataType *x)
{
	LNode *pre = L,*p;   int count = 0;
	while (pre != NULL && count < i - 1)
	{
		pre = pre->next;    count++;
	}
	if (pre == NULL || pre->next == NULL)
		return false;
	else
	{
		p = pre->next; *x = p->data;
		pre->next = p->next;
		free(p);
		return true;
	}
}

//按位查找单链表中的数据元素
bool ListGet(LinkedList L, int i, DataType *x)
{
	if (i < 1)
		return false;
	LNode *p = L->next;
	int j = 1;
	while (p != NULL && j < i)
	{
		p = p->next;  j++;
	}
	if (p != NULL)
	{
		*x = p->data;
		return true;
	}
	else
		return false;
}

//按值查找单链表中的数据元素
int ListLocate(LinkedList L, DataType x)
{
	LNode *p = L->next;
	int j = 1;
	while (p != NULL && p->data != x)
	{
		p = p->next;  j++;
	}
	if (p!=NULL && p->data == x)
		return j;
	else
		return 0;
}

//将两张非递减有序的单链表La和Lb合并得到一张新非递减有序的单链表Lc
LinkedList Union(LinkedList La, LinkedList Lb)
{
	LNode *Lc, *pa, *pb, *pc;
	Lc = (LNode *)malloc(sizeof(LNode));
	Lc->next = NULL;
	pa = La->next;
	pb = Lb->next;
	pc = Lc;
	while (pa && pb)
		if (pa->data <= pb->data)
		{
			pc->next = pa;
			pc = pa;
			pa = pa->next;
		}
		else
		{
			pc->next = pb;
			pc = pb;
			pb = pb->next;
		}
	if (pa)
		pc->next = pa;
	else
		pc->next = pb;
	return Lc;
}

int main()
{
    LinkedList La; //定义一个单链表La
    ListInit(&La); //初始化单链表La
    cout<<"判断单链表La是否为空表(1为空表,0为非空表):"<<ListEmpty(La)<<endl;
    DataType a[3]={1,3,5};
    CreatTail(La,a,3);//使用尾插法建立单链表La
    cout<<"判断单链表La是否为空表(1为空表,0为非空表):"<<ListEmpty(La)<<endl;
    cout<<"单链表La中所含数据元素的个数:"<<ListLength(La)<<endl;
    int x; ListGet(La,1,&x); cout<<"查询单链表La的第一个数据元素的值:"<<x<<endl;
    cout<<"查询单链表La中第一个与值为3的数据元素的位置:"<<ListLocate(La,3)<<endl;
	int y; ListDelete(La,3,&y); cout<<"删除单链表La中的第三个数据元素,被删除数据元素的值:"<<y<<endl;
	cout<<"在单链表La中的第三个位置上插入数据元素5"<<endl;ListInsert(La,3,5);

	LinkedList Lb; //定义一个单链表Lb
    ListInit(&Lb); //初始化单链表Lb
    DataType b[3]={4,3,2};
    CreatHead(Lb,b,3);//使用头插法建立单链表Lb
	cout<<"判断单链表Lb是否为空表(1为空表,0为非空表):"<<ListEmpty(Lb)<<endl;
	
	cout<<"输出单链表La中所有的数据元素:"; ListPrint(La); cout<<endl;
	cout<<"输出单链表Lb中所有的数据元素:"; ListPrint(Lb); cout<<endl;
	LinkedList Lc=Union(La,Lb);
	cout<<"输出单链表Lc中所有的数据元素:"; ListPrint(Lc); cout<<endl;

	cout<<"清空单链表Lc中所有的数据元素";ListClear(Lc); cout<<endl;
	cout<<"判断单链表Lc是否为空表(1为空表,0为非空表)"<<ListEmpty(Lc)<<endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值