C++笔记之——顺序容器

顺序容器为程序员提供了控制元素储存和访问顺序的能力,这种顺序不依赖与元素的值,而是与元素加入容器时的位置相对应。
所有顺序容器都提供了快速顺序访问元素的能力。
1.顺序容器概述
顺序容器有:vector;deque;list;forward_list;array;string.
    1.1 vector
        可变大小数组,支持快速随机访问,在尾部之外的位置插入或者删除元素会很慢。
    1.2 deque
        双端队列,支持快速随机访问。在头尾位置插入删除速度很快。
    1.3 list
        双向链表,只支持双向顺序访问,在list中任何位置插入删除操作都很快。
    1.4 forward_list
        单向链表,只支持单向顺序访问,在链表中任何位置插入删除操作都很快
    1.5 array
        固定大小的数组。支持快速随机访问。不能添加删除元素。
    1.6 string
        用于保存字符,随机访问快,在尾部插入删除速度快。    

    标准库类型vector;deque;list;forward_list;array;表示对象的集合,其中所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引,索引用于访问对象,因为vector;deque;list;forward_list;array;容纳着其他对象,所以常称为“容器”。
使用vector;deque;list;forward_list;array;类型必须首先包含vector;deque;list;forward_list;array;头文件。
vector;deque;list;forward_list;array;的定义在命名空间std中。

    c++语言既有类模板也有函数模板,其中vector;deque;list;forward_list;array;是一个类模板。模板本身不是类和函数,相反可以将模板看作为编译器生成类或者函数编写的一份说明,编译器根据模板创建类或者函数的过程称为实例化,当使用模板类时,需要指出编译器应把类或者函数实例化成何种类型。
2.初始化
    2.1 vector;deque;list;forward_list;
        array初始化:array<int,10> a;
        container<int> a1;  默认初始化
        container<int> a2 = {1,2,3,4};列表初始化
        container<int> a3(a2);拷贝初始化
        container<int> a4=a3;拷贝初始化
        container<int> a5(5, 1);值初始化
        container<int> a6{1,2,3,4};列表初始化
        container<int> a7(a6.begin(),a6.end());(不适用于array)
        container<int> a8(a6.begin()+1,a6.end()-1);(不适用于array)
        container<int> a9(&a6[0],&a6[4]);(不适用于array)
    2.2 string
        string a1;  默认初始化,a1是个空字符串;
        string a2 = "hello";拷贝初始化,a2是字面值hello的一个副本
        string a3(a2);拷贝初始化,a3是字面值a2的一个副本
        string a4=a3;拷贝初始化,a4是字面值a3的一个副本
        string a5(5, '1');直接初始化,a5="11111"
        string a6("hello5");直接初始化
        string a7(a6.begin(),a6.end());直接初始化
        string a8(a6.begin()+1,a6.end()-1);直接初始化
        string a9(&a6[0],&a6[4]);直接初始化
3.操作
    3.1 begin和end;cbegin和cend;rbegin和rend;crbegin和crend;
        c.begin(),c.end()返回指向c的首元素和尾元素之后位置的迭代器。
        c.cbegin(),c.cend()返回const_iterator
        c.rbegin(),c.rend()返回c的尾元素和首元素之前位置的迭代器(不支持forward_list)
        c.crbegin(),c.crend()返回const_reverse_iterator(不支持forward_list)

        list<int> b = { 1,2,3 };
        list<int>::iterator i1 = b.begin();
        list<int>::iterator i2 = b.end();
        for (auto i = i1; i != i2; i++)
            cout << *i;
        cout << endl;   123
        list<int>::reverse_iterator i4 = b.rbegin();
        list<int>::reverse_iterator i3 = b.rend();
        for (auto i = i4; i != i3;i++)
            cout << *i ;
        cout << endl; 321
    3.2 swap和assign
        list<int> a,b ;
        swap(a,b),a.swap(b)交换a,b中的元素,比a=b快
        assign不适用于array
        a.assign(b)将a中元素替换为b中的元素,
        a.assign(m,n)将a中元素替换为迭代器m,n中的元素,迭代器m,n不能指向a
    3.3 push_front,push_back和insert
        array都不支持
        push_front将元素插入到头部,list,forward_list,deque支持
        push_back将元素插入到尾部,list,vector,string,deque支持
        insert允许在容器中任意位置插入0个或者多个元素,vector,deque,list,string都支持,forward_list支持特殊版本的insert成员。
        insert返回值为指向第一个新加入元素的迭代器。如果没有插入任何元素则返回第一个参数
        vector<int> b = { 1,2,3 };
        b.insert(b.end(),4);  1234
        b.insert(b.begin(), b.end() - 2, b.end()); 341234
        b.insert(b.end(), 4, 5);3412345555
        forward_list支持特殊版本的insert成员:
        lst.insert_after(p,t)
        lst.insert_after(p,n,t)
        lst.insert_after(p,b,e)
        lst.insert_after(p,il)
        在迭代器p之后插入元素,t是一个对象,n是数量,b,e是表示范围的一对迭代器,il是一个花括号列表,返回一个指向最后一个插入元素的迭代器。
    3.4 emplace
        emplace_front,emplace,emplace_back。这些操作是构造而不是拷贝,对应push_front,insert,push_back.
        当调用push,insert时我们将元素的对象传递给他们,然后被拷贝到容器中。调用emplace则将参数传递给元素类型的构造函数。假设c保存Sales_data类:
        c.emplace_back("978-05",25,15);正确
        c.push_back("978-05",25,15);错误
        c.push_back(Sales_data("978-05",25,15))正确
        c.emplace_back()使用Sales_data默认构造函数。
        forward_list支持特殊版本的emplace成员:
        emplace_after(p,args)使用args在p指定的位置创建一个元素,返回一个指向这个新元素的迭代器。
    3.5 front,back,at
        每个顺序容器都有一个front成员函数,返回容器中首元素的引用。
        auto val = c.front()  ==  auto val1=*c.begin()
        除了forward_list之外的顺序容器都有一个back成员函数,返回尾元素的引用。
        auto val2 = c.back()   == auto val3=*(--c.end())
        at只适用于string,vector,deque,array,返回下标n的元素的引用,如果下标越界,则抛出一out_of_range异常。
        c.at(n)
        提供快速随机访问的容器string,vector,deque,array也都提供了下标运算符,返回容器中该元素的引用。c.front=42;auto val=c.front() ;val=10不改变c。auto &val=c.front() ;val=10改变c。
        给出的下标必须在范围内,下标运算符并不检查下标是否在合法范围内,使用越界的下标是一种严重的程序设计错误,而且编译器并不检查这种错误。可以使用at,如果越界则抛出异常。
        vector<int> data;空vector
        cout<<data[0];运行出错
        cout<<data.at(0);抛出一个out_of_range异常。
    3.6 pop_back,pop_front,erase,clear
        array都不支持
        c.pop_front(),删除c中首元素,vectorstringarray不支持.若c为空,则函数行为未定义。函数返回void。
        c.pop_back(),删除c中尾元素,forward_list不支持.若c为空,则函数行为未定义。函数返回void。
        c.erase(p),删除迭代器p所指定的元素,返回一个指向被删除元素之后元素的迭代器,若p指向尾元素,则返回尾后迭代器。
        c.erase(b,e)删除迭代器b和e所指定范围内的元素,返回一个指向最后一个被删除元素之后元素的迭代器。
        forward_list支持特殊版本的erase成员:
        lst.erase_after(p)
        lst.erase_after(b,e)
        删除p指定位置之后的元素,或删除从b之后直到但不包含e之间的元素的迭代器。返回一个指向被删除元素之后的迭代器。
        c.clear()删除c中所有元素,返回void,==c.erase(c.begin(),c.end())
    3.7 string额外操作
    3.7.1 包含在cctype头文件中
        c是字符,下列返回值都是为int类型
        isalnum(c) 当c是字母或者数字为真
        isalpha(c) 当c是字母为真
        isdigit(c) 当c是数字为真
        islower(c) 当c是小写字母为真
        isupper(c) 当c是大写字母为真
        isspace(c) 当c是空白字符为真
        ispunct(c) 当c是标点为真
        isprint(c) 当c是可打印字符为真
        tolower(c) 返回小写字母
        toupper(c) 返回大写字母
        #include<iostream>
        #include<string>
        #include<cctype>
        using namespace std;
        int main()
        {
            string a1="zh1, an2";
            int alpha = 0;
            int digit = 0;
            int punct = 0;
            for (auto &i : a1)
            {
                if (isalpha(i))
                    ++alpha;
                if (isdigit(i))
                    ++digit;
                if (ispunct(i))
                    ++punct;
                i=toupper(i);
            }
            cout << alpha << endl;
            cout << digit << endl;
            cout << punct << endl;
            cout << a1 << endl;
            system("pause");
            return 0;
        }
        4
        2
        1
        ZH1, AN2
        请按任意键继续. . .
        3.7.2 substr
            s.substr(pos,n)从pos开始n个字符拷贝,pos默认值为0,n默认值为s.size()-pos
            string s("hello world");
            string s2=s.substr(0,5);  hello
            string s3=s.sbustr(6); world
            string s4=s.substr(6,11);world
        3.7.3 数值转换
            int i=42;
            string s=to_string(i);
            double d=stod(s);
            int i=stoi(s)
            string s2="pi=3.14"
            d=stod(s2.substr(s2.find_first_of("+-1234567890")))         
        3.7.2 查找字符
            s.find(args)查找s中args第一个出现的位置
            string s("hello 123")
            s.find('1')
            s.rfind(args)最后一次出现位置
            s.find_first_of(args) args中任意字符第一次出现位置
            s.find_first_of("1234567890")
        3.7.3 子串查找
        #include<algorithm>
        int main()
        {
            string a1="zh1, an2";
            string a2 = "an";
            string::iterator a_f=search(a1.begin(), a1.end(),a2.begin(),a2.end());
            cout << a_f-a1.begin() << endl;
            system("pause");
            return 0;
        }       
4 容器操作可能使迭代器失效
    4.1 vectorstring
    插入元素时,若引起空间重配,则迭代器、引用、指针都失效。
    若未引起空间重配,则插入位置之前的迭代器、引用、指针仍有效,但指向插入位置之后的迭代器、引用、指针将会失效。
    删除元素时,删除位置之前的迭代器、引用、指针仍有效,但删除位置之后的迭代器、引用、指针一律无效。
    4.2 deque
    插入元素时,若插入到除首尾位置之外的任何位置,都会引起迭代器、引用、指针失效。
如果在首尾位置插入元素,则迭代器失效,引用和指针不会失效。
删除元素时,若删除的不是首尾元素,则迭代器、引用、指针都会失效。若删除的是首元素,则除指向首元素的迭代器、引用、指针收到影响,指向其他元素的迭代器、引用、指针仍有效。删除尾元素也是一样,只有被删除的元素受到影响,其他不会受到影响。
    4.3 list,forward_list
    插入和删除元素时,其他迭代器、指针、引用都仍然有效!
5.容器适配器
    适配器是标准库中的一个通用概念。容器,迭代器和函数都有适配器,本质上一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物。
    5.1 stack
    堆栈适配器,先进后出。
    stack<int>intstack;
    s.pop()删除栈顶元素
    s.push(item)创建一个新元素压入栈顶
    s.emplace(args)
    s.top()返回栈顶元素,但不将元素弹出栈
    5.2 queue,priority_queue
    队列适配器,先进先出
    定义一个queue的变量     queue<Type> M
    查看是否为空范例        M.empty()    是的话返回1,不是返回0;
    从已有元素后面增加元素   M.push()
    输出现有元素的个数      M.size()
    显示第一个元素          M.front()
    显示最后一个元素        M.back()
    清除第一个元素          M.pop()

    priority_queue提供了三个基本函数,分别是:
    top()
    push()
    pop()
    注意,pop并不会返回元素,top才会返回堆顶的元素。

    stack:底层一般用listdeque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时。只要求push_back,pop_back,back操作,可以使用除了array和forword_list之外的其他容器来构造容器。
    queue:底层一般用listdeque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时(stackqueue其实是适配器,而不叫容器,因为是对容器的再封装)。要求back,front,push_back,push_front,因此可以构造在listdeque上。
    priority_queue:的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现,除了front,push_back,pop_back,之外还要随机访问能力,可以构造在vectordeque上。
    创建一个适配器将一个命名的顺序容器作为第二个参数类型。
    vector<int> data{1,2,3,4};
    stack<int, vector<int> >da(data);

    所有适配器都要求容器具有添加和删除元素的能力,因此不能构建在array上
    所有适配器都要求容器具有添加,删除以及访问尾元素的能力,因此不能构造在forward_list上




猜你喜欢

转载自blog.csdn.net/zd_nupt/article/details/80526209
今日推荐