第三部分 STL(二)

二、STL

3. 常用容器

3.1 string容器

3.1.1 string基本概念
  • 本质
    • string是C++风格字符串,本质上是个类
    • string与char *的区别
      • char*是个指针
      • string是一个类,类内部封装了char*,管理这个字符串,是个char*型的容器
  • 特定
    • 内部封装了很多成员方法
      findcopydeleteinsertreplace
    • string管理char*分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
  • 自得
    使用string函数时,总有三种重载的传入方式
3.1.2 string构造函数

灵活使用

//string();   创建空字符串
string s1;

//string(const char* s);使用字符串s初始化
const char* str="s2";
string s2(str);

//string(const string& str);有另一string对象初始化
string s3(s2);

//string(int n, char c):使用n个字符c初始化
string s4(5,'a');
3.1.2 string赋值操作
  • 利用=
    函数原型:string& operator=()
    //(const char* s) char*类型字符串赋给当前字符串
        string s1; 
        s1 ="hello";
    //(const string &s) 一字符串赋给当前字符串
        string s2;
        s2=s1;
    //(const char c)  字符赋给当前字符串
        string s3;
        s3='a';
    
  • 利用assign函数
    函数原型:string& assign()
    //(const char* s) char*类型字符串赋给当前字符串
      string s1;
      s1.assign("hello");
    //(const char* s,int n) char*类型字符串前n个字符赋给当前字符串
      string s2;
      s2.assign("hello",3);
    //(string &s)  一字符串赋给当前字符串
      string s3;
      s3.assign(s2);
    //(int n, char c)  使用n个字符c赋给当前字符串
      string s4;
      s4.assign(5,'a');
    
3.1.3 string字符串拼接

实现在字符串末尾拼接字符串

  • 利用+=
    函数原型:string& operator=+()
    //(const char* s)
        string s1="hello ";
        s1+="world";
    //(const char c)
        s1+="!";
    //(const string &s)
        string s2="thanks";
        s1+=s2;
    
  • 利用append()函数
    函数原型:string& append()
    //(const char* s)
        string s1="hello ";
        s1.append("world");
    //(const char* s,int n)        
        s1.append("world hhh",5);
    //(const string &s)
        string s2="thanks you";
        s1.append(s2);
    //(const string &s,int pos,int n) 
    //第二个参数为从哪个位置开始截取,,第三个参数表示截取几个字符
        string s2="thanks you";
        s1.append(s2,0,5);
    
3.1.4 string查找和替换

查找:查找指定字符串是否存在。

  • 利用find函数与rfind函数
  • find从左往右查找(第一次出现),rfind从右往左查找(最后一次出现)
  • 找到后返回第一个字符所在的位置,没找到返回-1。
    //int find(const string &s,int pos),pos默认为0,
        string str="abcdefg";
        int ret=str.find("fg");
    
    //int find(const string &s,int pos,int n) pos位置查找s的前n个字符
    
    //int rfind(const string &s,int pos),pos默认为end
        string str="abcdefgab";
        int ret=str.rfind("ab");
    

替换:在指定的位置替换字符

  • 利用replace()函数
  • 指定从哪个位置起,多少个字符,替换成怎么样的字符
    //string& replace(int pos,int n,const string &s) 从pos开始n个字符
        string str="abcdefg";
        str.replace(2,3,"111");//ab111fg
    
3.1.5 string字符串的比较
  • compare()函数
  • 主要是为了判断相等,不是谁大谁小
  • 按字符的ASCII码值进行对比
  • =返回0,>返回1,<返回-1
    //int compare(const string &s)
        string str1="cd";
        string str2="ab";
        int ret=str1.compare(str2);
    
3.1.6 string字符存取
  • 通过[]访问单个字符
    str[i]
  • 通过at()函数
    str.at(i)
3.1.7 string子串
  • substr()函数
  • 实用性强,比如从邮箱中找出函数名
    //string substr(int pos,int n) 返回pos开始的n个字符
        string str1="abcdefg";
        string str2= str1.substr(1,3);//bcd
    
3.1.8 string插入和删除
  • insert()函数(插入)
    //string& insert(int pos,const string &s)
        string str1="cd";
        str1.insert(1,"11");//c11d
    
  • erase()函数(删除)
    //string& erase(int pos,int n) 删除从Pos开始的n个字符
        string str1="abcdefg";
        str1.erase(2,3);//abfg
    

3.2 vector容器

3.2.1 vector基本概念
  • 功能
    与数组相似,只能在尾端进行操作,一块连续的内存空间称为单端数组
  • 与普通数组区别
    数组是静态的,vector可以动态扩展
    动态扩展:不是在原空间之后续新空间,而是找更大的内存空间,将原数据拷贝到新空间,再释放原空间
  • vector的迭代器是支持随机访问迭代器,常用的迭代器有:
    v.begin():指向第一个数据,v.end():指向最后一个数据的后一个位置
    v.rend():指向第一个数据的前一个位置,v.rbegin():指向最后一个数据
3.2.2 vector构造函数

四种构造方式

//vector<T> v;  默认构造
vector<int>v1;

//vector(v.begin(),v.end())  通过区间方式(前闭后开)进行构造
vector<int>v2(v1.begin(),v1.end());

//vector(n,elem)  n个elem方式构造
vector<int>v3(10,100);

//vector<const vector &vec>  拷贝构造
 vector<int>v4(v3)
3.2.3 vector赋值操作

三种赋值操作

 //operator=
    vector<int> v1;
     vector<int> v2;
    v2=v1;

 //assign(v.begin(),v.end())  
     vector<int> v3;
    v3.assign(v1.begin(),v1.end());

 //assign(n,elem)
     vector<int> v4;
    v4.assign(10,100);
3.2.4 vector容量和大小

empty():判空(返回真为空)
capacity():返回容器的容量(≥size)
size():返回容器中元素的个数
resize(int num,elem):重新指定容器长度为num,若变长,以elem(不写的话默认为0)填充新位置,若变短,末尾超出部分删除

3.2.5 vector插入和删除
  • 插入
    push_back(elem):尾部插入元素elem
    insert(const_iterator pos,elem):迭代器指向的位置pos插入元素elem
    insert(const_iterator pos,int count,elem):迭代器指向位置pos插入count个元素elem
  • 删除
    pop_back():删除最后一个元素
    erase(const_iterator pos):删除迭代器指向的元素
    erase(const_iterator start,const_iterator end):删除迭代器从start到end之间的元素
    clear():删除容器中的所有元素
3.2.6 vector数据存取

at(int idx):返回索引idx所指的数据
[idx]:返回索引idx所指的数据
front():返回容器中第一个元素
back():返回容器中最后一个元素

3.2.7 vector互换容器

swap(vector):将vector与本身的元素互换
实现收缩内存的效果

//已知v.capacity()=10000;
vector<int>(v).swap(v);
//通过拷贝构造了一个匿名对象,再与v本身进行交换,成功将收缩内存
3.2.8 vector容器预留空间

减少vector再动态扩展容量时的扩展次数
reserve(int len):容器预留len个元素长度,预留位置不初始化,元素不可访问

3.3 deque容器

3.3.1 deque容器的基本概念
  • 功能
    可以对头、尾端进行操作,称为双端数组
  • deque与vector的区别
    • vector访问速度比deque快
    • deque头部插入删除速度比vector快
  • 内部工作原理
    内部有中控器,维护每段缓冲区的内容,维护的是每个缓冲区的地址,缓冲区中存放真实的数据,使得使用deque时像一片连续的内存空间
  • vector的迭代器是支持随机访问迭代器,常用的迭代器有:
    v.begin():指向第一个数据,v.end():指向最后一个数据的后一个位置
3.3.2 deque的构造函数

四种构造函数(与vector相同)

//deque<T> v;  默认构造
deque<int>v1;

//deque(v.begin(),v.end())  通过区间方式(前闭后开)进行构造
deque<int>v2(v1.begin(),v1.end());

//deque(n,elem)  n个elem方式构造
deque<int>v3(10,100);

//deque<const deque &vec>  拷贝构造
deque<int>v4(v3)
3.3.3 deque赋值操作

三种赋值操作(与vector相同)

//operator=
    deque<int> v1;
    deque<int> v2;
    v2=v1;

 //assign(v.begin(),v.end())  
    deque<int> v3;
    v3.assign(v1.begin(),v1.end());

 //assign(n,elem)
    deque<int> v4;
    v4.assign(10,100);
3.3.4 deque大小操作

没有容量的概念
empty():判空(返回真为空)
size():返回容器中元素的个数
resize(int num,elem):重新指定容器长度为num,若变长,以elem(不写的话默认为0)填充新位置,若变短,末尾超出部分删除

3.3.5 deque插入和删除
  • 两端操作
    push_back(elem):尾部添加一数据
    push_front(elem):头部插入一数据
    pop_back(elem):尾部删除一元素
    pop_front(elem):头部删除一元素
  • 指定位置操作
    insert(const_iterator pos,elem):迭代器指向的位置pos插入元素elem,返回新元素的位置
    insert(const_iterator pos,int count,elem):迭代器指向位置pos插入count个元素elem,无返回值
    insret(const_iterator pos,const_iterator start,const_iterator end)在pos位置插入迭代器从start到end之间的元素,无返回值
    erase(const_iterator pos):删除迭代器指向的元素,返回下一个数据的位置
    erase(const_iterator start,const_iterator end):删除迭代器从start到end之间的元素,返回下一个数据的位置
    clear():删除容器中的所有元素
3.3.6 deque存取操作

at(int idx):返回索引idx所指的数据
[idx]:返回索引idx所指的数据
front():返回容器中第一个元素
back():返回容器中最后一个元素

3.4 stack容器

栈,先进后出,一个出口,只能操作栈顶元素,不允许遍历,

  • 构造函数
    stack<T> stk:默认构造函数
    stack(const stack &stk):拷贝构造
  • 赋值操作
    stack& operator=(const stack &stk):等号赋值
  • 数据存取
    push(elem):栈顶添加元素
    pop():栈顶移除一个元素
    top();:返回栈顶元素
  • 大小操作
    empty():判断栈堆是否为空
    size():返回栈的大小

3.5 queue容器

队列,先进先出,一端移除(出队,队头),一端新增(入队,队尾),只能操作队头队尾,不允许遍历。

  • 构造函数
    queue que:默认构造函数
    queue(const queue &que):拷贝构造
  • 赋值操作
    queue& operator=(const queue &que):等号赋值
  • 数据存取
    push(elem):队尾添加元素
    pop():队头移除一个元素
    back():返回最后一个元素
    front():返回第一个元素
  • 大小操作
    empty():判断队列是否为空
    size():返回队列的大小

3.6 list容器

3.6.1 基本概念

STL提供的是双向循环链表
list迭代器为双向迭代器,只支持前移和后移
动态存储分配,不会造成内存浪费和溢出
插入删除方便,遍历麻烦
插入和删除不会造成原有list迭代器的失效(vector中不成立)
list与vector最常用,各有优缺点,注意选择

3.6.2 list构造函数

四种构造函数(几种STL的构造方式都相同)

//list<T> lst;  默认构造
list<int>L1;

//list(lst.begin(),lst.end())  通过区间方式(前闭后开)进行构造
list<int>L2(L1.begin(),L1.end());

//list(n,elem)  n个elem方式构造
list<int>L3(10,100);

//list<const deque &lst>  拷贝构造
list<int>L4(L3)
3.6.3 list赋值和交换

assign(beg,end)区间赋值
assign(n,elem)n个elem赋值
list& operator=(const list &lst)等号
swap(lst) 与lst本身的元素互换

3.6.4 list大小操作

empty():判空(返回真为空)
size():返回容器中元素的个数
resize(int num,elem):重新指定容器长度为num,若变长,以elem(不写的话默认为0)填充新位置,若变短,末尾超出部分删除

3.6.5 list插入和删除
  • 两端操作
    push_back(elem):尾部添加一数据
    push_front(elem):头部插入一数据
    pop_back(elem):尾部删除一元素
    pop_front(elem):头部删除一元素
  • 其他位置操作
    insert(const_iterator pos,elem):迭代器指向的位置pos插入元素elem,返回新元素的位置
    insert(const_iterator pos,int count,elem):迭代器指向位置pos插入count个元素elem,无返回值
    insret(const_iterator pos,const_iterator start,const_iterator end)在pos位置插入迭代器从start到end之间的元素,无返回值
    erase(const_iterator pos):删除迭代器指向的元素,返回下一个数据的位置
    erase(const_iterator start,const_iterator end):删除迭代器从start到end之间的元素,返回下一个数据的位置
    clear():清空容器中的所有元素
    remove(elem):移除容器中与elem相匹配的所有值
3.6.6 list数据存取

front():返回第一个元素
back():返回最后一个元素
不能使用[]或者at()访问,因为list不是连续线性的空间存储数据

3.6.7 list反转和排序

reverse():反转
sort():排序(默认为从小到大,若要更改可添加参数)

L.sort(myCompare);//降序排列
bool myCompare(int val1,int val2){
    return val1>val2;
}

在所有不支持随机访问迭代器的容器中,不可以使用标准算法,它的内部会提供一些算法,使用时直接调用即可

3.7 set/multiset容器

3.7.1 set基本概念
  • 功能
    所有元素在插入时自动排序
  • 本质
    属于关联式容器,底层结构为二叉树
  • 区别
    • set不允许插入重复元素,但multiset允许
    • set插入数据的同时会返回插入结果.表示是否插入成功(pair<Iterator,bool>)
    • multiset不会检测数据。
3.7.2 set构造和赋值
  • 构造
    set<T> s:默认构造
    set(const set &st):拷贝构造
  • 赋值
    set operator=(const set &st):等号赋值
3.7.3 set大小与交换
  • 大小
    size():返回容器中元素的个数
    empty()判空
  • 交换
    swap(st):交换两个容器
3.7.4 set插入与删除
  • 插入
    insert(elem):插入一个数
  • 删除
    erase(const_iterator pos):删除迭代器指向的元素,返回下一个数据的位置
    erase(const_iterator start,const_iterator end):删除迭代器从start到end之间的元素,返回下一个数据的位置
    erase(elem):删除容器中值为elem的元素
    clear():清空容器中的所有元素
3.7.5 set查找与统计
  • 查找
    find(elem):若找到返回该元素迭代器位置,若没找到返回set.end()
  • 统计
    count(elem):统计elem的元素个数
    对于set而言,count=0或者=1
3.7.6 set容器排序

仿函数修改默认的排序大小

  • set存放内置数据类型
    class myCampare(){
    public:
        bool operator()(int v1,int v2){
        return v1>v2;
        }
    }
    //将自定义类型写在函数列表中
    set<int,myCompare>s;//则此set容器为自定义类型排序
    
  • set存放自定义数类型
    对于自定义数据类型,必须指定排序规则
    class myCampare(){
    public:
        bool operator()(const Person&v1,const Person&v2){
            //按照年龄降序
            return p1.age>p2.age;
        }
    }
    set<Person,myCompare>s;
    

3.8 map/multimap容器

3.8.1 pair队组
  • 创建方式(二种)

    //第一种方式
    pair<string,int>p1("Tom",20);
    //第二种方式
    pair<string,int>make_pair("Jerry",30);
    
  • 调用
    p.first:调用第一个参数
    p.second:调用第二个人参数

3.8.2 map基本概念
  • 简介
    • map中所有元素都是pair
      • pair中第一个元素为key(键值),索引作用,第二个元素为value(实值)
    • 所有元素根据元素的键值自动排序
  • 本质
    属于关联式容器,底层结构为二叉树
  • 优点
    可以根据key值快速找到value值
  • map/multimap区别
    map中不允许有重复的key值元素,但multimap中允许
3.8.3 map构造和赋值
  • 构造
    map<T1,T2> mp:默认构造
    map(const map &mp):拷贝构造
  • 赋值
    map& operator=(const map &mp)等号赋值
3.8.4 map大小与交换
  • 大小
    size():返回容器中元素的个数
    empty()判空
  • 交换
    swap(mp):交换两个容器
3.8.5 map插入和删除
  • 插入(三种)
    map<int,int> m;
    //第一种
    m.insert(pair<int,int>(1,10));
    //第二种
    m.insert(make_pair(2,20));
    //第三种
    m.insert(map<int,int>::value_type(3,30));
    //第四种(不建议,若是插错会自动创建)
    m[4]=40;//[]可以利于key访问value
    
  • 删除
    • erase(const_iterator pos):删除迭代器指向的元素,返回下一个数据的位置
      erase(const_iterator start,const_iterator end):删除迭代器从start到end之间的元素,返回下一个数据的位置
      erase(key):删除容器中值为key的元素
      clear():清空容器中的所有元素
3.8.6 map查找和统计
  • 查找
    find(key):若找到返回该元素迭代器位置,若没找到返回map.end()
  • 统计
    count(key):统计key的元素个数
    对于map而言,count=0或者=1
3.8.7map排序

与set排序相同

4. 常用算法

4.1 常用遍历算法

4.1.1 for_each
for_each(v.begin,v.end,print01);
for_each(v.begin,v.end,print02());
//普通函数
void print01(int val){
    cout<<val<<" ";
}
//仿函数
class print02{
public:
    void operator()(int val){
        cout<<val<<" ";
    }
} 
4.1.2 transform

搬运容器到另一个容器
transform(Iterator beg1,Iterator end1.Iterator beg2,_func);
//beg1:原容器开始迭代器
//end1:原容器结束迭代器
//beg2:目标容器开始迭代器
//__func:函数或者函数对象(对搬运的元素进行操作)

class Transform{
public:
    int operator()(int val){
        return val;//可以对元素进行操作        
    }
}  
void test(){
    vector<int> v1;
    for(int i=0;i<10;i++){
        v1.push_back(i);
    }
    vector<int>v2;
    v2.resize(v1.size());//目标容器需要开辟空间
    transform(v1.begin(),v1.end(),v2.begin(),Transform());
}

4.2 常用查找算法

4.2.1 find

查找指定元素,若找到返回该元素迭代器位置,若没找到返回结束迭代器end()
find(iterator beg,iterator end,values)

  • 查找内置数据类型

    vector<int>::iterator it=find(v1.begin(),v1.end(),5);
    if(it==v1.end())
        cout<<"x"<<endl;
    else
        cout<<"√"<<endl;
    
  • 查找自定义数据类型

    //在Person中
    bool operator==(const Person &p){
        if(this->Name==p.Name&&this->Age==p.Age){
            return true;
        }
        else{
            return false;
        }
    }
    //在test中
    Person pp("bbb",30);
    vector<int>::iterator it=find(v1.begin(),v1.end(),pp);
    if(it==v1.end())
        cout<<"x"<<endl;
    else
        cout<<"√"<<endl;
    
4.2.2 find_if

按条件查找元素,返回迭代器
find_if(iterator beg,iterator end,_Pred)
//_Pred或者谓词

  • 查找内置数据类型

    class Myfind{
    public:
        bool operator()(int val){
            return val>5;
        }
    };
    vector<int>::iterator it=find_if(v1.begin(),v1.end(),Myfind());
    if(it==v1.end())
        cout<<"x"<<endl;
    else
        cout<<"√"<<*it<<e
    
  • 查找自定义数据类型

    class Myfind{
    public:
        bool operator()(int val){
            return val>5;
        }
    };
    
4.2.3 adjacent_find

查找相邻重复元素,返回相邻元素的第一个位置的迭代器
adjacent_find(iterator beg,iterator end);

vector<int>::iterator it=adjacent_find(v1.begin(),v1.end());
if(it==v1.end())
    cout<<"x"<<endl;
else
    cout<<"√"<<*it<<endl;
4.2.4 binary_search

查找指定元素是否存在,找到返回true,没找到返回false
bool binary_search(iterator beg,iterator end,value)
必须为有序序列,在无序序列中不可用

bool ret=binary_search(v.begin(),v.end,5);
if(ret)
    cout<<"x"<<endl;
else
    cout<<"√"<<*it<<endl;
4.2.5 count

统计元素个数
count(iterator beg,iterator end,value)

  • 统计内置数据类型

    int num=count(v.begin(),v.end(),5);
    //5的元素的个数
    
  • 统计自定义数据类型

    //在Person中
    bool operator==(const Person &p){
        if(this->Name==p.Name){
            return true;
        }
        else{
            return false;
        }
    }
    
4.2.6 count_if

按条件统计元素个数
count(iterator beg,iterator end,_pred)

  • 统计内置数据类型

    class Myfind{
    public:
        bool operator()(int val){
            return val>5;
        }
    };
    int num=count_if(v.begin(),v.end(),Myfind());
    
  • 统计自定义数据类型

    class Myfind{
    public:
        bool operator()(const Person&p){
            return p.age>20;
        }
    };
    int num=count_if(v.begin(),v.end(),Myfind());
    

4.3 常用排序算法

4.3.1 sort

对容器内部元素进行排序
sort(iterator beg,iterator end,_pred)
//_Pred可以不写,默认为从大到小排序

//降序
sort(v.begin(),v,end(),greater<int>());
4.3.2 random_shuffle

洗牌,指定范围内的元素随机调整次序
random_shuffle(iterator beg,iterator end)

srand(unsigned int)time(NULL));
//为了打乱更真实
random_shuffle(v.degin,v.end);
4.3.3 merge

合并两个容器的元素,并存储到另一个容器中
两个容器必须是有序的,且排列顺序是一致的,存储之后也是有序的
merge(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)
//beg1、end1容器1开始、结束迭代器
//beg2、end2容器2开始、结束迭代器
//target目标容器开始迭代器

vector<int> v3;
v3.resize(v1.size()+v2.size());//目标容器需要提前开辟空间
merge(v1.begin(),v1.end,v2.begin(),v2,end(),v3.begin());
4.3.4 reverse

将元素内容器进行反转
reverse(iterator beg,iterator end)

4.4 常见拷贝和替换算法

4.4.1 copy

容器内指定元素拷贝到目标容器中
copy(iterator beg,iterator end,iterator target)

vector<int> v2;
v2.resize(v1.size());//提前给目标容器开辟空间
copy(v1.begin(),v1.end,v2.begin())
4.4.2 replace

容器内指定范围的旧元素更改为新元素
replace(iterator beg,iterator end,oldvalue,newvalue);

4.4.3 replace_if

将区间内满足条件的元素,替换成指定元素
replace_if(iterator beg,iterator end,_pred,value);

class Myfind{//利于仿函数筛选满足的条件
public:
    bool operator()(int val){
        return val>5;
    }
};
replace_if(v.begin,v.end,Myfind,200);
4.4.4 swap

互换两个容器中的元素
两个容器需要是同种类型
swap(container c1,container c2)

4.5 常用算术生成算法

属于小型算法,头文件为#include<numeric>

4.5.1 accumulate

计算容器元素累计总和
accumulate(iterator beg,iterator end,value)
//value为起始累加值

int total=accumulate(v.begin,v.end,1000);
4.5.2 fill

向容器中填充指定的元素
full(iterator beg,iterator end,value)

4.6 常用集合算法

4.6.1 set_intersection

求两个容器的交集,返回值为交集最后一个元素的位置
两个集合必须是有序序列
set_intersection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)

vector<int> v3;
v3.resize(min(v1.size(),v2.size());//目标容器开辟空间需要从两个容器中取小值
vector<int>::iterator itEnd
=set_intersection(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
for_each(v3,begin(),itEnd,myprint());//遍历时要用返回的迭代器位置
4.6.2 set_union

求两个集合的并集,返回值为并集最后一个元素的位置
两个集合必须是有序序列
set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)

vector<int> v3;
v3.resize(v1.size()+v2.size());//目标容器开辟空间需要两个容器size相加
vector<int>::iterator itEnd
=set_union(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
for_each(v3,begin(),itEnd,myprint());//遍历时要用返回的迭代器位置
4.6.3 set_difference

求两个集合的差集,返回值为差集最后一个元素的位置
A-B与B-A的差集时不同的,注意区分前后(差集:除去相同部分)
两个集合必须是有序序列
set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator target)

vector<int> v3;
v3.resize(max(v1.size(),v2.size());//目标容器开辟空间需要从两个容器中取最大值
vector<int>::iterator itEnd
=set_union(v1.begin(),v1.end(),v2.begin(),v2.end(),v3.begin());
for_each(v3,begin(),itEnd,myprint());//遍历时要用返回的迭代器位置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值