第9章 顺序容器

Posted xiaogaogao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第9章 顺序容器相关的知识,希望对你有一定的参考价值。

exercises section 9.2

9.2

list<deque<int> > list_deque_int;

section 9.2.1  迭代器

1、迭代器与容器一样有公共的接口(forward_list的迭代器不支持递减运算符(--)

exercise section 9.2.1

9.3、

1.迭代器必须指向同一个容器中的元素,或者容器最后一个元素之后的位置。

2.end不在begin之前。

9.4、

//p9_4.cpp
#include <vector>
#include <iostream>

using namespace std;

bool find(vector<int>::iterator first, vector<int>::iterator last, int val)
{
    bool exist = false;      //用来指示是否找到指定值,初始为false

    for(auto ix = first; ix != last; ++ix)//遍历迭代范围
    {
        if(*ix == val)      //若值相等
        {
            exist = true;   //说明找到了指定的值
            break;          //停止迭代
        }
            
    }

    return exist;           //返回exist,若存在则exist为true,否则为false
}

9.5、

vector<int>::iterator find(vector<int>::iterator first, vector<int>::iterator last, int val)
{
    for(vector<int>::iterator it = first;it != last; ++it)
    {
        if(*it == val)
        return it;
    }

    return last;      //若没有找到则返回迭代器范围内的最后一个元素后的位置
}

9.6、

list的迭代器没有<关系运算符

9.2.2 Container Type Members


size_type  iterator  const_iterator  value_type  reference  const_reference

exercise section 9.2.2

9.7、

vector<int>::size_type

9.8、

list<string>::iterator  //读写

list<string>::const_iterator //读

 

9.2.3 begin and end Members


begin  cbegin  rcbegin  end  cend  rcend  rbegin  rend

exercise section 9.2.3

9.9、

begin: 返回的iterator依赖于容器的类型,若容器为const则返回const_iterator,否则返回iterator,

cbegin: 返回const_iterator

9.10、

it1 : iterator  it2 : const_iterator  it3 : const_iterator  it4 : const_iterator

9.2.4 Defineing and Initializing a Constainer


1、复制另一个容器初始化(直接复制具有相同元素相同类型的容器、使用迭代器范围复制元素可以转化的容器)

2、用花括号列表初始化

3、Size-Related Constructors :(num,value)  //num表示数量,value表示值(若省略则按元素默认值初始化)

exercise section 9.2.4

9.11、

vector<int> vec;  //empty

vector<int> vec1(10);  //10 elements with value 0

vector<int> vec2(10,1);  //10elements with value 1

vector<int> vec3(vec2);  //same as vec 2

vector<int> vec4(vec2.begin(), vec2.end());  //same as vec2

vector<int> vec5{0, 1, 2, 3, 4, 5};  //6 elements with corresponding value as curly braces

9.12、

使用一个容器对象作为参数的容器构造函数,容器类型和元素类型都需要和构造函数的类型相同

使用迭代器作为参数的构造函数,没有此限制(只要元素能够转换成相应的元素类型都可以)

9.13、

//p9_13.cpp
#include <iostream>
#include <vector>
#include <list>

using namespace std;

int main()
{
    list<int> lis{1, 3, 5, 7, 9};
    vector<int> ivec(10, 1);

    vector<double> dvec(lis.begin(), lis.end());
    vector<double> dvec1(ivec.begin(), ivec.end());

    cout << "dvec : ";
    for(auto ix : dvec)
        cout << ix <<  ;
    cout <<
;
    cout << "dvec2 : ";
    for(auto ix : dvec1)
        cout << ix <<  ;
    cout << 
;

    return 0;
}

9.2.5 Assignment and swap

build-in arrays : 不允许使用 = 赋值

library array : 可以但左右的类型和大小都要相同

swap: 除了array(数组)swap不复制、删除或插入任何元素。

对array使用swap会交换元素

新标准定义了成员swap和非成员swap,一般使用非成员版的

exercises section 9.2.5

9.14、

//p9_14.cpp
#include <list>
#include <string>
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    list<char *> cstr = {"hello", "world", "good", "good", "study"};
    vector<string> strvec;
    strvec.assign(cstr.begin(), cstr.end());

    cout << "strvec: " ;
    for(auto ix : strvec)
        cout << ix <<  ;
    cout << 
;

    return 0;
}

9.2.6 Container Size Operations

size  empty  max_size

forward_list 没有size

9.2.7 Relational Operators

1、所有的容器都支持==、!=; 除无序关联容器外还支持 >  >=  <  <=;

2、进行关系运算的两个容器的容器类型和容器中的元素类型都必须相同

3、容器的关系运算符使用了底部元素的关系运算符,如果要对自定义的类型作为容器元素的容器作关系运算,必须定义底层元素的关系运算

exercises section 9.2.7

9.15、9.16

//p9_15.cpp
#include <iostream>
#include <vector>
#include <list>

using namespace std;

int main()
{
    vector<int> vec{ 1, 2, 3, 4, 5, 6 };
    vector<int> vec2(10, 1);
    vector<int> temp;
    list<int> lis(10,2);

    if (vec == vec2)
        cout << "yes" << endl;
    else
        cout << "no" << endl;
    
    temp.assign(lis.begin(), lis.end());
    if (vec == temp)
        cout << "vec == lis" << endl;
    else
        cout << "vec != lis" << endl;
    return 0;
}

9.17

c1和c2必须是同类型的非关联容器,且底部元素也要相同且支持<运算

9.3 Sequential Container Operations

1 push_back  2 push_front  3 emplace_back  4 emplace_front  5 emplace  6 insert(3种用法)

1、push_back除了 array 和 forward_list 所有的顺序容器都支持push_back.

  push_front : list  forward_list  deque

2、可以对不支持push_front的容器使用insert在第一个元素前增加元素

3、对vector deque string使用 insert 插入任何位置都是合法的,但是耗费资源

4、获取iterator 范围不能是目标容器的

5、emplace_back 和 push_back 的区别是 push_back 先创建一个局部临时对象,emplace_back 直接在container 管理的空间构造一个对象

6、emplace 函数的参数必须和容器中元素的构造函数的参数相匹配

 

exercise section 9.3.1


9.18、

//p9_18.cpp
#include <iostream>
#include <deque>
#include <string>

using namespace std;

int main()
{
    deque<string> str_deq;
    string strtemp;
    while(cin >> strtemp)
        str_deq.push_back(strtemp);
    for(auto it = str_deq.begin(); it != str_deq.end(); ++it)
        cout << *it <<  ;

    cout << 
 << "done!";

    return 0;
}

9.19、

值需要修改一下容器名和头文件

//p9_19.cpp
//p9_18.cpp
#include <iostream>
#include <list>
#include <string>

using namespace std;

int main()
{
    list<string> str_lis;
    string strtemp;
    while(cin >> strtemp)
        str_lis.push_back(strtemp);
    for(auto it = str_lis.begin(); it != str_lis.end(); ++it)
        cout << *it <<  ;

    cout << 
 << "done!";

    return 0;
}

9.20、

//p9_20.cpp
#include <iostream>
#include <deque>
#include <list>

using namespace std;

int main()
{
    list<int> lis{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    deque<int> even_deq;
    deque<int> odd_deq;

    for(auto it = lis.begin(); it != lis.end(); ++it)
    {
        if(*it%2 == 0)
            even_deq.push_back(*it);
        else
        {
            odd_deq.push_back(*it);
        }
    }
    
    cout << "even_deq : ";
    for (auto ix : even_deq)
        cout << ix <<  ;
    cout <<
 << "odd_deq : " ;
    for (auto ix : odd_deq)
        cout << ix <<  ;

    return 0;
}

 9.21、

在vector 和 list 容器中,insert 的操作是一样的效果

9.22、

插入操作会使迭代器,在每次可能的插入操作后,对要使用到的迭代器要进行更新

当插入操作使得容器重新分配内存后,所有的迭代器都会失效,所以在改变容器大小后,应当避免使用未更新的迭代器

源代码参考了https://blog.csdn.net/misayaaaaa/article/details/56831089

    vector<int>::iterator mid = iv.begin() + iv.size()/2;

    while(mid != iv.begin())
    {
        if(*mid == some_val)
            mid = iv.insert(mid, 2*some_val);
        else
        {
            --mid;
        }
        
    }

9.3.2 Accessing Elements

所有的顺序容器都有 front member

所有顺序容器除了forward_list 都有back member

end iterator 是最后一个元素的下一个位置的引用

在使用front back 或者解引用begin --end 要先检验容器是否为空

用at()member 可以确保下标索引不会超出范围

exercises section 9.3.2

9.23、

值全部相同为

9.24、

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> empty_vec;
    auto i1 = empty_vec.at(0);
    auto i2 = empty_vec.front();
    auto i3 = empty_vec.begin();



    return 0;
}

9.3.3 Erasing Elements

pop_front(not support vector string )  pop_back (not support forward_list)

除了删除 deque 的首尾元素,删除任何元素都会使容器的所有的迭代器、指针、引用失效

exercise section 9.3.3

9.25、

如果elem1 == elem2 调用直接结束不删除任何元素

如果elem2是尾后“元素”调用结束后返回尾后“元素”

9.26、

//p9_25.cpp
#include <iostream>
#include <list>
#include <vector>

using namespace std;

int main()
{
    int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
    vector<int> ivec;
    list<int> ilis;
    //int a = sizeof(ia);
    //cout << "a = " << a << endl;

    for (int ix = 0; ix < sizeof(ia)/sizeof(int); ++ix)
    {
        ivec.push_back(ia[ix]);
        ilis.push_back(ia[ix]);
    }

    cout << "befoer erase: " << endl;
    cout << "ivec : ";
    for (auto ix : ivec)
        cout << ix <<  ;
    cout << 
;
    cout << "ilis : ";
    for (auto ix : ilis)
        cout << ix <<  ;
    cout << 
;

    for (auto iter_ivec = ivec.begin(); iter_ivec != ivec.end();)
    {
        if (!(*iter_ivec % 2))
            iter_ivec = ivec.erase(iter_ivec);
        else
            ++iter_ivec;
    }
    for (auto iter_ilis = ilis.begin(); iter_ilis != ilis.end();)
    {
        if (*iter_ilis % 2)
            iter_ilis = ilis.erase(iter_ilis);
        else
            ++iter_ilis;
    }
    cout << "after erase: " << endl;
    cout << "ivec : ";
    for (auto ix : ivec)
        cout << ix <<  ;
    cout << 
;
    cout << "ilis : ";
    for (auto ix : ilis)
        cout << ix <<  ;
    cout << 
;

    return 0;
}

9.3.4 Specialized forward_list Operations

before_begin()  insert_after()  emplace_after()  erase_after()

exercise section 9.3.4

9.27、

//p9_27.cpp
#include <iostream>
#include <forward_list>

using namespace std;

int main()
{
    forward_list<int> i_flist{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    auto prev = i_flist.before_begin();
    auto curr = i_flist.begin();

    while(curr != i_flist.end())
    {  
        if(*curr%2)
            curr = i_flist.erase_after(prev);   //要更新curr
        else
        {
            prev = curr;
            ++curr;
        }
    }

    for(auto ix : i_flist)
        cout << ix <<  ;
    cout << 
;

    return 0;
}

9.28、

//p9_28.cpp
#include <iostream>
#include <string>
#include <forward_list>

using namespace std;

void add_after(forward_list<string> &str_flist, const string elem1, const string elem2)
{
    auto prev = str_flist.before_begin();
    auto curr = str_flist.begin();
    bool added = false;

    while (curr != str_flist.end())
    {
        if(*curr == elem1)
        {
            prev = curr;        //插入前prev要更新
            curr = str_flist.insert_after(prev,elem2);
            added = true;
        }
        else
        {
            prev = curr;
            ++curr;
        }  
    }
    if(!added)
        str_flist.insert_after(prev,elem2);

}

int main()
{
    forward_list<string>  str_flist{"good", "good", "every", "day"};
    string elem1("good");
    string elem2("study");

    add_after(str_flist, elem1, elem2);
    for(auto ix : str_flist)
        cout << ix <<  ;
    
    return 0;
}

9.3.5 Resizing a Container

resize(n)  resize(n,val);

exercises section 9.3.5

9.29、

vec.resize(100) 会在尾后增加75个值为默认值的元素

vec.resize(10)会从尾后开始删除90个元素

 

9.30、

1、单个参数比现有元素的个数小

2、元素具有默认值或默认构造函数

9.3.6 Container Operations May Invalidate Iterators

注意更新iterators,不要用变量存储end();

 

exercises section 9.3.6

9.31

对于 list 迭代器不支持进行+法运算 所以修改方式:用两个自增运算替代(或者advance(iter,2))

//只有vector 和 string 的迭代器支持算术运算

9.32

对形参的调用顺序不确定,作如下修改后在VS comunity 2019中编译通过运行;因为其插入操作实际插入的位置是在奇数的后面而不是前面,所以返回值也是后面的;

但是程序这样写可能在别的编译器中运行无法通过。参考https://blog.csdn.net/misayaaaaa/article/details/56834852 6楼的评论

    auto iter = vi.begin();
    while (iter != vi.end())
    {
        if (*iter % 2)
        {
            iter = vi.insert(iter, *iter++);
            iter += 1;
        }
        else
        {
            iter = vi.erase(iter);
        }

    }

 9.33、

begin在执行第一次操作之后就会失效

9.34、

在遇到第一个奇数的时候陷入死循环,不断的在其前面插入该元素的值;

 

9.4 How a vector Grows

向 vector 中添加元素时,如果遇到空间不足 vector 会重新分配内存,并将原来的全部元素移动到新的内存位置,并添加新的元素,释放原来的内存。

分配新内存的容量会大于所需的容量

capacity 返回必须重新分配内存前可以容纳的元素的个数

reserve 告诉vector 预先分配多少内存,只会在请求的空间大于目前的capacity时才会改变capacity ,

reserve 和 resize 都不会所小 vector 的保留空间

shrink_to_fit() 对 vector string deque 有用,只是请求,不保证执行后会返还内存

exercises section 9.4

9.35、

capacity 是vector 在必须重新分配内存时所能容纳的元素的数量

size 是 vector 中目前的元素的数量

9.36、

不会,因为当元素的数量(size)将要超过其容量(capacity)时就会重新分配内存

9.37、

list 并不需要连续的存储空间

array 大小是固定的,不用重新分配内存

9.38、

//p9_38.cpp -- explore how vectors grow
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int temp;
    vector<int> vec;
    cout << "size" << "    " << "capacity" << endl;
    cout << vec.size() <<  "    "  << vec.capacity() << endl;
    cin >> temp;
    vec.push_back(temp);
    cout << vec.size() <<  "    "  << vec.capacity() << endl;
    vector<int> vec2(vec.capacity(), 0);
    vec = vec2;
    cout << vec.size() <<  "    "  << vec.capacity() << endl;
    vec.push_back(temp);
    cout << vec.size() <<  "    "  << vec.capacity() << endl;

    return 0;
}

9.39、

vector<string> svec;        //创建一个空的vector<int>
svec.reserve(1024);         //告诉编译器预先分配1024个“空间”
string word;                    //创建一个string类型的变量
while(cin >> word)
    svec.push_back(word);//存入vector 中
svec.resize(svec.size() + svec.size() /2);    //调整容器的size在尾后增加原来size的1/2个为默认值的元素

9.40

256 : 1024

512 : 1024

1000:1500

1048:  1500

9.5 Additional string Operations 

exercises section 9.5.1

9.41

//p9_41.cpp -- initializes a string from a vector<char>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    char ch_temp;
    vector<char> chvec;
    while(cin >> ch_temp)
        chvec.push_back(ch_temp);
    string str(chvec.begin(), chvec.end());

    cout << str << endl;
    return 0;
}

 

9.42、

使用reserve 申请足够的内存

exercises section 9.5.2

9.43、

int change_to(string &s, string oldVal, string newVal)
{
    int count = 0;
    auto old_len = oldVal.size();
    auto new_len = newVal.size();

    for (string::iterator i = s.begin(); i != s.end();)
    {
        if (s.substr(i-s.begin(), old_len) == oldVal)
        {
            i = s.erase(i,i+old_len);    //擦除旧的元素要更新迭代器,返回的迭代器指向旧元素的后一个位置
            i = s.insert(i, newVal.begin(), newVal.end());//插入之后也要更新迭代器
            i += new_len;
            ++count;
        }
        else
        {
            ++i;
        }
        
    }

    return count;

}

9.44、

int change_to(string &s, string oldVal, string newVal)
{
    int count = 0;
    auto old_len = oldVal.size();
    auto new_len = newVal.size();

    for (int i = 0; i < s.size();)
    {
        if (s.substr(i, old_len) == oldVal)
        {
            s.replace(i, old_len, newVal);
            i += new_len;
            ++count;
        }
        else
        {
            ++i;
        }

    }

    return count;
}

9.45、

//p9.45.cpp -- 
#include <iostream>
#include <string>

using namespace std;

string func(const string name, const string prefix, const string suffix);

int main()
{
    string newstr;
    string name("Stanly");
    string prefix("Mr.");
    string suffix("Jr.");

    newstr = func(name, prefix, suffix);

    cout << newstr;

    return 0;
}

string func(const string name, string prefix, string suffix)
{
    string str(name);
    string sp(" ");
    prefix.append(sp);
    str.insert(str.begin(), prefix.begin(), prefix.end());
    str.append(sp);
    str.append(suffix);

    return str;
}

9.46、

string func(const string name, const string prefix, const string suffix)
{
    string str(name);
    str.insert(0,prefix);
    str.insert(str.size(), suffix);

    return str;
}

9.5.3 string Search Operations 

find()  rfind()  find_first_of()  find_last_of()  find_first_not_of()  find_last_not_of();

不要用 int 类型接受搜索操作的返回值

exercises section 9.5.3

9.47、

//p4_47.cpp
#include <iostream>
#include <string>

using namespace std;
void seperate(const string str);
void seperate2(const string str);

int main()
{
    string str("ab2c3d7R4E6");
    seperate(str);
    seperate2(str);

}
//find_first_of()
void seperate(const string str)
{
    string arph{"abcedfghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    string dig{"0123456789"};
    
    string::size_type pos = 0;
    cout << "alpha : ";
    while((pos = str.find_first_of(arph,pos)) != string::npos)
    {
        cout << str[pos] <<  ;
        ++pos;
    }
    cout << endl;
    pos = 0;
    cout << "numeric: ";
    while((pos = str.find_first_of(dig,pos)) != string::npos)
    {
        cout << str[pos] <<  ;
        ++pos;
    }
    cout << 
;
}
//find_first_not_of();
void seperate2(const string str)
{
    string arph{"abcedfghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    string dig{"0123456789"};
    
    string::size_type pos = 0;
    cout << "alpha : ";
    while((pos = str.find_first_not_of(dig,pos)) != string::npos)
    {
        cout << str[pos] <<  ;
        ++pos;
    }
    cout << endl;
    pos = 0;
    cout << "numeric: ";
    while((pos = str.find_first_not_of(arph,pos)) != string::npos)
    {
        cout << str[pos] <<  ;
        ++pos;
    }
    cout << 
;
        
}

 

9.48、

返回 string::size_type npos

9.49、

//p9_49.cpp
#include <iostream>
#include <string>
#include <fstream>

using namespace std;

bool no_ade_sdender(const string word);

int main(int argc, char * argv[])
{
    if (argc != 2)
    {
        cout << "usage : " << argv[0] << " filename" << endl;
        exit(EXIT_FAILURE);
    }
    string word;
    ifstream input(argv[1],ifstream::in);
    if(input)
    {
        string temp;
        while(input >> temp)
        {
            if(!no_ade_sdender(temp))
            {
                if(word.size() < temp.size())
                    word = temp;
            }
        }

    }
    cout << word ;
}

bool no_ade_sdender(const string word)
{
    bool flag = false;
    string ade_sdender("dfpg");

    if(word.find_first_of(ade_sdender) != string::npos)
        flag = true;
    
    return flag;
}

exercise section 9.5.5

9.50、

//p9_50.cpp
#include <iostream>
#include <vector>
#include <string>

using namespace std;

int total(const vector<string> str);//float

int main()
{
    vector<string> str;
    string temp;
    while(cin >> temp)
        str.push_back(temp);
    int sum = total(str);    //float
    cout << "sum = " << sum << endl;
}

int total(const vector<string> str)   //float 
{
    int count = 0;    //float count = 0;
    for(auto iter = str.begin(); iter != str.end(); ++iter)
    {
        count += stoi(*iter);    //count += stof(*iter)
    }

    return count;
}

9.51、

//p9_51.cpp
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class date{
    public:
        date(){}
        date(string str);
        unsigned get_day(){return day;}
        unsigned get_month(){return month;}
        unsigned get_year(){return year;}
    private:
        unsigned day = 0;
        unsigned month = 1;
        unsigned year = 1900;
};

date::date(string str)
{
    string dig("0123456789");

    const vector<string>  Mon_{"January", "February", "Marcy", "April", 
                                "May", "June", "July", "August", 
                                "September", "October", "November", "December",
                                "Jan","Feb","Mar","Apr", 
                                "May", "Jun", "Jul","Aug",
                                "Sep", "Oct","Nov","Dec" };

    /*const vector<string>  Mon_s{"Jan","Feb","Mar","Apr", "May", "Jun", "Jul",
         "Aug", "Sep", "Oct","Nov","Dec"};*/
    
    string::size_type flag_month  = str.find_first_of(dig);
    if(flag_month != 0)
    {
        string::size_type flag_days = str.find_first_not_of(dig, flag_month);
        string::size_type flag_years = str.find_first_of(dig,flag_days);
        unsigned temp_month = 0;
        string month_str = str.substr(0,flag_month-1);
        
        for (auto ix : Mon_)
        {
            
            if(month_str == ix)
            {
                 month = temp_month%12 + 1;
                 break;
            }
            ++temp_month;
            if(temp_month >=24)
            {
                cout <<"erro : no such month: " << month_str << endl;
                exit(EXIT_FAILURE); 
            }
        }
        day = stoi(str.substr(flag_month,flag_days - flag_month));
        year = stoi(str.substr(flag_years));
    }
    else
    {
        string::size_type flag_month_end = str.find_first_not_of(dig);
        string::size_type flag_day_begin = str.find_first_of(dig,flag_month_end);
        string::size_type flag_day_end = str.find_first_not_of(dig,flag_day_begin);
        string::size_type flag_year_begin = str.find_first_of(dig,flag_day_end);
        month = stoul(str.substr(flag_month,flag_month_end - flag_month));
        day = stoul(str.substr(flag_day_begin,flag_day_end - flag_day_begin));
        year = stoul(str.substr(flag_year_begin));
    }
}

int main()
{
    date date1("May 11,1997");
    date date2("November 12,1998");
    date date3("12/11/1999");

    cout << date1.get_month() <<  << date1.get_day() <<   << date1.get_year() << endl;
    cout << date2.get_month() <<  << date2.get_day() <<   << date2.get_year() << endl;
    cout << date3.get_month() <<  << date3.get_day() <<   << date3.get_year() << endl;

    return 0;
}

9.52、

适配器就相当于一个转接头,

题目的意思没搞懂

 

 

 

 

  

 

 

 

 

以上是关于第9章 顺序容器的主要内容,如果未能解决你的问题,请参考以下文章

C++Primer第5版读书笔记(第9章)

顺序容器C++

顺序容器C++

9-1-顺序查找-查找-第9章-《数据结构》课本源码-严蔚敏吴伟民版

第9章 音频和视频

第3章:布局与容器