09_STL包括容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数六个部分

【目录】

一、 STL : 2
1、 简介: 2
2、 分类: 2
3、 例子: 2
二、 容器(containers) 与 迭代器(iterators) 3
1、 序列容器: 3
2、 关联容器: 3
3、 Vectors (数组) 3
4、 List(双向链表) 4
5、 Set(链式结构)-红黑树容器 7
6、 Multiset 9
7、 映射map 12
8、 Multimap 13
9、 Hashset 14
10、 Hashmap 15
11、 堆stack 16
12、 queue队列 17
13、 Deque双端队列: 18
14、 Priority_queue (堆)最高优先级元素总是第一个出列 19
15、 Bitset位集合 20
16、 字符串string 22
三、 算法(algorithms) 24
1、 Find 与 for_each 例子: 24
2、 Find_if 例子: 25
3、 lambda表达式 26
4、 Fill例子: 30
5、 Count,统计例子: 31
6、 adjacent_find 查找相同一组的元素: 31
7、 random_shuffle 打乱数据: 32
8、 Partition 分区无序 , rotate转换: 32
9、 prev_permutation 自动排序并且可以显示: 33
10、 Sort 排序: 33
11、 partial_sort 部分排序 : 34
四、 GPU编程 34
1、 Hello 34
2、 35

一、STL :

  1、简介:
      ①.STL ( Standard Template Library),标准模板库;
      ②.STL现在是C++的一部分,因此不用额外安装什么;
      ③.STL被内建在你的编译系统之内;
      ④.在C++标准中,STL被组织为下面的17个头文件:<algorithm>、<deque>、<functional>、<iterator>、<array>、<vector>、<list>、<forward_list>、<map>、<unordered_map>、<memory>、<numeric>、<queue>、<set>、<unordered_set>、<stack>和<utility>。
  2、分类:
      ①.容器(containers)、
      ②.迭代器(iterators)、
      ③.空间配置器(allocator)、
      ④.配接器(adapters)、
      ⑤.算法(algorithms)、
      ⑥.仿函数(functors)六个部分
  3、例子:

#include<iostream>
#include <vector>//容器
#include<array>//数组
#include <algorithm>//算法

using namespace std;

/*实现一个类模板,专门实现打印的功能*/
template<class T> //类模板实现了方法
class myvectorprint
{
public:
    void operator ()(const T &t)//重载,使用(),打印
    {
        std::cout << t << std::endl;
    }
};
void main(){
    vector<int>  myvector;
    myvector.push_back(11);
    myvector.push_back(21);

    array<int, 10> myarray = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };

    myvectorprint<int >print;//对于打印进行实例化


    //begin,endl迭代器,是一个指针,每一个指针指向的都是内容的实体,所以可以直接通过*p打印出来内容。
    for_each (myvector.begin(), myvector.end(),print);
    for_each(myarray.begin(), myarray.end(), print);
    cin.get();

    //算法可以适用于任何容器,for_each是一个算法
(这里foreach实现的是一个函数包装器的功能,可以查看下源码)
}

二、容器(containers) 与 迭代器(iterators)

  1、序列容器:
      ①.每个元素都有固定位置,这取决于插入时机和地点,与元素值无关。例如:list , vector , deque ……
  2、关联容器:
      ①.每个元素位置取决于特定的排序准则,和插入顺序无关。例如:set , multiset , map , multimap……
  3、Vectors (数组)
      ①.内部数据结构:数组。
      ②.在堆上开辟空间。
      ③.随机访问每个元素,所需要的时间为常量。
      ④.在末尾增加或删除元素所需时间与元素数目无关,在中间或开头增加或删除元素所需时间随元素数目呈线性变化。
      ⑤.可动态增加或减少元素,内存管理自动完成,但程序员可以使用reserve()成员函数来管理内存。
      ⑥.vector的迭代器在内存重新分配时将失效(它所指向的元素在该操作的前后不再相同)。当把超过capacity()-size()个元素插入vector中时,内存会重新分配,所有的迭代器都将失效;否则,指向当前元素以后的任何元素的迭代器都将失效。当删除元素时,指向被删除元素以后的任何元素的迭代器都将失效。
      ⑦.例子:

#include<iostream>
#include<vector>
#include <array>
#include <tuple>
using namespace std;

void main1()
{
    array<int, 5>myarray = { 1, 2, 3, 4, 5 };
    //数组,静态数组,栈上

    vector <int >myvetor;
    myvetor.push_back(1);
    //动态数组,堆上,

    //不需要变长,容量较小,array
    //需要变长,容量较大,vetor
}

  4、List(双向链表)
      ①.内部数据结构:双向环状链表。
      ②.不能随机访问一个元素。
      ③.可双向遍历。
      ④.在开头、末尾和中间任何地方增加或删除元素所需时间都为常量。
      ⑤.可动态增加或减少元素,内存管理自动完成。
      ⑥.增加任何元素都不会使迭代器失效。删除元素时,除了指向当前被删除元素的迭代器外,其它迭代器都不会失效。
      ⑦.例子:

#include<iostream>
#include <hash_set>
#include <list>
#include<stdio.h>

//list适用于经常插入,经常删除

using namespace std;
void main()
{
    list<int> mylist;

    mylist.push_back(1);
    mylist.push_back(2);
    mylist.push_back(3);
    mylist.push_back(4);
    //mylist[1];错误链表是没下标的,必须使用迭代器
    auto ibegin = mylist.begin();//指针,指向一个迭代器,迭代器存储了位置
    auto iend = mylist.end();
    //list用迭代器进行遍历
    for (;ibegin!=iend;ibegin++)
    {
        cout << *ibegin << endl;
        printf("%p,%p\n",  ibegin._Ptr , ibegin);//重载
    }

    cin.get();
}
//list删除
void main3()
{
    list<int> mylist;
    mylist.push_back(1);
    mylist.push_back(2);
    mylist.push_back(3);
    mylist.push_back(4);    
    mylist.push_back(5);
    //auto i = mylist.begin();//删除元素,依赖于迭代器,
    //++i;
    auto i = mylist.end();//end最后一个没有实体,
    i--;
    mylist.erase(i);//链式存储,不允许下标访问
    //只能用迭代器,链表迭代器只能用++,--
    //mylist.clear();清空
    auto ibegin = mylist.begin();//指针,指向一个迭代器,迭代器存储了位置
    auto iend = mylist.end();

    for (; ibegin != iend; ibegin++) {
        if ((*ibegin) == 3)
        {
            mylist.erase(ibegin);//删除,删除的时候迭代器会发生
            break;
(注意:这里删除之后迭代器发生了变化,如果没有break的话这里会产生错误。迭代器必须重新赋值)
        }
        //cout << *ibegin << endl;
    }
    {
        auto ibegin = mylist.begin();//指针,指向一个迭代器,迭代器存储了位置
        auto iend = mylist.end();

        for (; ibegin != iend; ibegin++)
        {
            cout << *ibegin << endl;
        }
    }
    cin.get();
}
void main4()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    list<int > mylist(a, a + 5);//根据数组初始化,
    //传递开始地址,传递结束地址
   //   mylist(0);不行
    //mylist[1];不行,只能用迭代器访问
    mylist.push_back(10);
    mylist.push_front(12);
    auto ibegin = mylist.begin();//指针,指向一个迭代器,迭代器存储了位置
    auto iend = mylist.end();

    for (; ibegin != iend; ibegin++)
    {
        if (*ibegin==3)
        {
            mylist.insert(ibegin ,30);
            break;//删除或者插入,迭代器都会发生变化
        }
    }
    mylist.remove(30);//直接一个函数,根据元素来删除

    cin.get( ) ;
}
/*反向迭代器*/
void main5()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    list<int > mylist(a, a + 5);//根据数组初始化,
    auto rb = mylist.rbegin();
    auto re = mylist.rend();
    //同时正向与方向查找
    for (;rb != re; rb++)
    {
        cout << *rb << endl;
    }

    cin.get();
}
/*list链表合并*/
void  main6()
{
    int a[5] = { 1, 2, 3, 104, 5 };
    list<int > mylist1(a, a + 5);//根据数组初始化,
    int b[5] = { 11, 122,33, 44, 55 };
    list<int > mylist2(b, b + 5);//根据数组初始化,
    mylist1.sort();
    mylist2.sort();//排序

    mylist1.merge(mylist2);//合并之前必须有序
    {
        auto ibegin = mylist1.begin();//指针,指向一个迭代器,迭代器存储了位置
        auto iend = mylist1.end();

        for (; ibegin != iend; ibegin++)
        {
            cout << *ibegin << endl;
        }
    }
    cout << "\n\n\n";
    {
        auto ibegin = mylist2.begin();//指针,指向一个迭代器,迭代器存储了位置
        auto iend = mylist2.end();

        for (; ibegin != iend; ibegin++)
        {
            cout << *ibegin << endl;
        }
    }
    cin.get();
}
/*list唯一*/
void main7()
{
        int a[6] = { 1, 2,98, 2, 5, 98 };
        list<int > mylist1(a, a + 6);//根据数组初始化,
        {
            auto ibegin = mylist1.begin();//指针,指向一个迭代器,迭代器存储了位置
            auto iend = mylist1.end();

            for (; ibegin != iend; ibegin++)
            {
                cout << *ibegin << endl;
            }
        }
        mylist1.sort();
        mylist1.unique();//唯一依赖于排序
        cout << "\n\n\n";
        {
            auto ibegin = mylist1.begin();//指针,指向一个迭代器,迭代器存储了位置
            auto iend = mylist1.end();

            for (; ibegin != iend; ibegin++)
            {
                cout << *ibegin << endl;
            }
        }

        cin.get();
}

  5、Set(链式结构)-红黑树容器
      ①.按照键进行排序存储,值必须可以进行比较,可以理解为set就是键和值相等的map键唯一。
      ②.元素默认按升序排列。
      ③.如果迭代器所指向的元素被删除,则该迭代器失效。其它任何增加、删除元素的操作都不会使迭代器失效。
      ④.例子:

#include<iostream>
#include <set>
using namespace std;

void main1231()
{
    set<int>myset;
    myset.insert(10);插入
    myset.insert(9);
    myset.insert(8);
    myset.insert(7);
    myset.insert(5);
    myset.insert(6);
    myset.insert(7);
    //myset.insert(7);重复会被舍弃
    auto findpos = myset.find(10);查找
    cout << "  find ->" << *findpos << "  \n";



    auto ib = myset.begin();
    auto ie = myset.end();
    for (;ib!=ie;ib++)
    {
        cout << *ib << "  ";

    }
    std::cout << "\n"<<myset.size() << endl;
    cin.get();
}

      ⑤.高级:

#include<iostream>
#include <set>
#include <string>
#include <bitset>

using namespace std;

struct strless
{
    bool operator()(const char *str1, const char *str2) 
//二分查找法依赖于有序,字符串有序
    {
        return strcmp(str1, str2)  <  0;
    }
};

//红黑树,处理纯数字非常少,处理类对象以及字符串
void main1()
{
    const char *cmd[] = { "abc", "calc", "notepad", "const","xyz","ghj" };

    set< const char *, strless> myset(cmd, cmd + 6, strless());//构造
    myset.insert("1234");
    myset.insert("4567"); 添加

    //pair起到获取插入返回值,第一个类型,类型比大小的方式
(己:就是将插入值所在的节点【二叉树上值所对应的节点】返回,)
    pair<set<const char *>::iterator, bool> p = myset.insert("9876");
    cout << "pair start" << endl;
    cout << *(p.first) <<"   "<< p.second << endl;
    cout << "pair over" << endl;

    auto ib = myset.begin();
    auto ie = myset.end();
    for (;ib!=ie;ib++)
    {
        cout << *ib << endl;
    }

    set<const char *, strless>::iterator pfind = myset.find("xyz");//查找
    std::cout <<"\n\n\n"<< *pfind << endl;

    cin.get();
}

  6、Multiset
      ①.键可以不唯一。(己:相同元素在二叉树上的同个节点,以链表的形式存储)
      ②.其它特点与map相同。
      ③.例子:

#include<iostream>
#include <set>
#include <stdio.h>
#include <list>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

void main12()
{
    multiset <int>myset;
    myset.insert(11);
    myset.insert(12);
    myset.insert(13);
    myset.insert(10);
    myset.insert(10);
    myset.insert(100);
    auto ib = myset.begin();
    auto ie = myset.end();

    for (;ib!=ie;ib++)
    {
        std::cout << *ib << std::endl;
        printf("%p,%p\n", ib, ib._Ptr);//智能指针
    }

    cin.get();
}
/*智能指针讲解list*/
void main()
{
    list<int> mylist;
    mylist.push_back(11);
    mylist.push_back(1);
    mylist.push_back(16);
    mylist.push_back(1);
    mylist.push_back(18);

    auto ib = mylist.begin();
    auto ie = mylist.end();
    for (;ib!=ie;ib++)
    {
        std::cout << *ib << std::endl;
        printf("%p\n", ib);

        printf("%p\n", ib._Ptr);

        //智能指针  STL  bug ,分行打印,先访问内部,再访问外部(注意:)
        printf("%p,%p\n", ib._Ptr,ib );//智能指针.
    }
    cin.get();
}
/*智能指针讲解list*/
void mainx()
{
    list<int> mylist;

    mylist.push_back(1);
    mylist.push_back(2);
    mylist.push_back(3);
    mylist.push_back(4);
    //mylist[1];
    auto ibegin = mylist.begin();//指针,指向一个迭代器,迭代器存储了位置
    auto iend = mylist.end();
    //list用迭代器进行遍历
    for (; ibegin != iend; ibegin++)
    {
        cout << *ibegin << endl;
        printf("%p,%p\n", ibegin._Ptr, ibegin);//重载
    }

    cin.get();
}
/*find_if  greater   ,   bindlst  */
bool less3(int x)
{
    return x < 3;
}
void mainu()
{
    vector<int> mylist;
    mylist.push_back(1);
    mylist.push_back(2);
    mylist.push_back(16);
    mylist.push_back(1);
    mylist.push_back(18);

    using namespace std;

    auto ib = mylist.begin();
    auto ie = mylist.end();
    for (; ib != ie; ib++)
    {
        std::cout << *ib << std::endl;

    }

    //仿函数可以实现一定的算法策略

    auto ifind = find_if(mylist.begin(), mylist.end(), less3);  // bind1st( greater<int>(), 3)
     //绑定一个函数, greater<int>(),3比三大的全部过滤掉

    std::cout <<"\n\n\n\n"<< *ifind << endl;

    cin.get();
}

      ④.高级:

#define _CRT_SECURE_NO_WARNINGS
#include <set>
#include <iostream>
#include <string>

//mutiset每一个节点都是一个链表,set每个节点就是一个节点
using namespace std;

struct student
{
    int id;
    char name[30];
};
//排序
struct stuless
{
    bool operator()(const student &s1, const student &s2)
    {
        return s1.id < s2.id;
    }
};
void main2()
{
    student sarray[3] = { { 10, "tansheng" }, { 3, "liguilong" }, { 4, "xiongfei" } };
    multiset<student, stuless> myset (sarray, sarray + 3, stuless());
    student stu1;
    stu1.id = 20;
    strcpy(stu1.name, "mouzhiwei");
    myset.insert(stu1);
    strcpy(stu1.name, "mouzhiwei1");
    myset.insert(stu1);
    auto ib = myset.begin();
    auto ie = myset.end();
    for (;ib!=ie;ib++)  {
        cout << (*ib).id << "  " << (*ib).name << endl;
    }

    cin.get() ; 
}

      ⑤.补充(将相等的元素全部查找出来):

#include <set>
#include <iostream>


using namespace std;

void mainA()
{

    multiset<int> myset;
    myset.insert(100);
    myset.insert(101);
    myset.insert(100);
    myset.insert(103);
    myset.insert(100);

    auto pfind = myset.find(101);找到第一个101
    std::cout << *pfind << std::endl;

    auto allfind = myset.equal_range(100);
    //找到红黑树的链表节点,遍历所有的元素

    //find链表的头结点,second最后一个空节点,遍历所有的元素
    for (auto it = allfind.first; it != allfind.second;it++)
    {
        cout << *it << endl;
    }

    cin.get();

}

  7、映射map

#include <map>//也是红黑树
#include <iostream>
using namespace std;

void main1111()
{

    map<const char * , int> mymap;
    mymap["司令"] = 10;//映射 ,对等的映射查找
    mymap["军长"] = 9;
    mymap["师长"] = 8;
    mymap["旅长"] = 7;

    cout << mymap["司令"] << endl;
    cout << mymap["军长"] << endl;
    cout << mymap["师长"] << endl;
    cout << mymap["旅长"] << endl;

    std::cin.get();
}

struct  student
{
    char * name;
    int  year;
};

struct stuinfo
{
    int id;
    student stu;
};

void main3213()
{
    stuinfo infoarrary[] = { { 10, { "yincheng1", 21 }  },{ 5, { "yincheng2", 22 } } , { 25, { "yincheng3", 30 } } };

    map<int, student> m;//编号映射 结构体
    for (int i = 0; i < 3;i++)
    {
        m[   infoarrary[i].id   ] = infoarrary[i].stu;//编号映射一个学生的信息

    }
    stuinfo infoarrarys = { 101, { "china", 99 } };
    m[25] = infoarrarys.stu;//映射


    map<int,student>::iterator ib = m.begin();
    auto ie = m.end();
    for (;ib!=ie;ib++)
    {
        cout << (*ib).first << endl;
        cout << (*ib).second.name <<"  " <<(*ib).second.year << endl;
    }

    cin.get();
}

  8、Multimap
      ①.基本:

#include <map>
#include <iostream>
using namespace std;


//map,mutlimap区别是map每一个节点是一个映射
//multimap每一个一个节点是映射的链表的开头

void main121321()
{
    map<const char *, int> m;
    m.insert(pair<const char *, int>("司令1",101));
    m.insert(pair<const char *, int>("司令2", 102));
    m.insert(pair<const char *, int>("司令3", 103));
    m.insert(pair<const char *, int>("司令1", 104));

    map<const char *, int>::iterator ib = m.begin();
    auto ie = m.end();
    for (; ib != ie; ib++)
    {
        cout << (*ib).first << "   " << (*ib).second << "\n";
    }

    cin.get();
}

void main2123123()
{
    multimap<const char *, int> m;
    m.insert(pair<const char *, int>("司令1", 101));
    m.insert(pair<const char *, int>("司令2", 102));
    m.insert(pair<const char *, int>("司令3", 103));
    m.insert(pair<const char *, int>("司令1", 104));

    auto ib = m.begin();
    auto ie = m.end();
    for (; ib != ie; ib++)
    {
        cout << (*ib).first << "   " << (*ib).second << "\n";
    }

    cin.get();
}

      ②.补充:

#include <iostream>
#include <map>
#include <string>
using namespace std;

void main2()
{
    multimap<string, string> mymap;
    mymap.insert(pair<string, string>("yincheng", "a"));
    mymap.insert(pair<string, string>("yincheng1", "b"));
    mymap.insert(pair<string, string>("yincheng", "c"));
    mymap.insert(pair<string, string>("yincheng", "d"));

    auto ib = mymap.begin();
    auto ie = mymap.end();
    for (;ib!=ie;ib++)
    {
        cout << (*ib).first << "   "<<(*ib).second << endl;
    }

    auto pfind = mymap.find("yincheng");//只找到相等元素的第一个
    cout << "\n\n\n";
    cout << (*pfind).first << "   " << (*pfind).second<< endl;
    cout << "\n\n\n";
    auto it = mymap.equal_range("yincheng");
//从树节点吧关键字相同的链表全部拔下

    //first起点,secondl链表最后的节点后面一个空节点,都是迭代器
    for (auto i = it.first; i != it.second;i++)
    {
        cout << (*i).first << "   " << (*i).second << endl;
    }

    cin.get();
    cin.get();
}

  9、Hashset

#include <hash_set>
#include <iostream>
#include<algorithm>
#include <string>
using namespace std;

void main123123123()
{
    const char *cmd[] = { "abc", "calc", "notepad", "const", "xyz", "ghj" };
    hash_set<const char*> hs;//C++11自带了字符串的哈希,哈希有哈希表,查找方便快速

    hs.insert("chian");添加
    hs.insert("chi123an");
    hs.insert("chi23an");
    hs.insert("chzcian");
    hs.insert("1chzcian");

    auto pfind = hs.find("chi1213an");查找

    if (pfind == hs.end())
    {
        std::cout << "没有";
    }
    else
    {
        std::cout << *pfind;
    }
    cin.get();
}

void main1asdasdsad()
{
    hash_set<int> hs;
    hs.insert(91);
    hs.insert(21);
    hs.insert(41);


    auto ib = hs.begin();
    auto ie = hs.end();
    for (;ib!=ie;ib++)
    {
        cout << *ib << endl;
    }
    auto pfind = hs.find(211);
    if (pfind==ie)
    {
        std::cout << "没有";
    } 
    else
    {
        std::cout << *pfind;
    }

    cin.get();
}

  10、Hashmap

#include <hash_map>//也是红黑树
#include <iostream>
#include<map>
using namespace std;

void main()
{
    map< int,const char *> m;
    m.insert(pair< int, const char *>(201, "司令1" ));
    m.insert(pair< int, const char *>(101, "司" ));
    m.insert(pair< int, const char *>(401, "司令11111" ));
    m.insert(pair< int, const char *>(301, "司令"));

    auto ib = m.begin();
    auto ie = m.end();
    for (; ib != ie; ib++)
    {
        cout << (*ib).first << "   " << (*ib).second << "\n";
    }
    {
        hash_map< int, const char *> m;
        m.insert(pair< int, const char *>(201, "司令1"));
        m.insert(pair< int, const char *>(101, "司"));
        m.insert(pair< int, const char *>(401, "司令11111"));
        m.insert(pair< int, const char *>(301, "司令"));

        auto ib = m.begin();
        auto ie = m.end();
        for (; ib != ie; ib++)
        {
            cout << (*ib).first << "   " << (*ib).second << "\n";
        }
        auto tofind = m.find(1101);
        if (tofind == ie)
        {
            cout << "没有找到";
        }
        else
        {
            cout << "--"<<(*tofind).first<<"--"<<(*tofind).second;
        }
    }
    std::cin.get();
}

  11、堆stack

#include <stack>
#include <iostream>

using namespace std;

void mainB()
{
    int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    stack<int> mystack;
    for (int i = 0; i < 10;i++)
    {
        mystack.push(a[i]);
    }

    while (!mystack.empty())
    {
        int num = mystack.top();
        std::cout << num << " ";
        mystack.pop();
    }

    cin.get();
}
void mainA()
{
    int num;
    cin >> num;
    stack<int> mystack;
    for ( ;num;num/=2)
    {
        mystack.push(num % 2);
        std::cout << "当前元素个数" << mystack.size() << endl;
    }
    while (!mystack.empty())
    {
        int num=mystack.top();
        std::cout << num << " ";
        mystack.pop();
    }
    cin.get();
    cin.get();
}

  12、queue队列

#include <queue>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <list>

#include<deque>//双端队列

//提供了二维动态数组的功能,头部,尾部,任意操作

using namespace std;

void mainX()
{

    queue<char *>myq;
    myq.push("calc");
    myq.push("notepad");
    myq.push("tasklist");
    myq.push("mspaint");

    while (!myq.empty())
    {
      char *p=  myq.front();//获取
      system(p);
      myq.pop();
    }
}

  13、Deque双端队列:

void mainY()
{
    deque<int> mydq;
    mydq.push_back(1);
    mydq.push_back(11);
    mydq.push_back(111);
    mydq.push_back(1111);
    mydq.push_back(11111);
    mydq.push_front(123);
    mydq.insert(mydq.begin() + 3, 100);//插入

    for (int i = 0; i < mydq.size();i++)
    {
        std::cout << mydq[i] << std::endl;
    }
    auto ib = mydq.begin();
    auto ie = mydq.end();
    for (; ib != ie; ib++)
    {
        std::cout << *ib<< std::endl;
    }

    cin.get();
}

void main11()
{

    deque<int> mydq;
    mydq.push_back(1);
    mydq.push_back(11);
    mydq.push_back(111);
    mydq.push_back(1111);
    mydq.push_back(11111);
    mydq.push_front(123);
    //mydq.erase(mydq.begin());
    //mydq.erase(mydq.end() - 1);
    mydq.pop_front();//头部弹出
    mydq.pop_back();//尾部
    //mydq.clear();

    auto ib = mydq.begin();
    auto ie = mydq.end();
    for (; ib != ie; ib++)
    {
        std::cout << *ib << std::endl;
    }

    cin.get();
}
void main1234()
{
    deque<int> mydq1;
    mydq1.push_back(1);
    mydq1.push_back(11);
    mydq1.push_back(111);
    mydq1.push_back(1111);
    mydq1.push_back(11111);

    deque<int> mydq2;
    mydq2.push_back(2);
    mydq2.push_back(21);
    mydq2.push_back(211);
    mydq2.push_back(2111);

    mydq1.swap(mydq2);整体交换
    {
        auto ib = mydq1.begin();
        auto ie = mydq1.end();
        for (; ib != ie; ib++)
        {
            std::cout << *ib << std::endl;
        }
    }
    {
        auto ib = mydq2.begin();
        auto ie = mydq2.end();
        for (; ib != ie; ib++)
        {
            std::cout << *ib << std::endl;
        }
    }

    cin.get();
}

void mainXF()
{
    deque<int> mydq1;
    mydq1.push_back(1);
    mydq1.push_back(11);
    mydq1.push_back(111);
    mydq1.push_back(1111);
    mydq1.push_back(11111);
    std::cout << mydq1.front() << std::endl;首元素
    std::cout << mydq1.back() << std::endl; 尾元素
    std::cout << mydq1.max_size() << std::endl; 最大装多少个
    std::cout << mydq1.size() << std::endl; 

    cin.get();
}

  14、Priority_queue (堆)最高优先级元素总是第一个出列

void  mainRT()
{
    priority_queue<int > myq;
    myq.push(10);
    myq.push(12);
    myq.push(11);
    myq.push(110);
    myq.push(101);//自动排序

    while (!myq.empty())
    {
        std::cout << myq.top() << endl;
        myq.pop();
    }

    cin.get();
}

struct student
{
    int age;
    string name;
};
//strcmp==0;

struct stuless
{
    bool operator()(const student &s1,  const student &s2)
    {
        return s1.age < s2.age;
    }

};

void main()
{                  //类名,   //存储结构         //比大小函数
    priority_queue<student, deque<student>, stuless> myq;
    student s1;
    s1.age = 10;
    s1.name = "谭胜";
    student s2;
    s2.age = 9;
    s2.name = "熊飞";
    student s3;
    s3.age = 19;
    s3.name = "熊peng飞";
    myq.push(s1);
    myq.push(s2);
    myq.push(s3);
    while (!myq.empty())
    {
        std::cout << myq.top().age << myq.top().name << endl;
        myq.pop();
    }

    cin.get();
}

  15、Bitset位集合

#include <set>
#include <bitset>
#include <iostream>
#include<string>
using namespace std;
/*正常打印*/
void main3X()
{
          //8 位, (255)代表构造的数据 
    bitset<8>bs(255);
    for (int i = 0; i < 8;i++)//最高位存储i=7上
    {
        cout << bs[i];/*这个是高位放高位*/
    }
    cin.get();
    cin.get();
}
/*反向打印*/
void main3Y()
{
    //8 位, (215)代表构造的数据 
    bitset<8>bs(215);
    for (int i = 7; i >=0; i--)
    {
        cout << bs[i] << "  " << ~bs[i] << endl;

    }
    cin.get();
    cin.get();
}
/*float数的二进制*/
void  main3Z()
{
    float num = 1231231236.8;
    bitset<32> myset(num);/*32位*/
    for (int i = 31; i >=0;i--)
    {
        cout << myset[i];
    }
    cin.get();
}
/*将二进制位转化为string*/
void  main3S()
{
    int  num =-5;
    bitset<32> myset(num);
    for (int i = 31; i >= 0; i--)
    {
        cout << myset[i];
    }
    string str = myset.to_string();
    cout <<"\n" <<str << endl;

    unsigned int data;
    data = myset.to_ulong();//补码
    cout << "\n" << data<< endl;

    cin.get();
}
/*位操作方法*/
void main345()
{
    bitset<8>bs(255);
    bs.set(7, 0);//操作二进制位
    bs.set(0, 0);
    cout << bs.size() << endl;//位数
    //bs.reset();//全部清零
    //bs.none();//测试下是否有越位
    for (int i = 7; i >=0; i--)//最高位存储i=7上
    {
        cout << bs[i];
    }

    cin.get();
}

  16、字符串string

#include<string>
#include <iostream>
#include <stdlib.h>

using namespace std;

//字符串初始化
void main1s()
{
    char str[124] = "china is  big";
    //str = "12321";C写法,不能这样写,strcpy才行

    //string str1(str);
    //str1 = "china  is great";
    string str1("ABCDEFG");
    str1 = "china  is  china";
    std::cout << str1;

    cin.get();
}
/*字符串连接*/
void main2s()
{
    string str1("ABCD");
    string str2("1234");
    string str3 = str1 + str2;//重载了+操作符
    std::cout << str3;

    char stra[12]="1231";
    char strb[24]="2132";
    //char strc[36] = stra + strb;不行,strcat才行
    cin.get();
}
/*字符串的追加,+也能实现这个功能*/
void main3s()
{
    string str1("ABCD");
    string str2("1234");
    str1.append(str2);
    str1 += str2;//字符串的增加
    std::cout << str1;

    cin.get();
}
/*字符串插入*/
void main4s()
{
    string str1("ABCD");
    string str2("1234");
    //任意位置插入字符
    str1.insert(str1.begin(),'X');
    /*字符串就想数组一样,可以采用下标的写法*/
    str1.insert(str1.end(), 'X');
    str1.insert(str1.begin()+3,3, 'X');
    /*第三个位置插入三个字符x*/
    std::cout << str1;
    cin.get();
}
/*字符串添加高级*/
void  main5s()
{
    string str1("12345678");
    auto ib = str1.begin(); 
    auto ie = str1.end();
    for (;ib!=ie;ib++)
    {
        cout << *ib << endl;
    }
    //str1.erase(str1.begin());//删除一个字符
    //str1.erase(str1.begin()+3,str1.end()-2);
    //删除这中间一连串的字符串
    str1.erase(3, 4);
    //c从第三个字符开始删除四个字符
    cout << str1 << endl;

    cin.get();
}
/*字符串替换*/
void main6s()
{
    string str1("12345678china");
    str1.replace(5, 3, "china");//从0到第三个字符替换为china
    //replace,1位置,长度,字符串
    /*就是在第5(位置)之后的三个字符(原来字符串的长度),被替换为“china”(内容)*/

    cout << str1 << endl;
    cin.get();
}
/*字符串查找*/
void mainA1()
{
    string str("233锄禾日当午,谭胜把地雷买下土,谭胜来跳舞,炸成250");
    //cout << (int)str.find("谭胜大爷") << endl;
    //int pos = str.find(",");
    //找到第一个皮配的,不匹配返回-1,
    //int pos = str.rfind("谭胜");
    //尾部找到第一个皮配的,不匹配返回-1,

    cin.get();
}
/**/
void mainA2()
{
    string str("ab123mn");
    //int pos = str.find_first_of("123");
    //find_firstof是第一个找到与字符串皮配字符位置
    //int pos = str.find_first_not_of("abc");
    //find_firstof是第一个找到与字符串不皮配字符位置

    //int pos = str.find_last_of("123");
    //find_firstof是最后一个找到与字符串皮配字符位置
    int pos = str.find_last_not_of("123");

    cout << pos << endl;
    cin.get();
}
/*判断是否相等*/
void main1234()
{
    string str1 = "calc";
    string str2 = "ABC1";
    char strA[5] = "Asd";
    char strB[5] = "Asd";
    cout <<( str1 == str2) << endl;//重载了运算符
    cout << (strA == strB) << endl;//比较地址,比较必须使用strcmp

    cout << str1.empty()<<endl;//是否为空
    const char *p = str1.c_str();
    system(p);

    cin.get();
}
/*反复查找*/
void main()
{
    string str("abc is abc  china is china");
    //int pos = str.find('a', 0);
    //字符也一样,从0位置开始查找,pos是位置
    //std::cout << pos << endl;    0
    //pos = str.find('a', pos+1);    7
    //std::cout << pos << endl;

        cin.get();
}

三、算法(algorithms)

  1、Find 与 for_each 例子:

#include <algorithm>
#include <iostream>
using namespace std;

struct print
{
    void operator ()(int x)//重载了()符号,之后调用()
    {
        std::cout << x << endl;
    }
};

void printA(int x)
{
    std::cout << x << endl;
}

void main1()
{
    int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int *p = find(a, a + 10, 8);
    std::cout << (void*)a << (void*)(a + 10) << std::endl;
    std::cout << *p << endl;
    std::cout << p << endl;
    if (p==(a+10))
    {
        std::cout << "没有找到\n";
    }
    for_each(a, a + 4, print());//遍历每一个元素,
    //printA是一个函数指针,必须是函数类型

    cin.get();
}
void main1()
{
    vector<int> myv;
    myv.push_back(1);
    myv.push_back(2);
    myv.push_back(3);
    for_each(myv.begin(), myv.end(), [](int v){ cout << v << endl; });
    auto  i = find(myv.begin(), myv.end(), 23);如果没找到就返回end指针
    if (i==myv.end())
    {
        std::cout << "23玩失踪";
    }   else
    {
        std::cout <<*i;
    }
    cin.get();
}

  2、Find_if 例子:

void mainu()
{
    vector<int> mylist;
    mylist.push_back(1);
    mylist.push_back(2);
    mylist.push_back(16);
    mylist.push_back(1);
    mylist.push_back(18);

    using namespace std;

    auto ib = mylist.begin();
    auto ie = mylist.end();
    for (; ib != ie; ib++)
    {
        std::cout << *ib << std::endl;

    }

    //仿函数可以实现一定的算法策略

    auto ifind = find_if(mylist.begin(), mylist.end(), less3);  
    // less3 = bind1st( greater<int>(), 3)
     //绑定一个函数, greater<int>(),3比三大的全部过滤掉

    std::cout <<"\n\n\n\n"<< *ifind << endl;

    cin.get();
}
void main2()
{
    vector<int> myv;
    myv.push_back(1);
    myv.push_back(2);
    myv.push_back(3);
    for_each(myv.begin(), myv.end(), [](int v){ cout << v << endl; });
    //auto  i = find_if(myv.begin(), myv.end(), [](int v)->bool{ return (v > 4); });
    auto  i = find_if_not(myv.begin(), myv.end(), [](int v)->bool{ return (v > 4); });
    if (i == myv.end())
    {
        std::cout << "玩失踪";
    }   else
    {
        std::cout << *i;
    }
    cin.get();
}

  3、lambda表达式
      ①.初级:
          基本格式:【】(型参)->返回值{}

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;

template<class T>  //模板类,实现对于某些容器元素的操作
class add
{
public:
    void operator()( T &t)//重载()运算符,进行操作
    {
        t *= 2;
        std::cout << t<<"\n";
    }
};

void  go(int a)
{
    a *= 2;
    std::cout << a << "\n";
}

void main()
{
    vector<int> myv;
    myv.push_back(10);
    myv.push_back(9);
    myv.push_back(7);
    myv.push_back(9);

    add<int> addA;//省略,
    //for_each(myv.begin(), myv.end(), addA);
    //for_each(myv.begin(), myv.end(), add<int>());
    //for_each(myv.begin(), myv.end(), go);
    /*函数包装器与类包装器*/

    /*兰达表达式*/
    auto fun = [](int a, int b){ return a + b; };//R表达式

    auto funA = [](int a){a *= 2; cout << a << endl; };
    cout << fun(1, 2) << endl;
    for_each(myv.begin(), myv.end(), funA);
    for_each(myv.begin(), myv.end(), [](int a){a *= 2; cout << a << endl; });

    cin.get();
}

      ②.高级:

#include <functional>
#include <iostream>
#include<vector>
#include<algorithm>

using namespace std;
/*lambda表达式,带参数,无返回值*/
void main1()
{
    auto fun1 = [](){cout << "hello china"; };
    fun1();
    auto fun2 = [](int a, int b){return a + b; };
    cout << fun2(10, 9) << endl;

    std::cin.get();
}
/*lambda表达式结合算法for_each*/
void main2()
{
    vector<int>  myv;
    myv.push_back(1);
    myv.push_back(2);
    myv.push_back(11);
    auto fun1 = [](int v){  cout << v << endl; };
    for_each(myv.begin(), myv.end(), fun1);

    /*
    for_each(myv.begin(), myv.end(),  [](int v){cout << v << endl;});
    */
    std::cin.get();
}
/* [=](int v){ },引用外部变量,不能修改*/
void main3()
{
    vector<int>  myv;
    myv.push_back(1);
    myv.push_back(2);
    myv.push_back(11);

    int a = 10;
    // =知道a的存在,可以引用,只能读,不可以写,引用当前块语句内部的局部变量,
    auto fun1 = [=](int v){ v += a;  cout << v << endl;  };

    for_each(myv.begin(), myv.end(), fun1);
    cout << a << endl;
    std::cin.get();
}
/*[&a](int v){ } : 引用变量a*/
void main4()
{
    vector<int>  myv;
    myv.push_back(1);
    myv.push_back(2);
    myv.push_back(11);

    int a = 10;
    //引用变量a,
    auto fun1 = [&a](int v){a = 3; v += a;  cout << v << endl;  };
    for_each(myv.begin(), myv.end(), fun1);
    cout << a << endl;
    std::cin.get();
}
/*函数指针,函数调用*/
void main5()
{

     [](){cout << "hello china"; };//是一个函数指针
     [](){cout << "hello china"; }();//调用函数

     cin.get();
}
/*类中的lambda表达式*/
class test
{
public:
    vector<int>  myv;
    int num;
public:
    test()
    {
        num = 12;
        myv.push_back(10);
        myv.push_back(11);
    }
    void add()
    {
        int  x = 3;
        //[]引用this
        //auto fun1 = [this,x](int v){ cout << v+x+this->num << endl; };
        //=按照副本引用this,还有当前块语句局部变量,不可以赋值,但是可以读取
        //&按照引用的方式操作局部变量,this,可以赋值,可以读取
        //副本(拷贝)引用a,[=]   [a]
        //引用 a [&]  [&a]

        auto fun1 = [&](int v){ cout << v + x + this->num << endl; x = 3; };
        for_each(this->myv.begin(), this->myv.end(), fun1);
    }
};
/*
C++ 11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。Lambda的语法形式如下:
[函数对象参数](操作符重载函数参数) mutable或exception声明->返回值类型{ 函数体 }
可以看到,Lambda主要分为五个部分:
[函数对象参数]、(操作符重载函数参数)、mutable或exception声明、->返回值类型、{ 函数体 }。下面分别进行介绍。
一、[函数对象参数],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。
函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
1、空。没有使用任何函数对象参数。
2、 = 。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
3、&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
4、this。函数体内可以使用Lambda所在类中的成员变量。
5、a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
6、&a。将a按引用进行传递。
7、a, &b。将a按值进行传递,b按引用进行传递。
8、 = ,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
9、&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
二、(操作符重载函数参数),标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a, b))和按引用(如:(&a, &b))两种方式进行传递。
三、mutable或exception声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。
exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)。
四、->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
五、{ 函数体 },标识函数的实现,这部分不能省略,但函数体可以为空。
/*lambda返回值*/
void mainS ()
{
    //double是返回值类型
    auto fun1 = []()->double{cout << "hello china"; return 1; };
    fun1();

    auto fun2 = [](int a,double b)->decltype(a/b){cout << "hello china"; return a/b; };
    /*decltype(a/b)获取表达式的类型*/
    fun2(1,2.3);
}
/*mutable修改内部副本的值*/
void main()
{
    int a = 10;
    auto fun1 = [a](int v)mutable->double{ v += a;  cout << v << endl; a = 3; return 3; };
    cout << a << endl;
    std::cin.get();
}

  4、Fill例子:

#include <iostream>
#include <vector>
#include <algorithm>
#include <list>
#include <set>
#include <string>
using namespace std;

template <class T>
class show
{
public:
    void   operator ()(T &t)
    {
        cout << t << "  ";
    }

};

void main3()
{
    list <int >  list1;
    vector <int > v1;
    list1.push_back(121);
    list1.push_back(12);
    v1.push_back(121);
    v1.push_back(12);
    //sort(list1.begin(), list1.end());//排序
    //sort(v1.begin(), v1.end());//排序,简单的排序
    //算法依赖于数据结构(链式,线性),不同的数据结构,算法不一样
    fill(v1.begin() + 3, v1.end(), 3);//填充,指定位置数据进行初始化
    /**/

    for_each(list1.begin(), list1.end(), show<int>());
    cout << "\n";
    for_each(v1.begin(), v1.end(), show<int>());

    cin.get();
}

  5、Count,统计例子:

void main4()
{
    multiset<int > myset;
    myset.insert(3);
    myset.insert(1);
    myset.insert(2);
    myset.insert(1);

    int i = 0;
    for (auto ib = myset.begin(), ie = myset.end(); ib != ie;ib++,i++)
    {
    }
    cout << i << endl;

    int num = count(myset.begin(), myset.end(), 1);//统计多少个节点

    cout << num<< endl;
    cin.get();
}

  6、adjacent_find 查找相同一组的元素:
      因为在multiset这红黑树上相同的元素会放在同个节点上,在同个节点上的相同元素按照链表排列。

void  main5()
{
    multiset<int > myset;
    myset.insert(3);
    myset.insert(1);
    myset.insert(2);
    myset.insert(1);

    for_each(myset.begin(),myset.end(), show< const int>());
    auto  it=  adjacent_find(myset.begin(), myset.end());
    cout << "\n" << *it << endl;
    it++;
    cout << "\n" << *it << endl;
    it++;
    cout << "\n" << *it << endl;
    it++;
    cout << "\n" << *it << endl;
    it = adjacent_find(it, myset.end());
    //查找相同的数据,可以自己确定位置
    cout << "\n" << *it << endl;
    it++;
    cout << "\n" << *it << endl;

    cin.get();
}

  7、random_shuffle 打乱数据:

void   main6()
{
    vector<int> v1;
    for (int i = 0; i < 10;i++)
    {
        v1.push_back(i);
    }
    for_each(v1.begin(), v1.end(), show<int>());
    cout << "\n";
    random_shuffle(v1.begin(), v1.end());
    /*打乱原有的数据*/
    for_each(v1.begin(), v1.end(), show<int>());
    cout << "\n";
    random_shuffle(v1.begin(), v1.end());
    for_each(v1.begin(), v1.end(), show<int>());
    cout << "\n";
    random_shuffle(v1.begin(), v1.end());
    for_each(v1.begin(), v1.end(), show<int>());

    cin.get();
}

  8、Partition 分区无序 , rotate转换:

bool  isok(int num)
{
    return (num == 8);
}
void  main7()
{

    vector<int> v1;
    for (int i =10; i>0; i--)
    {
        v1.push_back(i);
    }
    for_each(v1.begin(), v1.end(), show<int>());

    //partition(v1.begin(), v1.end(), isok);
    /*服务于快速排序法的分区,根据最后一个函数包装器,将数据分区,这里将数据分为两个区,8是分界线*/
    rotate(v1.begin(), v1.begin()+8, v1.end());
    //v1.begin(), v1.begin()+8之间的数据移动到后面
    cout << "\n";
    for_each(v1.begin(), v1.end(), show<int>());
    /*
    rotate(v1.begin(), v1.begin()+1, v1.end());
    cout << "\n";
    for_each(v1.begin(), v1.end(), show<int>());

    rotate(v1.begin(), v1.begin() + 1, v1.end());
    cout << "\n";
    for_each(v1.begin(), v1.end(), show<int>());

    rotate(v1.begin(), v1.begin() + 1, v1.end());
    cout << "\n";
    for_each(v1.begin(), v1.end(), show<int>());
    */

    cin.get();
}
bool  isokN(int num)
{
    return (num >12);
}
void  main9()
{
    vector<int> v1;
    v1.push_back(11);
    v1.push_back(8);
    v1.push_back(12);

    for_each(v1.begin(), v1.end(), show<int>());
    partition(v1.begin(), v1.end(), isokN);
    //分块划分,不要求有序
    cout << "\n";
    for_each(v1.begin(), v1.end(), show<int>());
    cin.get();
}

  9、prev_permutation 自动排序并且可以显示:

void  main8()
{
    int a[4] = { 2, 1, 3 ,10};
    do {
        cout << a[0] << " " << a[1] << " " << a[2] <<a[3]<< "\n";
    } while (prev_permutation(a,a+4));//排序并显示步骤

    cin.get();
}

  10、Sort 排序:

void  main10()
{
    vector<char>one;
    one.push_back('B');
    one.push_back('A');
    one.push_back('C');
    for_each(one.begin(), one.end(), show<char>());
    //sort(one.begin(), one.begin() + 3);
    sort(one.begin(), one.begin() + 3); 对前三个排序
    cout << "\n";
    for_each(one.begin(), one.end(), show<char>());

    cin.get();
}

  11、partial_sort 部分排序 :

class student
{
public:
    string name;
    int score;
public:
    student(string str, int num) :name(str), score(num)
    {
    }
    bool operator <(const student &s1)const
    {
        return this->score < s1.score;
    }
};
int main()
{
    vector<student> ss;
    {
        student s1("银城A", 106);
        ss.push_back(s1);
    }
    {
        student s1("银城B", 101);
        ss.push_back(s1);
    }
    {
        student s1("银城C", 103);
        ss.push_back(s1);
    }
    {
        student s1("银城D", 105);
        ss.push_back(s1);
    }
    partial_sort(ss.begin(), ss.begin() + 2,ss.end());
    //将比较的结果中最小的两个排序,,部分排序
    for (int i = 0; i < 4;i++)
    {
        std::cout << ss[i].name << ss[i].score << "\n";
    }
    cin.get();
}

四、GPU编程

  1、Hello

#include <amp.h>
#include <iostream>

using namespace concurrency;
 using namespace std;
void main()
{
    int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    array_view<int> av(10,a);
    //GPU计算结构,av存储到GPU显存,根据数组初始化

    //=直接操作AV,(index<1>idx)操作每一个元素
    //restrict (amp) 定位GPU执行
    parallel_for_each(av.extent, [=](index<1>idx) restrict (amp) {
        av[idx] += 123; 
    });
    for (int i = 0; i < 10;i++)
    {   
        std::cout << av[i] << endl;  

    }
    cin.get();
}

  2、

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值