zoukankan      html  css  js  c++  java
  • c++ primer 读书笔记

    顺序容器:为程序提供控制元素存储和访问顺序的能力,这种顺序与元素加入到容器时的位置相对应,而与元素值无关。

    另外还有根据关键字的值来存储元素的容器:有序、无序关联容器。

    另外STL还有三种容器适配器,用来与容器类型适配。

    顺序容器包括

    vector 可变大小数组
    deque 双端队列,支持随机访问,在front/back插入、删除速度很快
    list 双向链表,只支持顺序访问,在任何位置插入元素很快
    forward_list 单向链表,只支持单向顺序访问
    array 固定大小数组,支持随机访问,不能添加、删除元素
    string 与string相似的容器,专门用与保存字符,随机访问块,在尾部插入、删除速度快

    除array外,其他的绒里都提供高效、灵活的内存管理(改变内存中的元素,数量,改变容器的大小)。

    string/vector将元素存放在连续的内存空间中,可以随机访问,但是添加、删除元素的效率低。

    list和forward_list 添加、删除元素都非常快,代价是不支持随机访问(为了访问某一个元素,需要遍历整个容器)

    deque支持快速的数据访问,与string/vector相似,在中间为止添加/删除元素代价可能很高,但是在首尾位置添加/删除元素很快。

    容器支持、

    类型别名        解释
    iterator    此容器类型的迭代器类型,就是下标|指针
    const_iterator       可以读取元素,但是不能修改元素的迭代器类型
    size_type    无符号类型,足够保存此种容器类型的最大可能容器的大小
    difference_type   带符号整数类型,足够宝尊两个迭代器之间的距离
    
    value_type  元素类型
    
    reference  元素的左值类型,与value_type& 类型相同
    
    const_reference  元素的const左值类型,即 const value_type &
    =========================
    构造函数  解释
    C c;  默认构造函数,构造函数
    C c1(c2);
    C c(b,e);不支持array
    C c{a,b,c...} 列表初始化c
    =========================
    赋值 与swap
    c1 = c2;
    c1 = {a,b,c...}
    a.swap(b)
    swap(a,b)
    =======================
    大小
    c.size();不支持forward_list
    c.max_size()
    c.empty()
    ====================
    添加删除元素/不适用于array
    c.insert(args)
    c.emplace(inits);使用inits构造c中的一个元素
    c.erase(args);删除args制定的元素
    c.clear()  ;删除c中所有的元素,返回void
    =============================
    关系运算符
    ==,!=  ;所有容器都支持相等(不等)运算符
    <,<=,>,>=  ;关系运算符(无序关联容器不支持)
    ==================================
    获取迭代器
    c.begin(),c.end()
    c.cbegin(),cend(),返回const_iterator
    =====================
    反向容器的额外成员(不支持forward_list)
    reverse_iterator
    const_reverse_iterator
    c.rbegin(),c.rend();//返回指向c的尾元素和首元素之前位置的迭代器
    c.crbegin(),c.crend()

    9.2.3 begin和 end 成员

    当不需要写访问时,应使用cbegin和cend成员

    9.2.4容器定义和初始化

    C c;

    C c1(c2)

    C c1 = c2;

    C c{1,2,3...}

    C c={1,2,3,...}

    C c(begin,end);

    ---------只有顺序容器的构造函数才能接收大小参数

    C seq(n)

    C seq(n,t)

    9.2.5

    容器赋值运算

    c1 = c2;

    c = {1,2,c...}

    swap(c1,c2);交换c1/c2中的元素,c1/c2必须具有相同的类型;swap通常比c2向c1拷贝元素快

    c1.swap(c2);

    assign操作不适用于关联容器和array

    seq.assign(b,e)//

    seq.assign(il)//将seq中的元素替换为初始化列表il中的元素

    seq.assign(n,t)

    ####note: swap只是交换了两个容器的内部数据结构,除array外,swap不对元素进行拷贝,删除和插入操作,可以保证在O(1)时间内完成。

    9.3

    向vector/string/deque插入元素会使所有指向容器的迭代器iterator,引用reference,指针pointer失效,所以在跟新了容器的元素时,都应该更新迭代器,引用,指针。

    在一个vector/string的尾部之外的任何位置,或是deque的首尾之外的任何位置天价了元素,都需要移动元素,而且向一个vector/string添加元素可能引起整个对象存储空间的重新分配。重新分配一个对象的存储空间需要分配新的内存,并将元素从旧的空间移动到新的空间中。

    容器元素是拷贝

    当文用一个对象来初始化容器时,或将一个对象插入倒容器中时,实际上放入到容器中的是对象值的一个拷贝,而不是对象本身。就像我们将一个对象传递给非引用参数一样,容器中的元素与提供值的对象之间没有任何关联了。随后对容器中元素任何改变都不会影响到原始对象,反之依然。

    使用emplace操作,新标准引入了三个新成员emplace_front,emplace,emplace_back,这些操作不是构造而是拷贝元素,这些操作对应push_back,insert,push_back,允许我们将元素放置在容器头部,一个指定位置或容器头部

    9.3.2访问元素

    包括array在内的每个顺序容器都有一个front(),

    除了forward_list外,每个顺序容器都有一个back(),分别返回首尾元素

    在顺序容器中访问元素的操作
    at和下标操作符只适用于string,vector,deque,array容器,back不能用于forward_list
    c.back()
    c.front()
    c[n]
    c.at[n]

    访问成员函数返回都是引用,back,front,at,[]返回的都是引用,如果容器是一个const对象,则返回const引用。如果容器不是const,则返回值是普通引用,我们可以引用它改变元素的值:

        if(!c.empty()){
            c.front() = 42;
            auto &v = c.back();
            v = 1024;
            auto v2 = c.back();//如果我们使用auto变量来保存这些函数的值,并且希望使用此变量来改变元素的值,必须记得将变量定义为引用类型 auto &v = c.back();
            v = 0;
        }

    9.3.3

    顺序容器的删除操作
    这些操作会改变容器的大小,不能用于array
    forward_list 有特殊的erase,forward_list不支持pop_back;
    vector/string 不支持pop_back
    c.pop_back()
    c.pop_front()
    c.earse(p)
    c.erase(b,e);
    c.clear()

    9.3.4 特殊的forward_list操作

    forward_list当添加/删除一个元素时,会改变该元素之前、之后的元素指针;

    forward_list没有定义insert,emplace,erase,而是定义了insert_after,emplace_after和erase_after的操作,所以在删除元素之前应该先知道这个元素的首前迭代器;

    #################################

    泛型算法:

    算法如何工作

    find的工作实在一个未排序的元素序列中寻找一个特定的元素,执行的步骤:

    1,访问序列中的首元素

    2,比较此元素与我们要查找的元素

    3,如果此元素与我们要查找的值匹配,find返回标识此元素的值

    4,否则,find前进到下一个元素,重复执行步骤2,3,

    5,如果到达序列末尾,find停止

    6,如果find到达序列末尾,他应该返回一个指出元素未找到的值。此值和步骤3返回的值必须具有相容的类型。

    ============

    初始泛型算法:STL中提供了超过100个算法,有一致的结构,除了少数例外,每个算法都对一个范围内的元素进行操作,此范围就是“输入范围”,前闭后开【)。我们可以根据算法是否读取元素,改变元素,或者重排元素位置来进行区分。

    ##只读算法

    find(vec.cbegin(),vec.end(),val)

    accumulate(vec.cbegin(),vec.cend(),0);

    对于只读而不改变元素的算法,通常最好使用cbegin()和cend();但是有时候根据需要,也需要使用begin(),end();

    equal(vec.cbegin(),vec.cend(),vec2.cbegin()); equal假设:第二个序列至少与第一个序列一样长,

    ##写容器元素的算法

    算法不会执行容器操作,因此他们本身不可能改变容器的大小。但是会修改容器的内容。

    fill(vec.begin(),vec.end(),0);

    算法不要求比较的容器都相同,但是他们的容器类型都必须相同。equal(vec.begin,vec.end(),list1.begin());ok

    插入迭代器back_inserter(),定义在头文件iterator中的一个函数;接受一个指向容器的引用,返回一个与该容器绑定的插入迭代器。

    vector<int> vec;
    auto it = back_inserter(vec);
    *it = 32;

    拷贝算法copy,另一个向目的迭代器指向的输出序列中的元素 写入数据的算法。 接受三个迭代器,前两个是输入范围,第三个表示目的序列的起始位置。

    int a[] = {1,2,3,4,5,6,7};
    int a2[sizeof(a)/sizeof(*a)];a2与a大小一样
    auto ret = copy(begin(a),end(a),a2);//ret = a2.end()

    note:copy(begin(a1),end(a1),a2)  a2的大小要与a1一样长

    replace_copy(ilsit.begin(),ilist.end(),0,2);将ilist中所有的0改变为2

    ##重排容器元素的算法

    sort,会重排输入序列中的元素,使之有序,利用元素类型<(小于)运算符来实现的

    unique, 消除重复单词,首先将vector排序,使得重复的单词相邻出现。返回的位置是  一个指向  不重复值 范围末尾的迭代器。

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    void dlimDups(vector<string> &words){
        sort(words.begin(),words.end());
    
        for(auto i: words){
            cout<<i<<" ";
        }cout<<endl;
    
        auto end_unique = unique(words.begin(),words.end());
        for(auto i: words){
            cout<<i<<" ";
        }cout<<endl;
    
        words.erase(end_unique,words.end());
    
        for(auto i: words){
            cout<<i<<" ";
        }cout<<endl;
    }
    
    int main()
    {
        vector<string> vstr = {"the","quick","red","fox","jumps","over","the","slow","red","turtule"};
        cout<<"vstr.length = "<<vstr.size()<<endl;
    
        for(auto i:vstr){
            cout<<i<<" ";
        }cout<<endl;
    
        dlimDups(vstr);
    
        return 0;
    }

    ##定制操作算法

    sTL允许我们定义自己的操作来代替默认运算符,sort算法默认的比较操作符是<,我们可以定义自己的操作顺序>,>=等。

    我们可以向算法传递函数,或者lambda表达式;

    如果我们希望单词排序程序输出,先按长度排序,大小相同的再按字典顺序来排。

    定义sort(vec.begin,vec.end(),predicate),

    predicate谓词,STL算法使用的谓词分为两类:一元谓词(接受一个参数),二元谓词(有两个参数);由于接受谓词参数的算法对输入序列中的元素调用谓词,那么元素类型必须能转换为谓词的参数类型。

    bool isShorter(const string &s1, const string &s2){
       return s1.size() < s2.size();  
    }

    这个二元谓词函数,在输入序列中所有可能的元素值上面定义了一个一致的序。

    sort(words.begin(),words.end(),isShorter);//按照长度由短至长排序。

    在我们words是按照大小排序的同时,如果还需要长度的元素按字典序排序。这是我们需要使用稳定排序算法: stable_sort(words.begin(),words.end(),isShorter);

    lambada表达式以后再说。

     ===========================================================

    第11章定义关联型容器

    map/set容器

    map中的元素是key-value对;set中每个元素只包含一个关键字;

    set支持高效关键字查找操作---检查一个给定关键字是否在set中,可以定义忽略掉的单词等。

    标准库中提供了8个关联容器,体现在3个不同的维度上:

    1,或者是一个set,或者是一个map
    2,或者要求不重复关键字,或者允许重复关键字
    3,按顺序保存元素,或无序保存元素;

    具体的类型有:

    map/set/mutlimap/multiset/

    unordered_map/unordered_set/

    unordered_multimap/unordered_multiset

    11.2 关联容器概述

    定义关联容器:

    map<string,size_t> word_count;

    set<string> excluds = {"1","b","c"};

    map<string,string> author = {{"b","b_value"},{"c","c_value"}};

    初始化multimap/multiset,一个map/set中的关键字必须是唯一的,即对于一个给定的关键字,只能有一个元素的关键字对应它。

    vector<int> ivec;

    for(vector<int>::size_type i = 0;i != 10;i++){

      ivec.push_back(i);ivec.push_back(i);

     }

    set<int> iset(ivec.cbegin(),ivec.cend());

    11.2.2 关键字类型的要求

    默认情况下,STL使用关键字类型的小于符号来比较两个关键字;在set类型中,关键字类型就是元素类型;在map类型中,关键字类型是元素的第一部分的类型。

    可以向一个算法提供我们自己定义的比较操作,也可以定义自己定义的操作来代替关键字小于运算服。所提供的操作必须在关键字类型上定义一个严格弱序,这个严格弱序不一定是“小于等于”。

    使用关键字类型的比较函数,为了指定使用自定义的操作,必须在定义关联容器类型时提供此操作的类型,用尖括号支出要定义的哪种类型的容器,自定义的操作类型必须在尖括号紧跟着元素类型给出。

    bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs){

      return lhs.isbn() < rhs.isbn();

    }

    multiset<Sales_data, decltype(compareIsbn)*>  bookstore(compare)  --->C++ primer chinese Page379

    11.2.3 pair type

    #include <utility>

    pair<type_1,type_2> mypair;

    pair<T1,T2> p;
    pair<T1,T2> p(v1,v2);
    pair<T1,T2> p = {v1,v2};
    make_pair(v1,v2);
    p.first
    p.second
    p1 relop p2// <, > ,<=, >=  //c++ primer 5th Page 380
    p1 == p2
    p1 != p2

    11.3

    key_type 容器的关键字类型

    mapped_type 每个关键字关联的类型,只用于map,就是值类型;例如,map<string,int>::mapped_type v5;//v5 is int

    value_type 对于set来说,它与keytype相同;对于map来说, is pair<const key_type,mapped_type>

    定义关联型迭代器,当解引用一个关联容器迭代器时,我们会得到一个类型为容器的value_type,对于map来说,value—type是一个pair类型,其first成员是一个const关键字,但是second不是const的

    另外set的迭代器是const,就是不能利用解引用符号来修改set中的元素值。例如×set—it = 42,是不允许的,因为set—it是一个只读类型

    关联容器和算法,通常我们不对关联容器使用泛型算法。const意味着不能将关联容器传递给修改或重排容器元素的算法,因为这类算法需要向元素写入值,set类型中的元素是const,map中的元素是pair,但是第一个元素是const;

    so,关联容器只能用于读取元素的算法,但是很多这类算法,需要搜索序列,由于关联容器中的元素不能通过他们的关键字进行快速查找,因此对其使用泛型算法没有什么意思。但是关联容器总是有一个find成员,通过一个给定的关键字来直接获取元素。

    11.3.2 添加元素

    利用insert函数,或者emplace函数,

    对于set来说,插入重复数据,没有什么影响;

    对于map来说,需要插入的pair类型,因此需要利用原始数据创建pair;insert的返回值是一个pair,pair的first成员是一个迭代器,指向具有给定关键字的元素,second成语根据是否是新插入的元素返回true(是)/false(原来就有的)

    初级展开语句

    ret

    ret.first

    ret.first->  

    ret.first->second

    ++ret.first->second     =  ++((ret.first)->second);

    11.3.3 delete elements

    c.erase(k);//kye = k, return size_type,  is a quantity of deleted elements

    c.erase(p); // p is a iterator, is the next element of deleted elemtent

    c.erase(b,e)

    11.3.4 map index control

    there is not [] in set.

    11.3.5 access elements

    find();

  • 相关阅读:
    理解css中min-width和max-width,width与它们之间的区别联系
    html实现时间轴_纯css实现响应式竖着/垂直时间抽布局效果
    web页面的重构和回流【转载】
    介绍web开发中实现会话跟踪的常用技术方法
    web标签语义化的理解_web语义化是什么意思
    从浏览器地址栏输入url到显示页面的步骤(以HTTP为例)
    H5调用手机的相机/摄像/录音等功能 _input:file的capture属性说明
    相邻元素之间的margin合并问题
    HTML连载33-背景定位
    Java连载22-for循环
  • 原文地址:https://www.cnblogs.com/li-daphne/p/5450885.html
Copyright © 2011-2022 走看看