您的位置:首页 > 编程语言 > C语言/C++

《C++primer(第五版)》学习之路-第九章:顺序容器

2015-09-23 22:37 721 查看
【 声明:版权所有,转载请标明出处,请勿用于商业用途。 联系信箱:libin493073668@sina.com】

9.1 顺序容器概述

1.顺序容器类型

vector 可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。

deque 双端队列。支持快速随机访问。在头尾位置插入/删除速度很快。

list 双向链表。只支持双向顺序访问。在list中任何位置进行插入/删除操作速度都很快。

forward_list 单向链表。只支持单向顺序访问。在链表任何位置进行插入/删除操作速度都很快。

array 固定大小数组。支持快速随机访问。不能添加或删除元素。

string 与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入/删除速度快。

2.以下是一些选择容器的基本原则

⑴.除非你有很好的理由选择其他容器,否则应使用vector

⑵.如果你的程序有很多小的元素,且额外开销很重要,则不要使用list或forward_list

⑶.如果程序要求随机访问元素,应使用vector或deque

⑷.如果程序需要在头尾位置插入或删除元素,应使用list或forward_list

⑸.如果程序需要在头尾位置插入或删除元素,但不会在中间位置进行插入或删除操作,则使用deque

⑹.如果程序只有在读取输入时才需要再容器中间位置插入元素,随后需要随机访问元素,则

--首先,确定是否真的需要再容器中间位置添加元素。当处理输入数据时,通常可以很容易地向vector追加数据,然后再调用标准库的sort函数来重排容器中的元素,从而避免在中间位置添加元素。

--如果必须在中间位置插入元素,考虑在输入阶段使用list,一旦输入完成,将list中的内容拷贝到一个vector中

9.2 容器库概览

1.容器操作

类型别名

iterator 此容器类型的迭代器类型

const_iterator 可以读取元素,但不能修改元素的迭代器类型

size_type 无符号整数类型,足够保存此种容器类型最大可能容器的大小

different_type 带符号整数类型,足够保存两个迭代器之间的距离

value_type 元素类型

reference 元素的左值类型;与value_type含义相同

const_reference 元素的const左值类型

构造函数

C c; 默认构造函数,构造空容器

C c1(c2); 构造c2的拷贝c1

C c(b,e); 构造c,将迭代器b和e指定范围内的元素拷贝到c(array不支持)

C c(a,b,c...); 列表初始化c

赋值与swap

c1 = c2 将c1中的元素替换为c2中元素

c1 = {a,b,c..} 将c1中的元素替换为列表中的元素

a.swap(b) 交换a和b的元素

swap(a,b) 与a.swap(b) 等价

大小

c.size() c中元素的数目

c.max_size() c可保存的的最大元素数目

c.empty() 若c中存储了元素,返回false,否则返回true

添加/删除元素(不适用于array)

注:在不同容器中,这些操作的接口都不同

c.insert(args) 将args中的元素拷贝进c

c.emplace(inits) 使用inits构造c中的一个元素

c.erase(args) 删除args指定的元素

c.clear() 删除c中的所有元素,返回void

关系运算符

==,!= 返回指向c的首元素和尾元素之后位置的迭代器

<,<=,>,>= 关系运算符(无序关联同期不支持)

获取迭代器

c.begin(),c.end() 返回指向c的首元素和尾元素之后位置的迭代器

c.cbegin(),c.cend() 返回const_iterator

反向容器的额外成员

reverse_iterator 按逆序寻址元素的迭代器

const_reverse_iterator 不能修改元素的逆序迭代器

c.rbegin(),c.rend() 返回指向c的尾元素和首元素之前位置的迭代器

c.crbegin(),c.crend() 返回const_reverse_iterator

2.容器定义和初始化

C c 默认构造函数。如果C是一个array,则c中元素按默认方式初始化,否则c为空

C c1(c2) c1初始化为c2的拷贝。c1和c2必须是相同类型。

C c1 = c2

C c{a,b,c...} c初始化为初始化列表中元素的拷贝。列表中元素的类型必须与C的元素类型相容。对于array

C c = {a,b,c..} 类型,雷彪中元素数目必须等于或少于array的大小,任何遗漏的元素都进行值初始化。

C c(b,e) c初始化为迭代器b和e指定范围中的元素的拷贝。范围中

C seq(n) seq包含n个元素,这些元素进行了值初始化;此构造函数是explicit的

C seq(n,t) seq包含n个初始化为值t的元素

3.容器赋值运算

c1 = c2 将c1中的元素替换为c2中元素的拷贝。c1和c2必须具有相同的类型

c = {a,b,c..} 将c1中元素替换为初始化列表中元素的拷贝

swap(c1,c2) 交换c1和c2中的元素。c1和c2必须具有相同的类型。swap通常比从c2向c1拷贝元素快得多

c1.swap(c2)

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

seq.assign(b,e) 将seq中的元素替换为迭代器b和e所表示的范围中的元素。迭代器b和e不能指向seq中的元素

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

seq.assign(n,t) 将seq中的元素替换为n个值为t的元素

9.3 顺序容器

1.向顺序容器添加元素的操作

这些操作会改变容器的大小,array不支持这些操作。

forward_list有自己转悠版本的insert和emplace;

forward_list不支持push_back和emplace_back。

vector和string不支持push_front和emplace_front。

c.push_back(t) 在c的尾部创建一个值为t或由args创建的元素,返回void

c.emplace_back(args)

c.push_front(t) 在c的头部创建一个值为t或由args创建的元素。返回void

c.emplace_front(args)

c.insert(p,t) 在迭代器p指向的元素之前创建一个值为t或由args创建的元素。返回指向新添加元素的迭

c.emplace(p,args) 代器。

c.insert(p,n,t) 在迭代器p指向的元素之前插入n个值为t的元素。返回指向新添加的第一个元素的迭代器;若n为0,则返回p

c.insert(p,b,e) 将迭代器b和e指定的范围内的元素插入迭代器p指向的元素之前。b和e不能指向c中的元素。返回指向新添加的第一个元素的迭代器;若范围为空,则返回p

c.insert(p,il) il是一个花括号包围的元素值列表。将这些给定值插入到迭代器p指向的元素之前。返回指向新添加的第一个元素的迭代器;若列表为空,则返回p

2.在顺序容器中访问元素的操作

at和下标操作只适用于string,vector,deque和array

back不适用于forward_list

c.back() 返回c中尾元素的引用。若c为空,函数行为未定义

c.front() 返回c中首元素的引用。若c为空,函数行为未定义

c
返回c中下标为n的元素的引用,n是一个无符号的整数。若n>=c.size(),则函数行为未定义。

c.at(n) 返回下标为n的元素的引用。如果下标越界,则抛出一out_of_range异常。

3.顺序容器的删除操作

这些操作会改变容器大小,所以不适用于array

forward_list有特殊版本的erase

forward_list不支持pop_back

vector和string不支持pop_front

c.pop_back() 删除c中尾元素。若c为空,则函数行为未定义。函数返回void

c.pop_front() 删除c中首元素。若c为空,则函数行为未定义。函数返回void

c.erase(p) 删除迭代器p所指定的元素,返回一个指向被删元素之后元素的迭代器,若p指向尾元素,则返回尾后(off_the_end)迭代器。若p是尾后迭代器,则函数行为未定义。

c.erase(b,e) 删除迭代器b和e所指定范围内的元素。返回一个指向最后一个被删元素之后元素的迭代器,若e本身就是尾后迭代器,则函数也返回尾后迭代器

c.clear() 删除c中所有元素。返回void

4.在forward_list中插入或删除元素的操作

lst.before_begin() 返回指向链表首元素之前不存在的元素的迭代器。此迭代器不能解引用。cbefore_begin()

lst.cbefore_begin() 返回一个const_iterator

lst.insert_after(p,t) 在迭代器p之后的位置插入元素,t是一个对象,n是数量,b和e是表示范围的

lst.insert_after(p,n,t) 一对迭代器(b和e不能指向lst内), il是一个花括号列表。返回一个指向最后一的

lst.insert_after(p,b,e) 个插入元素的迭代器。如果范围为空,则返回p。若p为尾后迭代器,则函数行为

lst.insert_after(p,il) 未定义

emplace_after(p,args) 使用args在p指定的位置之后创建一个元素。返回一个指向这个新元素的迭代器。若p为尾后迭代器,则函数行为未定义。

lst.earse_after(p) 删除p指向的位置之后的元素,或删除从b之后直到(但不包含)e之间的元素。返回一个

lst.earse_after(b,e) 指向被删元素之后元素的迭代器,若不存在这样的元素,则返回尾后迭代器。如果p指向lst的尾元素或者是一个尾后迭代器,则函数行为未定义。

5.顺序容器大小操作

resize不适用于array

c.resize(n) 调整c的大小为n个元素。若n<c.size(),则多出的元素被丢弃。若必须添加新元素,对新元素进行值初始化

c.resize(n,t) 调整c的大小为n个元素。任何新添加的元素都初始化为值t。

6.

向容器添加元素之后:

⑴.如果容器是vector或string,且存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效。如果存储空间未被重新分配,指向插入位置之前的元素的迭代器、指针和引用仍有效,但指向插入位置之后元素的迭代器、指针和引用将会失效。

⑵.对于deque,插入到除首尾位置之外的任何位置都会导致迭代器、指针和引用失效。如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效。

⑶.对于list和forward_list,指向容器的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍然有效。

当我们删除一个元素后:

⑴.对于list和forward_list,指向容器其他位置的迭代器(包括尾后迭代器和首前迭代器)、指针和引用仍然有效。

⑵.对于deque,如果在首尾之外的任何位置删除元素,那么指向被删除元素之外其他元素的迭代器、引用或指针也会失效。如果是删除deque的尾元素,则尾后迭代器也会失效,但其他迭代器、引用和指针不受影响;如果是删除首元素,这些也不会受影响。

⑶.对于vector和string,指向被删元素之前元素的迭代器、引用和指针仍然有效。

注:当我们删除元素时,尾后迭代器总是会失效。

9.4 vector对象是如何增长的

1.容器大小管理操作

shrink_to_fit只使用于vector、string和deque

capacity和reserve只适用于vector和string

c.shrink_to_fit() 请将capacity()减少为与size()相同大小

c.capacity() 不重新分配内存空间的话,c可以保存多少元素

c.reserve(n) 分配至少能容纳n个元素的内存空间

2.当添加的数超出了vector原本分配的最大容量,vector的实现采用的策略是在每次需要分配新内存空间时将当前容量翻倍。

9.5 额外的string操作

1.构造string的其他方法

string s(cp,n) s是cp指向的数组中前n个字符的拷贝。此数组至少应该包含n个字符。

string s(s2,pos2) s是string s2从下标pos2开始的字符的拷贝。若pos2>s2.size(),构造函数的行为未定义

string s(s2,pos2,len2) s是string s2从下标pos2开始len2个字符的拷贝。若pos2>s2.size(),构造函数的行为未定义。不管len2的值是多少,构造函数至多拷贝s2.size()-pos2个字符。

2.子字符串操作

s.substr(pos,n) 返回一个string,包含s中从pos开始的n个字符的拷贝。pos的默认值为0。n的默认值为s.size()-pos,即拷贝从pos开始的所有字符。

3.修改string的操作

s.insert(pos,args) 在pos之前插入args指定的字符。pos可以是一个下标或一个迭代器。接受下标的版本返回一个指向s的引用;接受迭代器的版本返回指向第一个插入字符的迭代器。

s.earse(pos,len) 删除从位置pos开始的len个字符。如果len被省略,则删除从pos开始直至s末尾的所有字符。返回一个指向s的引用。

s.assign(args) 将s中的字符替换为args指定的字符。返回一个指向s的引用

s.append(args) 将args追加到s。返回一个指向s的引用

s.replace(range,args) 删除s中范围range内的字符,替换为args指定的字符。range或者是一个下标和一个长度,或者是一对指向s的迭代器。返回一个指向s的引用

4.

string类提供了6个不同的搜索函数,每个函数都有4个重载版本。

每个搜索操作都会返回一个string::size_type值,表示匹配发生位置的下标。

如果搜索失败,则返回一个名为string::npos的static成员。

标准库将npos定义成一个const string::size_type类型,并初始化为-1。

string搜索函数返回string::size_type值,该类型时一个unsigned类型,因此我们应该尽量不要使用带符号类型来保存这些返回值

5.

string搜索操作

s.find(args) 查找s中args第一次出现的位置

s.rfind(args) 查找s中args最后一次出现的位置

s.find_first_of(args) 在s中查找args中任何一个字符第一次出现的位置

s.find_last_of(args) 在s中查找args中任何一个字符最后第一次出现的位置

s.find_first_not_of(args) 在s中查找第一个不在args中的字符

s.find_last_not_of(args)
在s中查找最后一个不在args中的字符

6.

字符串比较函数

s.compare(args)

args形式

s2 比较s和s2

pos1,n1,s2 将s中从pos1开始的n1个字符与s2比较

pos1,n1,s2,pos2,n2 将s中从pos1开始的n1个字符与s2中从pos2开始的n2个字符进行比较

cp 比较s与cp指向的以空字符结尾的字符数组

pos1,n1,cp 将s中从pos1开始的n1个字符与cp指向的以空字符结尾的字符数组进行比较

pos1,n1,cp,n2 将s中从pos1开始的n1个字符与cp指向的地址开始的n2个字符进行比较

7.

string和数值之间的转换

string参数中第一个非空白符必须是符号(+或-)或数字。它可以以0x或0X开头来表示十六进制数。对那些将字符串转换为浮点值的函数,string参数也可以以小数点开头,并可有包含e或E来表示指数部分。对于那些将字符串转换为整型值的函数,根据基数不同,string参数可以包含字母字符,对应大于数字9的数

如果string不能转换为一个数值,这些函数抛出一个invalid_argument异常。如果转换得到的数值无法用任何类型表示,则抛出一个out_of_range异常

to_string(val) 一组重载函数,返回数值val的string表示。val可以是任何算术类型。对每个浮点类型和int或更大的整型,都有相应版本的to_string。与往常一样,小整型会被提升。

stoi(s,p,b) 返回s的起始子串(表示整数内容)的数值,返回值类型分别是int,long,unsigned long,long long,

stol(s,p,b) unsigned long long。b表示转换所用的基数,默认值是10。p是size_t指针,用来保存s中第一个

stoul(s,p,b) 非数值字符下标,p默认为0,即函数不保存下标。

stoll(s,p,b)

stoull(s,p,b)

stof(s,p) 返回s的起始子串(表示浮点数内容)的数值,返回值类型分别是float,double或long
double。参数

stod(s,p)
p的作用于整数转换函数中一样

stold(s,p)

9.6 容器适配器

1.

所有容器适配器都支持的操作和类型

size_type 一种类型,足以保存当前类型的最大对象的大小

value_type 元素类型

container_type 实现适配器的底层容器类型

A a; 创建一个名为a的空适配器

A a(c); 创建一个名为a的适配器,带有容器c的一个拷贝

关系运算符 每个适配器都支持所有关系运算符:==,!=,<,<=,>,>=,这些运算符返回底层容器的比较结果

a.empty() 若a包含任何元素,返回false,否则返回true

a.size() 返回a中元素数目

swap(a,b) 交换a和b的内容,a和b必须有相同类型,包括底层容器类型也必须相同

a.swap(b)

2.

栈的其他操作

s.pop() 删除栈顶元素,但不返回该元素值

s.push(item) 创建一个新元素压入栈顶,该元素通过拷贝或移动item而来,或者由args构造

s.emplace(args)

s.top() 返回栈顶元素,但不将元素弹出栈

3.

queue和priority_queue的其他操作

q.pop() 返回queue的首元素或priority_queue的最高优先级元素,但不删除此元素

q.front() 返回首元素,但不删除此元素

q.back() 返回尾元素,但不删除此元素,只适用于queue

q.top() 返回优先级最高的元素,但不删除此元素,只适用于priority_queue

q.push(item) 在queue末尾或priority_queue中器当的位置创建一个元素,其值为item,或者有args构造

q.emplace(args)

PS:部分练习答案

练习9.2

std::list<std::deque<int>> ldi;


练习9.4

bool find(vector<int>::itreator beg,vector<int>::iterator end,int value)
{
	for(auto iter = beg; iter!=end; ++iter)
		if(*iter==value)
			return true;
	return false;
}


练习9.5

vector<int>::itreator find(vector<int>::itreator beg,vector<int>::iterator end,int value)
{
	for(auto iter = beg; iter!=end; ++iter)
		if(*iter==value)
			return iter;
	return end;
}


练习9.13

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

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

int main()
{
	list<int> ilst(5, 4);
	vector<int> ivc(5, 5);

	vector<double> dvc(ilst.begin(), ilst.end());
	for (auto i : ilst) cout << i;
	cout << endl;
	for (auto t : dvc) cout << t;
	cout << endl;

	vector<double> dvc2(ivc.begin(), ivc.end());
	for (auto i : ivc) cout << i;
	cout << endl;
	for (auto t : dvc2) cout << t;

	return 0;
}


练习9.14

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

int main()
{
	std::list<const char*> l{"one","two","three"};
	std::vector<std::string> v;
	v.assign(l.cbegin(),l.cend());
	
	for(const auto& ch: v)
	std::cout << ch << std::endl;
	return 0;
}


练习9.15

#include <iostream>
#include <vector>

int main()
{
	std::vector<int> vec1 {1, 2, 3, 4, 5};
	std::vector<int> vec2 {1, 2, 3, 4, 5};
	std::vector<int> vec3 {1, 2, 3, 4};

	std::cout << std::boolalpha << (vec1 == vec2) << std::endl;
	std::cout << std::boolalpha << (vec1 == vec3) << std::endl;

	return 0;
}


练习9.16

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

int main()
{
	std::list<int> list {1, 2, 3, 4, 5};
	std::vector<int> vec1 {1, 2, 3, 4, 5};
	std::vector<int> vec2 {1, 2, 3, 4};

	std::cout << std::boolalpha
	          << (std::vector<int>(list.begin(), list.end()) == vec1)
	          << std::endl;
	std::cout << std::boolalpha
	          << (std::vector<int>(list.begin(), list.end()) == vec2)
	          << std::endl;
}


练习9.18

#include <iostream>
#include <string>
#include <deque>

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

int main()
{
	deque<string> input;
	for (string str; cin >> str; input.push_back(str));

	for (auto iter = input.cbegin(); iter != input.cend(); ++iter)
		cout << *iter << endl;

	return 0;
}


练习9.19

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

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

int main()
{
    list<string> input;
    for (string str; cin >> str; input.push_back(str));
    
    for (auto iter = input.cbegin(); iter != input.cend(); ++iter)
        cout << *iter << endl;

    return 0;
}


练习9.20

#include <iostream>
#include <deque>
#include <list>
using std::deque;
using std::list;
using std::cout;
using std::cin;
using std::endl;

int main()
{
	list<int> l {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	deque<int> odd, even;
	for (auto i : l)
		(i & 0x1 ? odd : even).push_back(i);

	for (auto i : odd) cout << i << " ";
	cout << endl;
	for (auto i : even) cout << i << " ";
	cout << endl;

	return 0;
}


练习9.22

这是一个死循环,iter永远不会等于mid

#include <iostream>
#include <vector>
using std::vector;

void insertDoubleValue(vector<int>& iv, int some_val)
{
    auto cursor = iv.size() / 2;
    auto iter = iv.begin(), mid = iv.begin() + cursor;
    while (iter != mid) {
        if (*iter == some_val) {
            iter = iv.insert(iter, 2 * some_val);
            ++iter;
            ++cursor;
            mid = iv.begin() + cursor;
        }
        ++iter;
    }
}

void print(const vector<int>& iv)
{
    for (auto i : iv) std::cout << i << " ";
    std::cout << std::endl;
}

int main()
{
    vector<int> iv = {1, 1, 1, 1, 1, 7, 1, 9};
    insertDoubleValue(iv, 1);
    print(iv);
}


练习9.24

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v;
    std::cout << v.at(0); 
    std::cout << v[0]; 
    std::cout << v.front(); 
    std::cout << *v.begin();
    return 0;
}


练习9.25

如果elem1与elem2相等或者都为尾后迭代器,什么都不发生

如果elem2是尾后迭代器,那么会删除elem1到end()区间内的元素

练习9.26

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

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

int main()
{
    int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};

    vector<int> vec(ia, end(ia));
    list<int> lst(vec.begin(), vec.end());

    for (auto it = lst.begin(); it != lst.end();)
        if (*it & 0x1)
            it = lst.erase(it);
        else
            ++it;

    for (auto it = vec.begin(); it != vec.end();)
        if (!(*it & 0x1))
            it = vec.erase(it);
        else
            ++it;

    cout << "list : ";
    for (auto i : lst) cout << i << " ";
    cout << "\nvector : ";
    for (auto i : vec) cout << i << " ";
    cout << std::endl;

    return 0;
}


练习9.27

#include <iostream>
#include <forward_list>

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

int main()
{
	forward_list<int> flst = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
	for (auto prev = flst.before_begin(), curr = flst.begin(); curr != flst.end();)
		if (*curr & 0x1)
			curr = flst.erase_after(prev);
		else
			prev = curr++;

	for (auto i : flst)
		cout << i << " ";
	cout << endl;
}


练习9.28

void find_and_insert(forward_list<string> &list, string const& to_find, string const& to_add)
{
    auto prev = list.before_begin();
    for (auto curr = list.begin(); curr != list.end(); prev = curr++)
    {
        if (*curr == to_find)
        {
            list.insert_after(curr, to_add);
            return;
        }
    }
    list.insert_after(prev, to_add);
}


练习9.29

vec.resize(100); 增加75个元素在vec后面

vec.resize(10);删除后面90个元素

练习9.31

list版

#include <iostream>
#include <list>

using std::list;
using std::cout;
using std::endl;
using std::advance;

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

	for (auto i : vi) cout << i << " ";

	return 0;
}


forward_list版

#include <iostream>
#include <forward_list>

using std::forward_list;
using std::cout;
using std::endl;
using std::advance;

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

	for (auto i : vi) cout << i << " ";

	return 0;
}


练习9.35

size是容器类已有元素的数量

capacity是容器在不增加分配容量的情况下能分配的最大容量

练习9.37

因为list在内存中的存储方式不是连续的

array的存储大小是固定的

练习9.38

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

int main()
{
	std::vector<std::string> v;
	std::string word;

	while (std::cin >> word)
	{
		v.push_back(word);
		std::cout << "size = " << v.capacity() << "\n";
	}

	return 0;
}


练习9.41

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

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

int main()
{
	vector<char> vec {'p', 'e', 'z', 'y'};
	string str(vec.begin(), vec.end());

	cout << str << endl;

	return 0;
}


练习9.43

#include <string>
using std::string;

#include <iostream>

void Replace(string& s, const string& oldVal, const string& newVal)
{
	for (auto beg = s.begin(); beg != s.end(); ++beg)
	{
		if (*beg != oldVal.front()) continue;
		if (std::distance(beg, s.end()) < std::distance(oldVal.begin(), oldVal.end()))
			break;
		if (string {beg, beg + oldVal.size()} == oldVal)
		{
			auto pos = std::distance(s.begin(), beg);
			s.erase(beg, beg + oldVal.size());
			s.insert(beg, newVal.cbegin(), newVal.cend());
			beg = std::next(s.begin(), pos + newVal.size() - 1);
		}
	}
}

int main()
{
	string str {"To drive straight thru is a foolish, tho courageous act."};
	Replace(str, "thru", "through");
	Replace(str, "tho", "though");
	std::cout << str << std::endl;
	return 0;
}


练习9.44

#include <string>
using std::string;

#include <iostream>

void Replace(string& s, const string& oldVal, const string& newVal)
{
	for (auto beg = s.begin(); beg != s.end(); ++beg)
	{
		if (*beg != oldVal.front()) continue;
		if (std::distance(beg, s.end()) < std::distance(oldVal.begin(), oldVal.end()))
			break;
		if (string {beg, beg + oldVal.size()} == oldVal)
		{
			auto pos = std::distance(s.begin(), beg);
			s.erase(beg, beg + oldVal.size());
			s.insert(beg, newVal.cbegin(), newVal.cend());
			beg = std::next(s.begin(), pos + newVal.size() - 1);
		}
	}
}

int main()
{
	string str {"To drive straight thru is a foolish, tho courageous act."};
	Replace(str, "thru", "through");
	Replace(str, "tho", "though");
	std::cout << str << std::endl;
	return 0;
}


练习9.45

#include <iostream>
#include <string>

inline std::string pre_suffix(const std::string& name, const std::string& pre,const std::string& su)
{
	auto ret = name;
	ret.insert(ret.begin(), pre.begin(), pre.end());
	ret.append(su);

	return ret;
}
int main()
{
	std::string name("alan");
	std::cout << pre_suffix(name, "Mr.", ",Jr.") << std::endl;

	return 0;
}


练习9.46

#include <iostream>
#include <string>

std::string pre_suffix(const std::string& name, const std::string& pre,const std::string& su)
{
	std::string ret(name);
	ret.insert(0, pre);
	ret.insert(ret.size(), su);

	return ret;
}

int main()
{
	std::string name("alan");
	std::cout << pre_suffix(name, "Mr.", ",Jr.");

	return 0;
}


练习9.47

find_first_of

#include <string>
#include <iostream>

using std::string;
using std::cout;
using std::endl;

int main()
{
	string numbers {"123456789"};
	string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
	string str {"ab2c3d7R4E6"};

	cout << "numeric characters: ";
	for (string::size_type pos = 0; (pos = str.find_first_of(numbers, pos)) != string::npos; ++pos)
		cout << str[pos] << " ";
	cout << "\nalphabetic characters: ";
	for (string::size_type pos = 0; (pos = str.find_first_of(alphabet, pos)) != string::npos; ++pos)
		cout << str[pos] << " ";
	cout << endl;

	return 0;
}
find_first_not_of

#include <string>
#include <iostream>

using std::string;
using std::cout;
using std::endl;

int main()
{
	string numbers {"123456789"};
	string alphabet {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"};
	string str {"ab2c3d7R4E6"};

	cout << "numeric characters: ";
	for (string::size_type pos = 0; (pos = str.find_first_not_of(alphabet, pos)) != string::npos; ++pos)
		cout << str[pos] << " ";
	cout << "\nalphabetic characters: ";
	for (string::size_type pos = 0; (pos = str.find_first_not_of(numbers, pos)) != string::npos; ++pos)
		cout << str[pos] << " ";
	cout << endl;

	return 0;
}


练习9.49

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

using std::string;
using std::ifstream;
using std::cout;
using std::endl;

int main()
{
	ifstream ifs("data.txt");
	if (!ifs) return -1;
	string longest_word;
	for (string word; ifs >> word;)
		if (word.find_first_not_of("aceimnorsuvwxz") == string::npos && word.size() > longest_word.size())
			longest_word = word;

	cout << longest_word << endl;
}


练习9.50

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

int sum_for_int(const std::vector<std::string> &v)
{
	int sum = 0;
	for (auto const& s : v) sum += std::stoi(s);
	return sum;
}

float sum_for_float(const std::vector<std::string> &v)
{
	float sum = 0.0;
	for (auto const& s : v) sum += std::stof(s);
	return sum;
}

int main()
{
	std::vector<std::string> v = {"1", "2", "3", "4.5"};
	std::cout << sum_for_int(v) << std::endl;
	std::cout << sum_for_float(v) << std::endl;

	return 0;
}


练习9.51

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

class wy_Date
{
	public:
		wy_Date(const std::string& s);
		unsigned year;
		unsigned month;
		unsigned day;
};

int main()
{
	wy_Date d("99/21/3871");

	std::cout << d.day << " " << d.month << " " << d.year << " ";

	return 0;
}

wy_Date::wy_Date(const std::string& s)
{
	unsigned format = 0;

	//! 1/1/1900
	if (s.find_first_of("/") != std::string::npos) format = 0x10;

	//! Jan 1, 1900
	if (s.find_first_of(",") >= 4 && s.find_first_of(",") != std::string::npos)
		format = 0x01;

	switch (format)
	{

			//! format = 1/1/1900
		case 0x10:
			day = std::stoi(s.substr(0, s.find_first_of("/")));
			month = std::stoi(s.substr(s.find_first_of("/") + 1,
			                           s.find_first_of("/") - s.find_last_of("/")));
			year = std::stoi(s.substr(s.find_last_of("/") + 1, 4));
			break;

			//! format = January 1, 1900  or Jan 1, 1900
		case 0x01:
			day = std::stoi(
			          s.substr(s.find_first_of("1234567890"),
			                   s.find_first_of(",") - s.find_first_of("1234567890")));

			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 = std::stoi(s.substr(s.find_last_of(" ") + 1, 4));
			break;
	}
}


练习9.52

#include <stack>
using std::stack;

#include <string>
using std::string;

#include <iostream>
using std::cout;
using std::endl;

int main()
{
	auto& expr = "This is (Mooophy(awesome)((((wooooooooo))))) and (ocxs) over";
	auto repl = '#';
	auto seen = 0;

	stack<char> stk;

	for (auto c : expr)
	{
		stk.push(c);
		if (c == '(') ++seen;
		if (seen && c == ')')
		{
			while (stk.top() != '(') stk.pop();
			stk.pop();
			stk.push(repl);
			--seen;
		}
	}

	string output;
	for (; !stk.empty(); stk.pop()) output.insert(output.begin(), stk.top());
	cout << output << endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: