王道数据结构-栈和队列(C++代码实现)

本质也是一种线性表,只是操作受限,只能在一端插入或删除,具有last in first out的特性,故入栈、出栈顺序很重要。有了线性表的基础,也能快速构建【顺序栈】和【链栈】。

目录

 一、顺序栈的实现

1.指针top初始指向top=-1型顺序栈

0)初始化

1)判断栈是否为空

2)读栈顶元素

3)入栈

4)出栈

5)栈的遍历

6)完整代码及运行结果

2.指针top初始指向top=0型顺序栈

0)初始化

1)判断栈是否为空

2)读栈顶元素-同top=-1的情况

3)入栈

4)出栈

5)栈的遍历

6)完整代码及运行结果

二、链栈的实现

1.不带头结点的链栈

1)易错点1:

 2)易错点2:

3)完整代码和运结果 

2.带头结点的链栈

相关代码

运行截图

三、队列的顺序存储

1.循环队列

1)入队

2)出队

3)队列长度

2.代码及运行截图


 一、顺序栈的实现

顺序栈:顾名思义,就是基于顺序表建立的栈,所以基本操作还是以顺序表为基础

1.指针top初始指向top=-1型顺序栈

0)初始化

bool InitStack(SqStack &S){
    S.top=-1;
    return true;
}

1)判断栈是否为空

//判栈空
bool StackEmpty(SqStack S){
    if(S.top==-1)
        return true;//栈空
    else
        return false;//栈不为空
}

2)读栈顶元素

3)入栈

为什么先top++,才放入元素? 

注意:先修改top指针的值,再放入元素;这个逻辑很好理解:我们可以从初始状态开始想,初始时栈为空,当前top=-1,如果先放入元素,x都无法找到S.data[-1]的位置,更无法进栈。而如果top先加1,那么当前top更新为top=0,那么x就可以放入S.data[0]的位置,非常合理,接下来也是遵循,先加1,再入栈。

4)出栈

为什么先保存栈顶元素,再top--?

注意:先保存栈顶元素的值,再修改top指针;如果top先自减,那么实际上保存的是

s.data【top-1】的数据,不是我们想要的效果 

5)栈的遍历

这里提到栈的遍历,是因为想将栈中元素打印出来,检查入栈和出栈操作是否正确。开始还想去单独求顺序表长,但突然发现top指针天然就是一个指示表长的指标!在top初始指向-1的语境下,s.top其实就是栈顶元素的下标,这对于遍历来说太方便了,不用做任何+1/-1的边界判断,即遍历时循环变量的范围为:0<=i<=s.top(注意右侧可以取等)

//从栈底到栈顶打印当前栈中元素
void Print(SqStack S){
    cout<<"栈底->栈顶"<<endl;
    for(int i=0;i<=S.top;i++)
        cout<<S.data[i]<<" ";
    cout<<endl;
}

6)完整代码及运行结果

#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <typeinfo>

using namespace std;

//测试用例:12 23 34 45 56 67 78 89 -100

#define MAXSIZE 100//栈中元素最大个数
typedef struct SqStack{
    int data[MAXSIZE];//开辟数组存储栈中元素
    int top;//栈底指针
}SqStack;

//初始化顺序栈
bool InitStack(SqStack &S){
    S.top=-1;
    return true;
}

//判栈空
bool StackEmpty(SqStack S){
    if(S.top==-1)
        return true;//栈空
    else
        return false;//栈不为空
}

//读栈顶元素,若S非空,返回栈顶元素
bool GetTop(SqStack S,int &x){
    if(StackEmpty(S))
        return false;
    x=S.data[S.top];
    return true;
}

//入栈,若栈未满,将x入栈并成为新的栈顶
bool Push(SqStack &S,int x){
    if(S.top==MAXSIZE-1)
        return false;
    S.top++;//先让top指针自增
    S.data[S.top]=x;//然后数据入栈
    return true;
}

//出栈:若栈非空,弹出栈顶元素,并用x返回
bool Pop(SqStack &S,int &x){
    if(StackEmpty(S))
        return false;
    x=S.data[S.top];
    S.top--;
    return true;
}



//从栈底到栈顶打印当前栈中元素
void Print(SqStack S){
    cout<<"【打印:栈底->栈顶】"<<endl;
    for(int i=0;i<=S.top;i++)
        cout<<S.data[i]<<" ";
    cout<<endl;
}


int main(){
    SqStack S;
    int TopValue;//栈顶元素的值
    int x;//入栈元素
    InitStack(S);
    StackEmpty(S);
    cout<<"当前栈状态为(1-空 0-非空):"<<StackEmpty(S)<<endl;

    cout<<endl<<"【1-入栈】"<<endl;
    cout<<"请输入要入栈数据,输入为-100时停止入栈"<<endl;
    cin>>x;
    while(x!=-100&&S.top<MAXSIZE-1){
        Push(S,x);
        cin>>x;
    }
    GetTop(S,TopValue);
    cout<<"当前栈顶:"<<TopValue<<endl;
    Print(S);
    cout<<"当前栈状态为(1-空 0-非空):"<<StackEmpty(S)<<endl;

    cout<<endl<<"【2-出栈】"<<endl;
    int y;//弹出元素
    // Pop(S,y);
    // cout<<"当前出栈元素为:"<<y<<endl;
    // Print(S);
    while(StackEmpty(S)!=1)//将栈删空
    {
        Pop(S,y);
        cout<<"当前出栈元素为:"<<y<<endl;
        Print(S);
    }
    cout<<"栈已空,无法继续删除"<<endl;
}
开始运行...
当前栈状态为(1-空 0-非空):1

【1-入栈】
请输入要入栈数据,输入为-100时停止入栈
12 23 34 45 56 67 78 89 -100
当前栈顶:89
【打印:栈底->栈顶】
12 23 34 45 56 67 78 89 
当前栈状态为(1-空 0-非空):0

【2-出栈】
当前出栈元素为:89
【打印:栈底->栈顶】
12 23 34 45 56 67 78 
当前出栈元素为:78
【打印:栈底->栈顶】
12 23 34 45 56 67 
当前出栈元素为:67
【打印:栈底->栈顶】
12 23 34 45 56 
当前出栈元素为:56
【打印:栈底->栈顶】
12 23 34 45 
当前出栈元素为:45
【打印:栈底->栈顶】
12 23 34 
当前出栈元素为:34
【打印:栈底->栈顶】
12 23 
当前出栈元素为:23
【打印:栈底->栈顶】
12 
当前出栈元素为:12
【打印:栈底->栈顶】

栈已空,无法继续删除

运行结束。

2.指针top初始指向top=0型顺序栈

0)初始化

bool InitStack(SqStack &S){
    S.top=0;
    return true;
}

1)判断栈是否为空

//判栈空
bool StackEmpty(SqStack S){
    if(S.top==0)
        return true;//栈空
    else
        return false;//栈不为空
}

2)读栈顶元素-同top=-1的情况

3)入栈

为什么先入栈,再top++?

因为top初始指向top=0(即top指向下一个将入栈的位置),所以一开始就要先让数据入栈,即S.data[0]=x,再top++;而不是先加1,再入;

//入栈,若栈未满,将x入栈并成为新的栈顶
bool Push(SqStack &S,int x){
    if(S.top==MAXSIZE)
        return false;
    S.data[S.top]=x;//先让数据入栈
    S.top++;//再让top指针自增

4)出栈

为什么先top--,再弹出?

初始时,top=0;一些元素入栈后,top指向栈顶元素的下一个位置,所以此时相当于top指向的空间里没有数据,故需要先top--,再返回元素。

//出栈:若栈非空,弹出栈顶元素,并用x返回
bool Pop(SqStack &S,int &x){
    if(StackEmpty(S))
        return false;
    S.top--;//先让top自减
    x=S.data[S.top];//再弹出栈顶元素
    return true;
}

5)栈的遍历

top=0与top=-1的区别在于:此时0<=i<S.top,右端不能再取等号,因为S.top指向为空

//从栈底到栈顶打印当前栈中元素
void Print(SqStack S){
    cout<<"【打印:栈底->栈顶】"<<endl;
    for(int i=0;i<S.top;i++)
        cout<<S.data[i]<<" ";
    cout<<endl;
}

6)完整代码及运行结果

#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <typeinfo>

using namespace std;

//测试用例:22 33 44 55 66 77 88 99 -100

#define MAXSIZE 100//栈中元素最大个数
typedef struct SqStack{
    int data[MAXSIZE];//开辟数组存储栈中元素
    int top;//栈底指针
}SqStack;

//初始化顺序栈
bool InitStack(SqStack &S){
    S.top=0;
    return true;
}

//判栈空
bool StackEmpty(SqStack S){
    if(S.top==0)
        return true;//栈空
    else
        return false;//栈不为空
}

//读栈顶元素,若S非空,返回栈顶元素
bool GetTop(SqStack S,int &x){
    if(StackEmpty(S))
        return false;
    x=S.data[S.top];
    return true;
}

//入栈,若栈未满,将x入栈并成为新的栈顶
bool Push(SqStack &S,int x){
    if(S.top==MAXSIZE)
        return false;
    S.data[S.top]=x;//先让数据入栈
    S.top++;//再让top指针自增
    
    return true;
}

//出栈:若栈非空,弹出栈顶元素,并用x返回
bool Pop(SqStack &S,int &x){
    if(StackEmpty(S))
        return false;
    S.top--;//先让top自减
    x=S.data[S.top];//再弹出栈顶元素
    return true;
}


//从栈底到栈顶打印当前栈中元素
void Print(SqStack S){
    cout<<"【打印:栈底->栈顶】"<<endl;
    for(int i=0;i<S.top;i++)
        cout<<S.data[i]<<" ";
    cout<<endl;
}

int main(){
    SqStack S;
    int TopValue;//栈顶元素的值
    int x;//入栈元素
    InitStack(S);
    StackEmpty(S);
    cout<<"当前栈状态为(1-空 0-非空):"<<StackEmpty(S)<<endl;

    cout<<endl<<"【1-入栈】"<<endl;
    cout<<"请输入要入栈数据,输入为-100时停止入栈"<<endl;
    cin>>x;
    while(x!=-100&&S.top<MAXSIZE-1){
        Push(S,x);
        cin>>x;
    }
    GetTop(S,TopValue);
    cout<<"当前栈顶:"<<TopValue<<endl;
    Print(S);
    cout<<"当前栈状态为(1-空 0-非空):"<<StackEmpty(S)<<endl;

    cout<<endl<<"【2-出栈】"<<endl;
    int y;//弹出元素
    // Pop(S,y);
    // cout<<"当前出栈元素为:"<<y<<endl;
    // Print(S);
    while(StackEmpty(S)!=1)//将栈删空
    {
        Pop(S,y);
        cout<<"当前出栈元素为:"<<y<<endl;
        Print(S);
    }
    cout<<"栈已空,无法继续删除"<<endl;
}
开始运行...
当前栈状态为(1-空 0-非空):1

【1-入栈】
请输入要入栈数据,输入为-100时停止入栈
22 33 44 55 66 77 88 99 -100
当前栈顶:771756032
【打印:栈底->栈顶】
22 33 44 55 66 77 88 99 
当前栈状态为(1-空 0-非空):0

【2-出栈】
当前出栈元素为:99
【打印:栈底->栈顶】
22 33 44 55 66 77 88 
当前出栈元素为:88
【打印:栈底->栈顶】
22 33 44 55 66 77 
当前出栈元素为:77
【打印:栈底->栈顶】
22 33 44 55 66 
当前出栈元素为:66
【打印:栈底->栈顶】
22 33 44 55 
当前出栈元素为:55
【打印:栈底->栈顶】
22 33 44 
当前出栈元素为:44
【打印:栈底->栈顶】
22 33 
当前出栈元素为:33
【打印:栈底->栈顶】
22 
当前出栈元素为:22
【打印:栈底->栈顶】

栈已空,无法继续删除

运行结束。

二、链栈的实现

1.不带头结点的链栈

1)易错点1:

不带头结点的链表也需要malloc 申请空间,并初始为NULL,且不论带头结点还是不带头结点,都是L->next=NULL

bool IniLStack(LinkStack &LS){

    LS=(LinkStack)malloc(sizeof(LinkStack));

    LS->next=NULL;//初始化为空表

    return true;

}

开始出错的写法是:

bool IniLStack(LinkStack &LS){

    LS=(LinkStack)malloc(sizeof(LinkStack));

    LS=NULL;//初始化为空表

    return true;

}

 2)易错点2:

不带头结点的链表遍历,应该使得p的指向与头指针相同,而不是下一个结点

//顺序打印当前链栈中的数据

void Print(LinkStack LS){

    LNode* p;

    p=LS->next;//带头结点写法

    p=LS;//不带头结点

    cout<<"top栈顶->栈底bottom"<<endl;

    while(p!=NULL){

        cout<<p->data<<" ";

        p=p->next;

    }

    cout<<endl;

}

3)完整代码和运结果 

//不带头结点的链栈
#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <typeinfo>

using namespace std;

typedef struct LNode{
    char data;//数据域
    struct LNode* next;//指针域:指向LNode的指针
}LNode,*LinkStack;

bool IniLStack(LinkStack &LS){
    LS=(LinkStack)malloc(sizeof(LinkStack));
    LS->next=NULL;//初始化为空表
    return true;
}

//x入栈,不带头结点
bool pushLStack(LinkStack &LS,char x){
    LNode* s;//定义指向插入节点的指针
    s=(LNode*)malloc(sizeof(LNode));
    s->data=x;
    //改链操作:尤为注意,此为不带头结点情况!
    s->next=LS;
    LS=s;
    return true;

}

void StackLength(LinkStack &LS){
    LNode* p;
    int j=0;
    p=LS->next;
    while(p){
        p=p->next;
        j++;
    }
    cout<<"链栈当前的元素个数为:"<<j<<endl;
    //return j;
}

//顺序打印当前链栈中的数据
void Print(LinkStack LS){
    LNode* p;
    p=LS;
    cout<<"top栈顶->栈底bottom"<<endl;
    while(p!=NULL){
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}

//保存栈顶元素的值,并改链出栈
bool PopLStack(LinkStack &LS,char &x){
    if(LS->next==NULL)//如果栈为空
        return false;
    x=LS->data;//保存出栈数据(栈顶元素)
    LS=LS->next;//改链
    return true;
}

int main(){
    char x;//用于接收出栈元素
    LinkStack LS;//定义名为LS的链栈
    IniLStack(LS);
    cout<<"【1-入栈】"<<endl;
    cout<<"将字母序列:a c a e d a入链栈"<<endl;
    pushLStack(LS,'a');
    //cout<<pushLStack(LS,'a')<<endl;
    pushLStack(LS,'c');
    pushLStack(LS,'a');
    pushLStack(LS,'e');
    pushLStack(LS,'d');
    pushLStack(LS,'g');
    Print(LS);
    StackLength(LS);

    cout<<endl<<"【2-出栈】"<<endl;
    cout<<"将栈中前3个字母弹出链栈"<<endl;
    for(int i=0;i<3;i++)
    {
        PopLStack(LS,x);
        cout<<"当前出栈元素为:"<<x<<endl;
    }
    Print(LS);
    StackLength(LS);

    cout<<endl<<"【3-进进出出】"<<endl;
    cout<<"b c d e f g h i j k依次入栈"<<endl;
    for(int i=0;i<10;i++)
        pushLStack(LS,'b'+i);
    Print(LS);
    cout<<"出栈两次"<<endl;
    PopLStack(LS,x);
    PopLStack(LS,x);
    Print(LS);
    StackLength(LS);
}

运行结果: 

开始运行...
【1-入栈】
将字母序列:a c a e d a入链栈
top栈顶->栈底bottom
g d e a c a  
链栈当前的元素个数为:6

【2-出栈】
将栈中前3个字母弹出链栈
当前出栈元素为:g
当前出栈元素为:d
当前出栈元素为:e
top栈顶->栈底bottom
a c a  
链栈当前的元素个数为:3

【3-进进出出】
b c d e f g h i j k依次入栈
top栈顶->栈底bottom
k j i h g f e d c b a c a  
出栈两次
top栈顶->栈底bottom
i h g f e d c b a c a  
链栈当前的元素个数为:11

运行结束。

2.带头结点的链栈

链栈的入栈:本质就是头插法插入结点,不过注意带头结点的链栈,需要初始化,创建头结点,并使得头结点的next域置空;

链栈的出栈:先保存栈顶元素值,然后从头部修改链:即LS的next域指向它的下个结点:

LS->next=LS->next->next;如图所示

相关代码

#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <typeinfo>

using namespace std;

typedef struct LNode{
    int data;//数据域
    struct LNode* next;//指针域:指向LNode的指针
}LNode,*LinkStack;

bool IniLStack(LinkStack &LS){
    LS=(LinkStack)malloc(sizeof(LinkStack));//创建头节点
    LS->next=NULL;//初始化为空表
    return true;
}

//x入栈,带头结点
LinkStack headNode_pushLStack(LinkStack &LS,int x){
    LNode* s;//定义指向插入节点的指针
    s=(LNode*)malloc(sizeof(LNode));
    s->data=x;
    s->next=LS->next;//改链操作
    LS->next=s;
    return LS;
}

void StackLength(LinkStack &LS){
    LNode* p;
    int j=0;
    p=LS->next;
    while(p){
        p=p->next;
        j++;
    }
    cout<<"链栈当前的元素个数为:"<<j<<endl;
    //return j;
}

//顺序打印当前链栈中的数据
void Print(LinkStack LS){
    LNode* p;
    p=LS->next;
    cout<<"top栈顶->栈底bottom"<<endl;
    while(p!=NULL){
        cout<<p->data<<" ";
        p=p->next;
    }
    cout<<endl;
}

//保存栈顶元素的值,并改链出栈
bool PopLStack(LinkStack &LS,int &x){
    if(LS->next==NULL)//如果栈为空
        return false;
    x=LS->next->data;//保存出栈数据(栈顶元素)
    LS->next=LS->next->next;//改链
    return true;
}

int main(){
    int x;//用于接收出栈元素
    LinkStack LS;//定义名为LS的链栈
    IniLStack(LS);
    cout<<"【1-入栈】"<<endl;
    cout<<"将数字1~20入链栈"<<endl;
    for(int i=1;i<21;i++)
        headNode_pushLStack(LS,i);
    Print(LS);
    StackLength(LS);

    cout<<endl<<"【2-出栈】"<<endl;
    cout<<"将栈中前5个数字弹出链栈"<<endl;
    for(int i=0;i<5;i++)
    {
        PopLStack(LS,x);
        cout<<"当前出栈元素为:"<<x<<endl;
    }
    Print(LS);
    StackLength(LS);
    //cout<<"将链栈中数字全部出栈,直到为空"<<endl;

    cout<<endl<<"【3-进进出出】"<<endl;
    cout<<"-100 8 8 8 8 8依次入栈"<<endl;
    headNode_pushLStack(LS,-100);
    for(int i=0;i<5;i++)
        headNode_pushLStack(LS,8);
    Print(LS);
    cout<<"出栈两次"<<endl;
    PopLStack(LS,x);
    PopLStack(LS,x);
    Print(LS);
    StackLength(LS);
}

运行截图

开始运行...
【1-入栈】
将数字1~20入链栈
top栈顶->栈底bottom
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 
链栈当前的元素个数为:20

【2-出栈】
将栈中前5个数字弹出链栈
当前出栈元素为:20
当前出栈元素为:19
当前出栈元素为:18
当前出栈元素为:17
当前出栈元素为:16
top栈顶->栈底bottom
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 
链栈当前的元素个数为:15

【3-进进出出】
-100 8 8 8 8 8依次入栈
top栈顶->栈底bottom
8 8 8 8 8 -100 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 
出栈两次
top栈顶->栈底bottom
8 8 8 -100 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 
链栈当前的元素个数为:19

运行结束。

三、队列的顺序存储

1.循环队列

循环队列中设计到一个操作的关键点,就是取模操作%,目的是为了整合rear和front大小为一个,所以在做rear、front自加、计算队列长度、判断队满的操作时都要记得取模

1)入队

1.判断队满:(Q.rear+1)%MAXSIZE==Q.front

2.放入数据后,Q.rear的自加也要注意取模

错误写法:Q.rear++;//原因:漏掉了取模

正确写法:Q.rear=(Q.rear+1)%MAXSIZE;

3.上图:左为队满,右为队空

bool EnQueue(SqQueue &Q,int x){
    //判断队列是否已满
    if((Q.rear+1)%MAXSIZE==Q.front)//注意取余,才表示一整圈
        return false;
    //未满,则存入元素,rear指针+1
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MAXSIZE;
    return true;
}

2)出队

bool Dequeue(SqQueue &Q,int &x){
    //判断队列是否为空
    if(Q.front==Q.rear)
        return false;
    x=Q.data[Q.front];
    Q.front=(Q.front+1)%MAXSIZE;//队头指针+1取模
    return true;
}

3)队列长度

1.单向队列中:rear>=front length=rear-front

2.循环队列中:当rear<front时,length=0+rear+MAXSIZE-front

综合1、2,再加上一圈的取余,length=(0+Q.rear+MAXSIZE-Q.front)%MAXSIZE;

length=(Q.rear-Q.front+MAXSIZE)%MAXSIZE;

2.代码及运行截图

#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <typeinfo>

using namespace std;
#define MAXSIZE 100
typedef struct{
    int data[MAXSIZE];
    int front,rear;//定义队头、队尾
}SqQueue;

void InitQueue(SqQueue &Q){
    Q.rear=Q.front=0;//初始化队首、队尾
}

bool isEmpty(SqQueue Q){
    if(Q.rear==Q.front)
        return true;
    else 
        return false;
}

bool EnQueue(SqQueue &Q,int x){
    //判断队列是否已满
    if((Q.rear+1)%MAXSIZE==Q.front)//注意取余,才表示一整圈
        return false;
    //未满,则存入元素,rear指针+1
    Q.data[Q.rear]=x;
    Q.rear=(Q.rear+1)%MAXSIZE;
    return true;
}

//出队
bool Dequeue(SqQueue &Q,int &x){
    //判断队列是否为空
    if(Q.front==Q.rear)
        return false;
    x=Q.data[Q.front];
    Q.front=(Q.front+1)%MAXSIZE;//队头指针+1取模
    return true;
}

void QueueLength(SqQueue Q){
    int length;
    //length=(0+Q.rear+MAXSIZE-Q.front)%MAXSIZE;
    length=(Q.rear-Q.front+MAXSIZE)%MAXSIZE;
    cout<<"当前队列中元素的个数为:"<<length<<endl;
}

void Print(SqQueue &Q){
    cout<<"当前队列中的元素有:"<<endl;
    for(int i=Q.front;i<Q.rear;i++)
    {
        cout<<Q.data[i]<<" ";
    }
    cout<<endl;
}


int main(){
    SqQueue Q;
    int x;//接收出队元素
    InitQueue(Q);
    isEmpty(Q);
    Print(Q);
    for(int i=0;i<10;i++){
        EnQueue(Q,i);
    }
    Print(Q);
    QueueLength(Q);

    for(int i=100;i>90;i--){
        EnQueue(Q,i);
    }
    Print(Q);
    QueueLength(Q);

    int j=0;
    while(j<3){
        Dequeue(Q,x);
        cout<<"当前出队元素为:"<<x<<endl;
        j++;
    }
    Print(Q);
    QueueLength(Q);
}

开始运行...
当前队列中的元素有:

当前队列中的元素有:
0 1 2 3 4 5 6 7 8 9 
当前队列中元素的个数为:10
当前队列中的元素有:
0 1 2 3 4 5 6 7 8 9 100 99 98 97 96 95 94 93 92 91 
当前队列中元素的个数为:20
当前出队元素为:0
当前出队元素为:1
当前出队元素为:2
当前队列中的元素有:
3 4 5 6 7 8 9 100 99 98 97 96 95 94 93 92 91 
当前队列中元素的个数为:17

运行结束。

  • 0
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值