chapter-9

C++ Primer第九章!

#include "stdafx.h"
#include<iostream>
#include<list>
#include<string>
#include<array>
#include<vector>
#include<deque>
#include<forward_list>
#include<stack>

using namespace std;

int main()
{
    //容器就是一些特定类型对象的集合,顺序容器为程序员提供了控制元素存储和访问的能力!(即数据按地址顺序存储)
    //vector            可变大小的数组,支持快速访问,在尾部之外插入或删除元素都可能很慢
    //deque             双端队列,支持快速访问,在头尾位置插入或删除元素速度很快
    //list              双向列表,只支持双向顺序访问,在list任何位置插入或删除元素都很快
    //forward_list      单向列表,只支持单向顺序访问,在forward_list任何位置插入或删除元素都很快,其迭代器不支持--!
    //array             固定大小数组,支持快速访问,不能添加或删除元素
    //string            与vector相似的容器,只用于储存字符

    //vector和string,元素连续存储,支持下标快速访问;list和forward_list,不支持随机访问,中间插入数据快,内存开销大;deque,支持下标快速访问,支持头尾插入删除元素;array固定大小数组。
    //使用原则:1、除非有更好的选择,否则选用vector;2、如果元素很多且在乎内存开销,则不要使用list或forward_list;3、如果程序要求随机访问元素,应使用vector和deque;4、如果程序头尾操作而中间不操作,应选用deque;
    
    //容器通用操作
    //iterator              迭代器
    //const_iterator        const迭代器
    //size_type             无符号整型,容器最大容积
    //difference_type       带符号整型,两个迭代器之间的距离
    //value_type            元素类型
    //reference             元素的引用,用value_type &
    //const_reference       const
    //C c                   定义容器,默认构造函数构造空容器
    //C c1(c2)              构造c2的拷贝c1!创建容器的2种拷贝方式,使用迭代器时两个容器类型和函数类型可以不匹配,只要被拷贝的元素可以隐式转换!
    //C c(b,e)          构造c,将迭代器b和e指定范围内的元素拷贝到c。
    //C c{a,b,c...}         列表初始化c
    //C seq(n),seq(n,t)     seq包含n个元素,这些元素值被初始化(string不适用)。只有顺序容器才接受大小参数(不包括array)
    //c1=c2                 将c1中元素替换为c2中元素
    //c1={a,b,c...}         将c1中元素替换为列表中元素
    //a.swap(b)             交换容器a和容器b中的元素
    //swap(a,b)             等价于上
    //c.size()              返回c中的元素数目(不支持单向forward_list)
    //c.max_size()          返回c中所能容纳最大元素数目
    //c.empty()             容器c是否为空,当size为0返回true
    //c.insert(args)        将args中元素拷贝进c
    //c.emplace(inits)      使用inits构造c中的一个元素
    //c.rease(args)         删除指定元素
    //c.clear()             删除所有元素
    //==,!=,<,>             容器关系运算符,关系运算符左右两边的运算对象必须是相同类型的容器和相同类型的元素(元素必须定义了比较运算符)
    //c.begin(),c.cbegin(),c.end(),c.cend()     迭代器
    //reverse_iterator,const_reverse_iterator,c.rbegin(),c.rend(),c.crbein(),c.crend()  反向迭代器,执行++操作,会得到上一个元素!

    list<string> a = { "aa","bb","cc" };
    list<string> b(a);
    auto beg = a.crbegin();
    while (beg!=a.crend())
    {
        cout << " " << *beg;
        ++beg;
    }
    cout << endl;

    //标准库array初始化方式
    array<int, 10> ary1;            //类型为:保存10个int的数组
    array<int, 10> ary2 = { 0,1,2,3,4 };
    array<int, 10> ary3 = ary2;     //不能对内置数组进行拷贝或对象赋值,但是array可以,不过却不能使用ary3={0}形式!(元素类型和大小必须相同)

    //容器赋值运算(适用于所有容器)
    //c1=c2
    //c={a,b,c}             array不适用
    //swap(c1,c2)
    //c1.swap(s2)               交换两个相同类型容器的内容
    //assign操作不适用于关联容器和array,assign将右侧运算对象中所有元素拷贝到左边元算对象中
    //seq.assign(b,e)           将seq中元素替换为迭代器be所示范围内的元素,迭代器不能指向seq
    //seq.assign(il)            将seq中的元素替换为初始化列表il中的元素
    //seq.assign(n,t)           将seq中的元素替换为n个值为t的元素(assign是分配的意思!)
    
    list<string> lst1 = { "aa","bb","cc" };
    vector<string> vec1;
    vec1.assign(lst1.cbegin(), lst1.cend());

    list<string> lst2;
    swap(lst1, lst2);           //除了array外,swap不对任何元素进行操作,因此保证操作时间很短!
    lst2.insert(lst2.cbegin(), { "a","b" });

    if (lst1 == lst2)
        cout << "lst1 等于 lst2" << endl;
    else
        cout << "lst1 不等于 lst2" << endl;

    //顺序容器特有操作!这些操作会改变容器的大小,array不支持这些操作!
    //forward_list有自己专用insert和emplace,并且不支持push_back和emplace_back。
    //vector和string不支持push_front和emplace_front
    //当用对象初始化容器,或者将一个对象插入容器中,实际放入的是拷贝,而不是对象本身!
    //将元素插入(insert)到vector、deque、string合法,但是很耗时!
    //c.push_back(t)
    //c.emplace_back(args)
    //c.push_front(t)
    //c.emplace_front(args)     args为实参,传递给类的构造函数,直接在容器内构造元素。c.emplace_back(a,b,c)等价于c.push_back(class(a,b,c))!
    //c.insert(p,t)             在迭代器p指向元素之前创建一个值为t的元素(或由args创建的元素),返回指向新元素的迭代器!
    //c.emplace(p,args)         
    //c.insert(p,n,t)           同下
    //c.insert(p,b,e)           同下
    //c.insert(p,il)            il为花括号包围的元素值列表({a,b,c}),插到迭代器p指向元素之前,返回指向新添加的第一个元素的迭代器,若列表为空返回p!

    //顺序容器中访问元素的操作
    //at和下标操作只适用于string、vector、deque、array
    //back不适用于forward_list
    //c.back()              返回c中尾元素的引用,若c为空则函数行为未定义
    //c.front()             返回c中首元素的引用···
    //c[n]                  返回c中下标为n的元素的引用,n为无符号整数,若n>c.size(),则行为未定义
    //c.at(n)               同上,但是如下标越界,抛出out_of_range异常!推荐使用at函数!
    deque<int> deq1 = { 1,2,3 };
    auto &r = deq1.front();         //使用auto&获取第一个元素的引用!
    r = 3;
    
    //顺序容器删除元素。这些操作会改变容器的大小,array不支持这些操作!
    //forward_list有特殊版本的erase,并且不支持pop_back;vector和string不支持pop_front
    //c.pop_back()      删除c中尾元素。若c为空,则行为未定义。
    //c.pop_front()     删除c中首元素。若c为空,则行为未定义。
    //c.erase(p)        删除迭代器P所指元素,返回被删除元素之后元素的迭代器。若p指向尾迭代器,行为未定义!
    //c.erase(b,e)      
    //c.clear()         删除所有元素!

    //特殊的forward_list操作,单向链表,只有后驱(指向下一个元素)
    //lst.before_begin()                返回首元素之前不存在元素的迭代器,此迭代器不能解引用
    //lst.cbegore_begin()
    //lst.insert_after(p,t)             在迭代器p之后插入元素t。若p为尾后迭代器,则函数行为未定义!
    //lst.insert_after(p,n,t)
    //lst.insert_after(p,b,e)
    //lst.insert_after(p,il)
    //lst.emplace_after(p,args)
    //lst.erase_after(p)
    //lst.erase_after(b,e)              返回被删元素之后元素的迭代器!
    forward_list<int> flst = { 1,2,3,4,5,6 };
    auto prev = flst.before_begin();
    auto curr = flst.begin();
    while (curr != flst.end())
    {
        if (*curr % 2)
            curr = flst.erase_after(prev);          //删除某个元素,要使用指向前一个元素的迭代器!该函数返回指向被删元素之后的迭代器
        else
        {
            prev = curr;
            curr++;
        }
    }
    for (auto &r : flst)
    {
        cout << r << "--";
    }
    cout << endl;

    //改变容器大小,array不支持resize()
    //c.resize(n)               若容器缩小,则删除多余元素;若容器扩大,则默认初始化(推荐使用t初始化!)
    //c.resize(n,t)

    //容器的操作可能会使迭代器(包括指针、引用)失效!必须保证每次改变容器的操作后都能正确地重新定位迭代器!(每次操作后必须重新调用end()获取尾后迭代器)

    //vector对象是如何增长的?vector和string通常会分配比需求更大的空间,留作备用!
    //shrink_tofit只使用于vector、string和deque
    //capacity和reserve只适用于vector和string
    //c.shrink_to_fit()         将capacity减小为与size()相同大小,但不保证一定退回内存空间
    //c.capacity()              不重新分配内存,c可以保存多少元素
    //c.reserve(n)              分配至少能容纳n个元素的内存空间(调用reserve后,capacity将会大于或等于n)
    vector<int> vec_cap = { 0,1,2,3 };
    vec_cap.push_back(4);
    cout << vec_cap.size() << " " << vec_cap.capacity()<<endl;

    //额外的string操作
    //n,len2和pos2都是无符号值
    //string s(cp,n)                cp指向数组的前n个字符的拷贝(char *cp)
    //string s(s2,pos2)             从string s2的下标pos2开始的拷贝,如果pos2越界,行为未定义!
    //string s(s2,pos2,len2)        至多拷贝s2.size()-pos2(遇见空字符结尾停止)
    
    //s.substr(pos,n)               返回一个string,包含s从pos开始的n个字符,pos的默认值为0,n的默认值为s.size()-pos。

    //修改string的操作,P324
    //s.insert(pos,args),s.erase(pos,len),s.assign(args)(替换所有内容),s.append(args)(将新字符追加到末尾),s.replace(range,args).(args实参可以是str/str,pos,len/cp,len/cp/n,c/b,e/初始化列表等)

    //string搜索操作,如果搜索成功则返回string::size_type()下标值(无符号类型,建议使用无符号类型保存函数返回值),如果搜索失败则返回string::npos的static成员。
    //s.find(args)                          查找args第一次出现的位置
    //s.rfind(args)                         查找args最后一次出现的位置
    //s.find_first_of(args)                 在s中查找args任何一个字符第一次出现的位置
    //s.find_last_of(args)                  在s中查找args任何一个字符最后出现的位置
    //s.find_first_not_of(args)             在s中查找第一个不再args中的位置
    //s.fing_last_not_of(args)              在s中查找最后一个不再args中的位置
    //args必须是如下形式:c,pos/s2,pos/cp,pos/cp,pos,n(pos和n无默认值)等。其余pos默认值为0!
    string s_out_exp = "-a-b-c";
    cout << s_out_exp.substr(s_out_exp.find_first_of("-")+1)<<endl;

    //string的比较compare函数,根据结果等于、大于、小于,返回0、整数、负数!
    //s.compare(args),其参数args有如下形式:s2/pos1,n1,s2/pos1,n1,s2,pos2,n2/cp/pos1,n1,cp/pos1,n1,cp,n2
    string s_out_com = "-b";
    cout << s_out_com.compare(s_out_exp) << endl;

    //string的数值转换
    //to_string(val)        返回数值val的string表示
    //stoi(s,p,b)/stol(a,p,b)/stoul/stoll/stoull/,b表示基数(默认为10),若转换失败返回out_of_range异常
    //stof(s,p)/stod/stold
    string s_pi = "pi=3.14";
    double d_pi;
    d_pi = stod(s_pi.substr(s_pi.find_first_of("+-.0123456789")));      //第一个非空白字符必须是···
    cout << d_pi << endl;

    //容器适配器,即stack栈、queue队列、priority_queue,是某种事物的行为看起来像另一种事物!
    //所有容器适配器都支持的操作
    //size_type         一种类型,大小
    //value_type        元素类型
    //container_type    适配器底层容器类型
    //A a               创建空适配器a
    //A a(c)            创建适配器a,带有容器c的一个拷贝
    //a.empty()         
    //a.size()
    //swap(a,b)/a.swap(b)       同类型,且底层容器类型相同
    //stack只要求push_back、pop_back和back操作,可以使用deque/list/vector容器!queue要求使用back、push_back、front、push_front,可以使用list/deque/vector容器!priority_queue要求使用front、push_back、pop_back、随机访问能力,可以使用vector和deque!
    deque<int> deq_sta = { 0 };
    stack<int> stk(deq_sta);            //默认情况stack和queue是基于deque实现的,priority_queue是基于vector实现的!
    stack<string, vector<string>> str_stk;
    
    //stack操作,不能使用deque的操作,只能使用自己的!(先进后出)
    //s.pop()           删除栈顶元素,但不返回该值!
    //s.push(item)      创建新元素,压入栈顶
    //s.emplace(args)
    //s.top()           返回栈顶元素,但不将元素删除
    str_stk.push("abc");
    cout << str_stk.top() << endl;

    //queue和priority_queue队列的操作(queue先进先出,priority_queue为每个元素建立优先级(默认使用<运算符),新加入元素根据优先级排列(饭店根据预约时间排座,而不是到店时间))
    //q.pop()           删除queue首元素或priority_queue最高优先级元素,但不返回此元素
    //q.front()         返回首元素或尾元素,但不删除此元素
    //q.back()          只适用于queue
    //q.top()           返回最高优先级元素,但不删除此元素,只适用priority_queue
    //q.push(item)      在queue末尾或priority_queue中适当位置创建一个元素
    //q.emplace(args)

    system("pause");
    return 0;
}

//容器是c++相当重要的一部分,推荐使用好容器!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容