当前位置:   article > 正文

C++Primer 第九章 顺序容器

C++Primer 第九章 顺序容器

9.1 顺序容器概述

9.1 对于下面的程序任务,vector、deque和list哪种容器最为适合?解释你的选择的理由。如果没有哪一种容器优于其他容器,也请解释理由。

(a) 读取固定数量的单词,将它们按字典序插入到容器中。我们将在下一章中看到,关联容器更适合这个问题。
(b) 读取未知数量的单词,总是将单词插入到末尾。删除操作在头部进行。
(c) 从一个文件读取未知数量的整数。将这些数排序,然后将它们打印到标准输出。
  • 1
  • 2
  • 3

(a)list,需要在中间插入数据,list最好;
(b)deque,需要在头部和尾部插入或删除元素,选deque;
(c)vector,没有特别的需求选vector。

9.2 标准库概述

9.2 定义一个list对象,其元素类型是int的deque。

list<deque<int>> ld;
  • 1

9.3 构成迭代器范围的迭代器有何限制?

两个迭代器begin和end满足如下条件:
它们指向同一个容器中的元素,或者是容器中的最后一个元素之后的位置,且我们可以通过反复递增begin来到达end。换句话说,end不在begin之前。

9.4 编写函数,接受一对指向vector的迭代器和一个int值。在两个迭代器指定的范围中查找给定的值,返回一个布尔值来指出是否找到。

#include <iostream>
#include<vector>

using std::cin;
using std::cout;
using std::endl;
using std::vector;

bool find_i(vector<int>::iterator beg, vector<int>::iterator end, int i)
{
    for(beg; beg != end; ++beg)
        if(*beg == i)
            return true;
    return false;
}

int main()
{
   vector<int> vec{1, 2, 3, 4, 5};
   cout << find_i(vec.begin(), vec.end(), 3) << endl;

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

9.5 重写上一题的函数,返回一个迭代器指向找到的元素。注意,程序必须处理未找到给定值的情况。

#include <iostream>
#include <vector>

using std::cin;
using std::cout;
using std::endl;
using std::vector;

vector<int>::iterator find_i(vector<int>::iterator beg, vector<int>::iterator end, int i)
{
    for (beg; beg != end; ++beg)
        if (*beg == i)
            return beg;
    return beg;
}

int main()
{
    vector<int> vec{1, 2, 3, 4, 5};
    vector<int>::iterator it = find_i(vec.begin(), vec.end(), -1);
    if (it == vec.end())
        cout << "未找到给定值" << endl;
    else
        cout << *it << endl;
 
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

9.6 下面的程序有何错误?你应该如何修改它?

list<int> lst1;
list<int>::iterator iter1 = lst1.begin(),
					iter2 = lst1.end();
while (iter1 < iter2) /* ... */
//while(iter1 != iter2)
  • 1
  • 2
  • 3
  • 4
  • 5

9.2.2 容器类型成员

9.7 为了索引 int 的 vector 中的元素,应该使用什么类型?

vector<int>::size_type
  • 1

9.8 为了读取string 的list 中的元素,应该使用什么类型?如果写入list,又应该使用什么类型?

list<string>::const_iterator		//read
list<string>::iterator				//write
  • 1
  • 2

9.2.3容器类型成员

9.9 begin 和 cbegin 两个函数有什么不同?

begin返回容器的iterator类型,当我们需要写访问时使用;
cbegin返回容器的const_iterator类型,当我们不需要写访问时使用。

9.10 下面4个对象分别是什么类型?

vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin(), it2 = v2.begin();
auto it3 = v1.cbegin(), it4 = v2.cbegin();
it1:vector<int>::iterator,it2:vector<int>::const_iterator;
it3:vector<int>::const_iterator,it4:vector<int>::const_iterator。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

9.2.4 容器定义和初始化

9.11 对6种创建和初始化 vector 对象的方法,每一种都给出一个实例。解释每个vector包含什么值。

    vector<int> vec; // 默认初始化,没有元素

    vector<int> vec1(vec);
    vector<int> vec2 = vec; // 对vec的拷贝,没有元素

    vector<int> vec3{0,1,2,3,4,5,6,7,8,9};
    vector<int> vec4 = {0,1,2,3,4,5,6,7,8,9};//列表初始化,vec4中的元素就是列表中的元素,int类型

    vector<int> vec5(vec3.begin(), vec3.end());//迭代器范围内的元素拷贝

    vector<int> vec6(10);//10个0
    
    vector<int> vec6(10, -1);//10个-1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

9.12 对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同。

两个容器的类型及其元素必须匹配;
传递迭代器参数来拷贝一个范围时,就不要求容器类型相同了,只要能将要拷贝的元素转换。

9.13 如何从一个list初始化一个vector?从一个vector又该如何创建?编写代码验证你的答案。

#include <iostream>
#include <vector>
#include <list>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;

int main()
{
    list<int> li{0, 1, 2, 3, 4, 5, 6};
    vector<double> vec(li.begin(), li.end());
    for (auto d : vec)
        cout << d << " ";
    cout << endl;

    vector<int> vec1{1, 2, 3, 4};
    vector<double> vec2(vec1.begin(), vec1.end());
    for (auto d : vec2)
        cout << d << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

9.2.5赋值和swap

9.14 编写程序,将一个list中的char * 指针元素赋值给一个vector中的string。

#include <iostream>
#include <vector>
#include <list>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;

int main()
{
    list<const char *> lc = {"a", "an", "czy"};
    vector<string> vs;
    vs.assign(lc.cbegin(), lc.cend());
    for(const auto s : vs)
        cout << s << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

9.15 编写程序,判定两个vector是否相等。
9.16 重写上一题的程序,比较一个list中的元素和一个vector中的元素。

#include <iostream>
#include <vector>
#include <list>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;

int main()
{
    vector<int> v1{0,1,2,3};
    vector<int> v2{0,1,2,3,4};
    cout << (v1 == v2) << endl;

    list<int> li{0,1,2,3};
    cout << (v1 == (vector<int> {li.begin(), li.end()})) << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

9.17 假定c1 和 c2 是两个容器,下面的比较操作有何限制?
if (c1 < c2)

c1和c2不能是无序容器,且容器类型要相同,最后,元素类型要支持运算符。

9.3 顺序容器操作

9.3.1 向顺序容器中添加元素

9.18 编写程序,从标准输入读取string序列,存入一个deque中。编写一个循环,用迭代器打印deque中的元素。

#include <iostream>
#include <vector>
#include <list>
#include<string>
#include<deque>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;
using std::deque;

int main()
{
    deque<string> ds;
    string word;
    while (cin >> word)
        ds.push_back(word);
    
    for(auto iter = ds.begin(); iter != ds.end(); ++iter)
        cout << *iter << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

9.19 重写上一题的程序,用list替代deque。列出程序要做出哪些改变。

只需要将list换成deque即可。

9.20 编写程序,从一个list拷贝元素到两个deque中。值为偶数的所有元素都拷贝到一个deque中,而奇数值元素都拷贝到另一个deque中。

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <deque>

using std::cin;
using std::cout;
using std::deque;
using std::endl;
using std::list;
using std::string;
using std::vector;

int main()
{
    list<int> li{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    deque<int> di1, di2;
    for (const auto i : li)
        (i % 2 == 0) ? di1.push_back(i) : di2.push_back(i);

    cout << "di1 = ";
    for (const auto i : di1)
        cout << i << " ";
    cout << endl;

    cout << "di2 = ";
    for (const auto i : di2)
        cout << i << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

9.21 如果我们将第308页中使用 insert 返回值将元素添加到list中的循环程序改写为将元素插入到vector中,分析循环将如何工作。

还是一样的操作,实现的是在vector的一个特定位置反复插入元素。

9.22 假定iv是一个int的vector,下面的程序存在什么错误?你将如何修改?

    while (iter != mid)
    {
        cout << &iv[0] << " " << &iv[5] << endl;
        if (*iter == some_val)
            iv.insert(iter, 2 * some_val);
        iter++;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

9.3.2 访问元素

9.23 在本节第一个程序中,若 c.size() 为1,则val、val2、val3和val4的值会是什么?

同一个元素的拷贝。

9.24 编写程序,分别使用 at、下标运算符、front 和 begin 提取一个vector中的第一个元素。在一个空vector上测试你的程序。

#include <iostream>
#include <vector>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;
using std::vector;

int main()
{
    vector<int> vi;
    cout << *vi.begin() << endl;//段错误 (核心已转储)
    cout << vi.front() << endl;//段错误 (核心已转储)
    cout << vi.at(0) << endl;//terminate called after throwing an instance of 'std::out_of_range'
    cout << vi[0] << endl;//段错误 (核心已转储)

    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

9.3.3 删除元素

9.25 对于第312页中删除一个范围内的元素的程序,如果 elem1 与 elem2 相等会发生什么?如果 elem2 是尾后迭代器,或者 elem1 和 elem2 皆为尾后迭代器,又会发生什么?

如果elem1与elem2相等,则一个元素都不会删除;
如果elem2是尾后迭代器,则会从elem1元素删除到最后一个元素;
如果elem1与elem2都是尾后迭代器,则一个元素都不会删除。

9.26 使用下面代码定义的ia,将ia 拷贝到一个vector和一个list中。是用单迭代器版本的erase从list中删除奇数元素,从vector中删除偶数元素。

int ia[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89 };
  • 1
#include <iostream>
#include <vector>
#include <list>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;

int main()
{
   int ia[] = {0,1,1,2,3,5,8,13,21,55,89};
   vector<int> vec;
   list<int> list;
   for(auto i : ia)
   {
        vec.push_back(i);
        list.push_back(i);
   }

   for(auto iter = vec.begin(); iter != vec.end(); ++iter)
        if(*iter % 2)
            iter = vec.erase(iter);
    for(auto i : vec)
        cout << i << " ";
    cout << endl;

   for(auto iter = list.begin(); iter != list.end(); ++iter)
        if(*iter % 2 == 0)
            iter = list.erase(iter);
    for(auto i : list)
        cout << i << " ";
    cout << endl;

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

9.3.4 特殊的forward-list操作

9.27 编写程序,查找并删除forward_list中的奇数元素。

#include <iostream>
#include <forward_list>

using std::cin;
using std::cout;
using std::endl;
using std::forward_list;

int main()
{
   forward_list<int> flst = {0,1,2,3,4,5,6,7,8,9};
   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 i : flst)
        cout << i << " ";
    cout << endl;

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

9.28 编写函数,接受一个forward_list和两个string共三个参数。函数应在链表中查找第一个string,并将第二个string插入到紧接着第一个string之后的位置。若第一个string未在链表中,则将第二个string插入到链表末尾。

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <forward_list>

using std::cin;
using std::cout;
using std::endl;
using std::forward_list;
using std::list;
using std::string;
using std::vector;

void find_s(forward_list<string> &flst, const string s1, const string s2)
{
    auto prev = flst.before_begin();
    auto iter = flst.begin();
    while (iter != flst.end())
        if(*iter == s1)
            break;
        else
        {
            prev = iter++;
        }
    iter == flst.end() ? flst.insert_after(prev, s2) : flst.insert_after(iter, s2);
}

int main()
{
    forward_list<string> flst{"chen", "zi", "yun"};
    find_s(flst, "chen", "wang");

    for(auto s : flst)
        cout << s << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

9.3.5 改变容器大小

9.29 假定vec包含25个元素,那么vec.resize(100)会做什么?如果接下来调用vec.resize(10)会做什么?

会添加75个新元素,并对新元素进行初始化;
后面90个元素会被丢弃。

9.30 接受单个参数的resize版本对元素类型有什么限制(如果有的话)?

如果元素类型的类类型,则元素类型必须提供一个默认构造函数。

9.3.6 容器操作可能使迭代器失效

9.31 第316页中删除偶数值元素并复制奇数值元素的程序不能用于list或forward_list。为什么?修改程序,使之也能用于这些类型。

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <forward_list>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;
using std::vector;
using std::forward_list;

int main()
{
    list<int> li = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter = li.begin();
    while (iter != li.end())
    {
        if (*iter % 2)
        {
            iter = li.insert(iter, *iter);
            ++iter;
            ++iter;
        }
        else
            iter = li.erase(iter);
    }

    forward_list<int> vi = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    auto iter1 = vi.begin();
    auto pre = vi.before_begin();
    while (iter1 != vi.end())
    {
        if (*iter % 2)
        {
            iter1 = vi.insert_after(iter1, *iter);
            pre = iter1;
            ++iter1;
        }
        else
            iter1 = vi.erase_after(pre);
    }

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

9.32 在第316页的程序中,向下面语句这样调用insert是否合法?如果不合法,为什么?

iter = vi.insert(iter, *iter++);
//不合法,insert中的参数运行顺序是未定义的,我们不知道iter运行的是iter+1的状态还是未+1的状态。
  • 1
  • 2

9.33 在本节最后一个例子中,如果不将insert的结果赋予begin,将会发生什么?编写程序,去掉此赋值语句,验证你的答案。

插入操作:如果存储空间被重新分配,则迭代器全部失效;如果没有重新分配,插入位置之后的迭代器全部失效。

9.34 假定vi是一个保存int的容器,其中有偶数值也有奇数值,分析下面循环的行为,然后编写程序验证你的分析是否正确。

iter = vi.begin();
while (iter != vi.end())
	if (*iter % 2)
		iter = vi.insert(iter, *iter);
	++iter;
  • 1
  • 2
  • 3
  • 4
  • 5

会无限循环,当碰到第一个奇数时,iter从inert()中得到插入元素的迭代器,++iter后,迭代器指向的还是之前碰到的那个奇数,下次循环中还是检查这个奇数,程序陷入无限循环。

9.4 vector对象是如何增长的

9.35 解释一个vector的capacity和size有何区别。

容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下最多可以保存多少元素。

9.36 一个容器的capacity可能小于它的size吗?

不可能

9.37 为什么list或array没有capacity成员函数?

list所占的空间不是连续的;array是固定size的。

9.38 编写程序,探究在你的标准实现中,vector是如何增长的。

#include <iostream>
#include <vector>
#include <list>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;

int main()
{
   vector<int> vec;
   
   cout << "vec: size: " << vec.size() << " capacity: " << vec.capacity() << endl;
   vec.push_back(2);
   vec.push_back(2);
   vec.push_back(2);
   vec.push_back(2);
   vec.push_back(2);
   cout << "vec: size: " << vec.size() << " capacity: " << vec.capacity() << endl;

   while (vec.size() != vec.capacity())
   {
        vec.push_back(1);
        cout << "vec: size: " << vec.size() << " capacity: " << vec.capacity() << endl;
   }
   

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

9.39 解释下面程序片段做了什么:

vector<string> svec;
svec.reserve(1024);
string word;
while (cin >> word)
	svec.push_back(word);
svec.resize(svec.size() + svec.size() / 2);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

9.40 如果上一题的程序读入了256个词,在resize之后容器的capacity可能是多少?如果读入了512个、1000个、或1048个呢?

读入了256词、512词时,size增加到384、768,capacity不变;
读入1000词或1048词后,size增加到1500、1572,capacity至少增大到可以容纳当前size。

9.5 额外的string操作

9.41 编写程序,从一个vector初始化一个string。
9.42 假定你希望每次读取一个字符存入一个string中,而且知道最少需要读取100个字符,应该如何提高程序的性能?

#include <iostream>
#include <vector>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;
using std::vector;

int main()
{
    vector<char> vc{'c', 'h', 'e', 'n'};
    string s(vc.begin(), vc.end());

    vc.reserve(100);

    for (auto c : s)
        cout << c << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

9.5.2 改变string的其他方法

9.43 编写一个函数,接受三个string参数是s、oldVal 和newVal。使用迭代器及insert和erase函数将s中所有oldVal替换为newVal。测试你的程序,用它替换通用的简写形式,如,将"tho"替换为"though",将"thru"替换为"through"。

#include <iostream>
#include <vector>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;
using std::vector;

void rep_s(string &s, const string &oldVal, const string &newVal)
{
    // 1 查找oldVal
    //  auto pos = s.find(oldVal);
    for (auto iter = s.begin(); iter != s.end(); ++iter)
    {
        if (s.size() < oldVal.size())
            return;
        if (oldVal == string(iter, iter + oldVal.size()))
        {
            // 2 删除oldVal
            iter = s.erase(iter, iter + oldVal.size());
            // 3 替换
            iter = s.insert(iter, newVal.begin(), newVal.end());
        }
    }

    // 2 删除oldVal
    //  s.erase(pos, oldVal.size());
    // 3 替换
    //  s.insert(pos, newVal);
}

int main()
{
    string s = "tho thru";

    rep_s(s, "tho", "though");
    cout << s << endl;

    rep_s(s, "thru", "through");
    cout << s << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

9.44 重写上一题的函数,这次使用一个下标和replace。

#include <iostream>
#include <vector>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;
using std::vector;

void rep_s(string &s, const string &oldVal, const string &newVal)
{
    // 1 查找oldVal
    for (decltype(s.size()) i = 0; i != s.size(); ++i)
    {
        if (s.size() < oldVal.size())
            return;
        if (oldVal == string(s, i, oldVal.size()))
        {
            // 2 删除oldVal
            // 3 替换
            s.replace(i, i + oldVal.size(), newVal);        
        }
    }
}

int main()
{
    string s = "tho thru";

    rep_s(s, "tho", "though");
    cout << s << endl;

    rep_s(s, "thru", "through");
    cout << s << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

9.45 编写一个函数,接受一个表示名字的string参数和两个分别表示前缀(如"Mr.“或"Mrs.”)和后缀(如"Jr.“或"III”)的字符串。使用迭代器及insert和append函数将前缀和后缀添加到给定的名字中,将生成的新string返回。

#include <iostream>
#include <vector>
#include <list>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;

string add_s(const string &name, const string &pre, const string &rear)
{
    string s = name;
    s.insert(s.begin(), pre.begin(), pre.end());
    s.append(rear);
    return s;
}

int main()
{
   string name = "wang";
   cout << add_s(name, "Mr.", "Jr.") << endl;

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

9.46 重写上一题的函数,这次使用位置和长度来管理string,并只使用insert。

#include <iostream>
#include <vector>
#include <list>
#include<string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::vector;
using std::string;

string add_s(const string &name, const string &pre, const string &rear)
{
    string s = name;
    s.insert(0, pre);
    s.insert(s.size(), rear);
    return s;
}

int main()
{
   string name = "wang";
   cout << add_s(name, "Mr.", "Jr.") << endl;

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

9.5.3 string搜索操作

9.47 编写程序,首先查找string"ab2c3d7R4E6"中每个数字字符,然后查找其中每个字母字符。编写两个版本的程序,第一个要使用find_first_of,第二个要使用find_first_not_of。

#include <iostream>
#include <vector>
#include <list>
#include <string>

using std::cin;
using std::cout;
using std::endl;
using std::list;
using std::string;
using std::vector;

int main()
{
    string s("ab2c3d7R4E5");
    string numbers("0123456789");
    for (string::size_type pos = 0; (pos = s.find_first_of(numbers, pos)) != string::npos; ++pos)
        cout << s[pos] << " ";
    cout << endl;

    for (string::size_type pos = 0; (pos = s.find_first_not_of(numbers, pos)) != string::npos; ++pos)
        cout << s[pos] << " ";
    cout << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

9.48 假定name和numbers的定义如325页所示,numbers.find(name)返回什么?

string::npos

9.49 如果一个字母延伸到中线之上,如d 或 f,则称其有上出头部分(ascender)。如果一个字母延伸到中线之下,如p或g,则称其有下出头部分(descender)。编写程序,读入一个单词文件,输出最长的既不包含上出头部分,也不包含下出头部分的单词

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

int main()
{
    ifstream ifs("file1"); // 1、读入一个单词文件
    if (!ifs)
        return -1;

    // 2、不包含上出头部分和下出头部分
    string curr_word, long_word;
    while (ifs >> curr_word)
        // 3、找出最长的那个单词
        if (string::size_type pos = curr_word.find_first_not_of("abceimnorsuvwxz") == string::npos)
            long_word = (long_word.size() < curr_word.size() ? curr_word : long_word);
    cout << long_word << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

9.5.4 compare函数

9.5.5 数值转换

9.50 编写程序处理一个vector,其元素都表示整型值。计算vector中所有元素之和。修改程序,使之计算表示浮点值的string之和。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

int main()
{
    vector<string> vec{"+123", "22", "63"};
    int sum = 0;
    for(auto iter = vec.begin(); iter != vec.end(); ++iter)
        sum += stoi(*iter);
    cout << sum << endl;

    vector<string> vec1{"+12.3", "2.2", "6.3"};
    float sum1 = 0.0;
    for(auto iter = vec1.begin(); iter != vec1.end(); ++iter)
        sum1 += stof(*iter);
    cout << sum1 << endl;
   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

9.51 设计一个类,它有三个unsigned成员,分别表示年、月和日。为其编写构造函数,接受一个表示日期的string参数。你的构造函数应该能处理不同的数据格式,如January 1,1900、1/1/1990、Jan 1 1900 等。

#include <iostream>
#include <string>

using namespace std;

class date
{
private:
    unsigned int year;
    unsigned int month;
    unsigned int day;

public:
    date(const string &s);
};

date::date(const string &s)
{
    // Junuary 1,1900
    string::size_type index1, index2;
    if (s.find(",") != string::npos)
    {
        index1 = s.find(" ");
        index2 = s.find(",", index1 + 1);
        cout << "year = " << s.substr(index2 + 1) << ", month = " << s.substr(0, index1)
             << ", day = " << s.substr(index1 + 1, index2 - index1) << endl;

        if (s.find("Jan") < s.size()) month = 1;
        if (s.find("Feb") < s.size()) month = 2;
        if (s.find("Mar") < s.size()) month = 3;
        if (s.find("Apr") < s.size()) month = 4;
        if (s.find("May") < s.size()) month = 5;
        if (s.find("Jun") < s.size()) month = 6;
        if (s.find("Jul") < s.size()) month = 7;
        if (s.find("Aug") < s.size()) month = 8;
        if (s.find("Sep") < s.size()) month = 9;
        if (s.find("Oct") < s.size()) month = 10;
        if (s.find("Nov") < s.size()) month = 11;
        if (s.find("Dec") < s.size()) month = 12;

        year = stoi(s.substr(index2 + 1));
        day = stoi(s.substr(index1 + 1, index2 - index1));

        cout << year << month << day << endl;
    }
    // Jan 1 1900
    else if ((index1 = s.find(" ")) != string::npos)
    {
        index2 = s.find(" ", index1 + 1);

        if (s.find("Jan") < s.size()) month = 1;
        if (s.find("Feb") < s.size()) month = 2;
        if (s.find("Mar") < s.size()) month = 3;
        if (s.find("Apr") < s.size()) month = 4;
        if (s.find("May") < s.size()) month = 5;
        if (s.find("Jun") < s.size()) month = 6;
        if (s.find("Jul") < s.size()) month = 7;
        if (s.find("Aug") < s.size()) month = 8;
        if (s.find("Sep") < s.size()) month = 9;
        if (s.find("Oct") < s.size()) month = 10;
        if (s.find("Nov") < s.size()) month = 11;
        if (s.find("Dec") < s.size()) month = 12;

        year = stoi(s.substr(index2+1));
        day = stoi(s.substr(index1+1, index2-index1-1));

        cout << year << month << day << endl;
    }

    // 1/1/1900
    if ((index1 = s.find("/")) != string::npos)
    {
        index2 = s.find("/", index1 + 1);
        day = stoi(s.substr(0, index1));
        month = stoi(s.substr(index1 + 1, index2 - index1 - 1));
        year = stoi(s.substr(index2 + 1));

        cout << year << month << day << endl;
    }
}

int main()
{
    // date d("January 11,1900");
    // date d("1/1/1900");
    date d("Jan 1 1900");

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

9.6 容器适配器

9.52 使用stack处理括号化的表达式。当你看到一个左括号,将其记录下来。当你在一个左括号之后看到一个右括号,从stack中pop对象,直至遇到左括号,将左括号也一起弹出栈。然后将一个值(括号内的运算结果)push到栈中,表示一个括号化的(子)表达式已经处理完毕,被其运算结果所替代。

#include <iostream>
#include <string>
#include <stack>

using namespace std;

int main()
{
   string expression("This is (stk)");
   stack<char> stk;
   bool bSeen = false;
   for (auto c : expression)
   {
      if (c == '(')
      {
         bSeen = true;
         continue;
      }
      else if (c == ')')
         bSeen = false;

      if (bSeen)
         stk.push(c);
   }

   string repstr;
   while (!stk.empty())
   {
      repstr += stk.top();
      stk.pop();
   }

   expression.replace(expression.find("(") + 1, repstr.size(), repstr);

   cout << expression << endl;

   return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/178218
推荐阅读
相关标签
  

闽ICP备14008679号