cppPrimer学习-9th
Posted zongzi10010
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cppPrimer学习-9th相关的知识,希望对你有一定的参考价值。
目录
title: cppPrimer学习9th
date: 2020/1/3 10:37:05
toc: true
---
cppPrimer学习9th
源代码
知识点
我的小模版
#include <forward_list>
#include <iostream>
#include <list>
#include <vector>
using namespace std;
template <typename T>
void print(T src)
{
for (auto ch : src)
cout << ch <<",";
cout<<endl;
}
int main(int argc, const char** argv)
{
while(1);
}
resize改变的是size,reserve表示的是容量的预分配
在string转数字的时候,使用
if(ch.find_first_of("0123456789")!=string::npos)
后再来处理数字避免异常等,可以看练习题9.50.转换数字的字符串第一个字符要是合法的+-.0123456789
string用char来构造,string(1,ch)
练习题
9.1
9.1 对于下面的程序任务,vector, deque和list哪种容器最为合适?解释你选择的理由。如果没有哪一种容器优于其它容器,也请解释理由。
读取固定数量的单词,将它们按字典序插入到容器中。我们将在下一章看到,关联容器更适合这个问题。
读取未知数量的单词,总是将新单词插入到末尾。删除操作在头部进行。
从一个文件中读取未知数量的整数。将这些整数排序,然后打印到标准输出。
别人的答案使用
list
,因为涉及到中间插入,但是按照书本的解释,我觉得可以先使用vector
存放,再使用sort
排序,这里作者有写固定数量- 使用
deque
因为整数是小容量大小的数据元素,这里使用
vector
,再使用sort
9.2
定义一个list对象,其元素类型是int的deque。
list< deque<int> >
9.3
构成迭代器范围的迭代器有何限制
[begin,end)
begin++ 能够到达end
9.4
/**
* 编写一个函数,接受一对指向vector的迭代器和一个int值。在两个迭代器指定的范围中查找给定的值,返回一个布尔值来指出是否找到
*/
#include <iostream>
#include <vector>
using namespace std;
bool findInt(vector<int>::iterator src_begin, vector<int>::iterator src_end, int num)
{
for (vector<int>::iterator i = src_begin; i != src_end; i++) {
if (*i == num) return true;
}
return false;
}
int main(int argc, const char** argv)
{
vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
for (auto ch : a) {
cout << ch << ",";
}
cout << endl;
bool find = findInt(a.begin(), a.end(), 155);
cout << "find 155 is " << boolalpha << find << endl;
find = findInt(a.begin(), a.end(), 1);
cout << "find 1 is " << boolalpha << find << endl;
while (1) {
;
}
return 0;
}
9.5
/**
*重写上一题的函数,返回一个迭代器指向找到的元素。注意,程序必须处理未找到给定值的情况
*/
#include <iostream>
#include <vector>
using namespace std;
vector<int>::iterator findInt(vector<int>::iterator src_begin, vector<int>::iterator src_end, int num)
{
for (vector<int>::iterator i = src_begin; i != src_end; i++) {
if (*i == num) return i;
}
return src_end;
}
int main(int argc, const char** argv)
{
vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
for (auto ch : a) {
cout << ch << ",";
}
cout << endl;
auto find = findInt(a.begin(), a.end(), 155);
if (find == a.end()) {
cout << "no number find" << endl;
}
find = findInt(a.begin(), a.end(), 1);
if (find != a.end()) {
cout << "find 1 is " << *find << endl;
}
while (1) {
;
}
return 0;
}
9.6
下面程序有何错误?你应该如何修改?
list<int> lstl;
list<int>::iterator iter1 = lstl.begin(),
iter2 = lstl.end();
while (iter1 < iter2) /* ... */
迭代器是指针,对于指针比较大小没有什么意义,如果是 vector 或者 array 或者 deque 的话内存连续可以用作遍历
但是list 的地址不是连续的
9.7
为了索引int的vector中的元素,应该使用什么类型?
vector<int> sizetype 索引也就是下标
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
vector<int> a = {1, 2, 3, 4, 5, 6, 7, 8};
cout << a.size() << endl; // 8
while (1)
;
return 0;
}
9.8
为了读取string的list的元素,应该使用什么类型?如果写入list,又该使用什么类型
写: list<string>::iterator
读: list<string>::const_iterator
9.9
begin和cbegin两个函数有什么不同
iterator 和 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
9.11
/*
对6种创建和初始化vector对象的方法,每一种都给出一个实例。解释每个vector包含什么值
*/
#include <iostream>
#include <vector>
using namespace std;
void printVecInfo(const vector<int> src)
{
cout << "size=" << src.size() << " : ";
for (auto ch : src) cout << ch << ",";
cout << endl;
}
int main(int argc, const char** argv)
{
using C = vector<int>;
C a1;
C a2{1, 2, 3, 4, 5, 6, 7, 8, 9};
C a3 = a2;
C a4(a2.begin(), a2.begin() + 2);
C a5(5);
C a6(6, 1);
printVecInfo(a1); // size=0 :
printVecInfo(a2); // size=9 : 1,2,3,4,5,6,7,8,9,
printVecInfo(a3); // size=9 : 1,2,3,4,5,6,7,8,9,
printVecInfo(a4); // size=2 : 1,2,
printVecInfo(a5); // size=5 : 0,0,0,0,0,
printVecInfo(a6); // size=6 : 1,1,1,1,1,1,
while (1) {
;
}
return 0;
}
9.12
对于接受一个容器创建其拷贝的构造函数,和接受两个迭代器创建拷贝的构造函数,解释它们的不同
答案在p300顶部
接受一个容器创建其拷贝的构造函数,要求两个容器类型及元素类型必须匹配。
接受两个迭代器创建拷贝的构造函数,不要求容器类型匹配,而且元素类型也可以不同,只要拷贝的元素能转换就可以
list<int> numbers = {1, 2, 3, 4, 5};
list<int> numbers2(numbers); // ok, numbers2 has the same elements as numbers
vector<int> numbers3(numbers); // error: no matching function for call...
list<double> numbers4(numbers); // error: no matching function for call...
list<int> numbers = {1, 2, 3, 4, 5};
list<int> numbers2(numbers.begin(), numbers.end); // ok, numbers2 has the same elements as numbers
vector<int> numbers3(numbers.begin(), --numbers.end()); // ok, numbers3 is {1, 2, 3, 4}
list<double> numbers4(++numbers.beg(), --numbers.end()); // ok, numbers4 is {2, 3, 4}
forward_list<float> numbers5(numbers.begin(), numbers.end()); // ok, number5 is {1, 2, 3, 4, 5}
9.13
/*如何用一个list<int>初始化一个vector<double>, 从一个vector<int>又该如何创建*/
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
list<int> a = {1, 2, 3, 4, 5, 6, 7};
vector<double> b(a.begin(), a.end());
vector<int> c = {1, 2, 3, 4, 5, 6, 7};
vector<double> d(c.begin(), c.end());
return 0;
}
9.14
/*
编写程序,将一个list中的char*指针(指向C风格字符串)元素赋值给一个vector中的string
*/
#include <iostream>
#include <list>
#include <string>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
list<const char*> a(10, "hello");
vector<string> b;
b.assign(a.begin(), a.end());
for (auto ch : b) cout << ch << endl;
while (1)
;
}
9.15
// 编写程序,判定两个vector是否相等。
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
vector<int> a = {1, 2, 3, 4, 5, 6};
vector<int> b = {2, 2, 3, 4, 5, 6};
cout << boolalpha << (a == b) << endl;
while (1)
;
}
9.16
/*重写上一题的程序,比较一个list中的一个元素和一个vector中的元素。
先转换list到vector 再比较
*/
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
list<int> a(5, 1);
vector<int> b(6, 1);
cout << boolalpha << (vector<int>(a.begin(), a.end()) == b) << endl;
while (1)
;
return 0;
}
9.17
假定c1和c2是两个容器,下面的比较操作有何限制
容器类型相同
容器元素类型相同
容器的元素支持比较运算 包括=,<
9.18
/*
编写程序,从标准输入读取string序列,存入一个deque中。编写一个循环,用迭代器打印deque中的元素
备注: 这里需要使用ctrl+z
*/
#include <deque>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
int main(int argc, const char** argv)
{
string tmp;
deque<string> put;
while (cin >> tmp) {
put.push_back(tmp);
}
cout << "you input :
";
for (auto ch = put.begin(); ch != put.end(); ch++) {
cout << *ch << endl;
}
while (1) {
/* code */
}
return 0;
}
9.19
重写上题程序,用list代替deque。列出程序要做出哪些改变。
将deque改为list类型 iterator的类型也改为list即可。
9.20
/*
从一个list拷贝元素到两个deque中。值为偶数的所有元素都拷贝到一个deque中,而奇数值元素都拷贝到另一个deque中
*/
#include <deque>
#include <iostream>
#include <list>
#include <string>
#include <vector>
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> 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;
// }
int main()
{
list<int> src;
deque<int> dst1;
deque<int> dst2;
int num;
while (cin >> num) src.push_back(num);
for (int num : src) {
if (num & 0x01)
dst1.push_back(num);
else
dst2.push_back(num);
}
cout << "one" << endl;
for (int num : dst1) {
cout << num << " ";
}
cout << endl;
cout << "two" << endl;
for (int num : dst2) cout << num << " ";
cout << endl;
while (1)
;
return 0;
}
9.21
/* 如果我们将308页中使用insert返回值将元素添加到list中的循环程序改写为将元素插入到vector中,分析循环将如何工作
list<string> lst;
auto iter =lst.begin();
while(cin>>word)
iter=lst.insert(iter,word)
*/
一直往头部插入,vector 会执行拷贝移动
9.22
/*
假定iv是一个int的vector,下面的程序存在什么错误?你将如何修改?
vector<int>::iterator iter = iv.begin(), mid = iv.begin() + iv.size()/2;
while(iter != mid) {
if (*iter == some_val) {
iv.insert(iter, 2 * some_val);
}
}
1. iter 是iv 的迭代器,插入后长度变了,mid也就失效了 同时当vector扩大时,地址全部失效了
2. 死循环,iter没有++
insertDoubleValue2 是我写的,,这里取巧了,因为end是一直变的,我们根据end-cursor就好了
*/
#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 insertDoubleValue2(vector<int>& iv, int some_val)
{
auto cursor = iv.size() / 2;
auto iter = iv.begin();
while (iter != iv.end() - cursor) {
if (*iter == some_val) {
iter = iv.insert(iter, 2 * some_val);
++iter;
}
++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, 8};
insertDoubleValue(iv, 1);
print(iv);
iv = {1, 1, 1, 1, 1, 7, 1, 9, 8};
insertDoubleValue2(iv, 1);
print(iv);
while (1)
;
}
9.23
在本节第一个程序(309页)中,若c.size()为1, 则val, val2, val3和val4的值会是什么
第一个元素
9.24
编写程序,分别使用at、下标运算符、front和begin提取一个vector中的第一个元素。
在一个空vector上测试你的程序
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
std::vector<int> v;
std::cout << v.at(0); // terminating with uncaught exception of type std::out_of_range
std::cout << v[0]; // Segmentation fault: 11
std::cout << v.front(); // Segmentation fault: 11
std::cout << *v.begin(); // Segmentation fault: 11
while (1) return 0;
}
9.25
对于312页中删除一个范围内的元素的程序,如果elem1与elem2相等会发生什么?
如果elem2是尾后迭代器,或者elem1和elem2皆为尾后迭代器,又会发生什么
elem1=slist.erase(elements,elem2)
1. 不删除元素,不发生改变
2. 清空元素
3. 不删元素,不发生改变
9.26
/*
使用下面代码定义的ia,将ia拷贝到一个从vector和一个list中。
使用单迭代器版本的erase从list中删除奇数元素,从vector中删除偶数元素。
*/
#include <iostream>
#include <list>
#include <vector>
using namespace std;
int main(int argc, const char** argv)
{
int ia[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 55, 89};
// 这么做也可以,说明迭代器是+1的计算方式
// vector<int> va(ia, ia + sizeof(ia) / sizeof(int));
vector<int> va(begin(ia), end(ia));
list<int> lb(va.begin(), va.end());
for (auto it = va.begin(); it != va.end();) {
if ((*it) % 2)
it = va.erase(it);
else
it++;
}
for (auto it = lb.begin(); it != lb.end();) {
if ((*it) % 2)
it++;
else
it = lb.erase(it);
}
for (auto ch : va) cout << ch << ",";
cout << endl;
for (auto ch : lb) cout << ch << ",";
cout << endl;
while (1)
;
return 0;
}
9.27
/*
编写程序,查找并删除forward_list中的奇数元素。
*/
#include <forward_list>
#include <iostream>
using namespace std;
int main(int argc, const char** argv)
{
forward_list<int> flst = {2, 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 ch : flst) cout << ch << ",";
while (1)
;
return 0;
}
9.28
/*
编写函数,接受一个forward_list和两个string共三个参数。
函数应在链表中查找第一个string,并将第二个string插入到紧接着第一个string之后的位置。
若第一个string未在链表中,则将第二个string插入到链表末尾。
*/
#include <forward_list>
#include <iostream>
#include <string>
using namespace std;
void insert_lst(forward_list<string>& src, string after, string what)
{
if (src.empty()) {
return;
}
auto prev = src.before_begin();
auto curr = src.begin();
while (curr != src.end()) {
if (*curr == after) {
src.insert_after(curr, what);
return;
}
else {
curr++;
prev++;
}
}
src.insert_after(prev, what);
}
int main(int argc, const char** argv)
{
forward_list<string> lst = {"www", ".baidu", ".com"};
insert_lst(lst, ".baidu", ".hello");
for (auto ch : lst) cout << ch << endl;
insert_lst(lst, "xxx", ".hello");
for (auto ch : lst) cout << ch << endl;
while (1)
;
return 0;
}
9.29
假定vec包含25个元素,那么vec.resize(100)会做什么?如果接下来调用vec.resize(10)会做什么
1. 尾部添加75个0,同时可能因为移动拷贝,迭代器失效
2. 丢弃尾巴的90个元素
9.30
接受单个参数的resize版本对元素类型有什么限制
如果是类的话,需要有默认构造函数,或者初始值
9.31
// 大佬使用了 advance(prv, 2) 来操作迭代器
/*第316页中删除偶数值元素并复制奇数值元素的程序不能用于list或forward_list。
修改程序,使之也能用于这些类型
*/
#include <forward_list>
#include <iostream>
#include <list>
#include <vector>
using namespace std;
template <typename T>
void print(T src)
{
for (auto ch : src)
cout << ch <<",";
cout<<endl;
}
int main(int argc, const char** argv)
{
vector<int> v1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
list<int> l1(v1.begin(),v1.end());
forward_list<int> l2(v1.begin(),v1.end());
// 删除偶数元素,复制每个奇数元素
auto it1 = v1.begin();
while (it1 != v1.end()) {
if (*it1 % 2) {
it1 = v1.insert(it1, *it1);
it1+=2;
}
else {
it1=v1.erase(it1);
}
}
print(v1);
{ // list 使用两个++
// 删除偶数元素,复制每个奇数元素
auto it1 = l1.begin();
while (it1 != l1.end()) {
if (*it1 % 2) {
it1 = l1.insert(it1, *it1);
it1++;
it1++;
}
else {
it1=l1.erase(it1);
}
}
print(l1);
}
{ // forward_list 只有insert_after
// 删除偶数元素,复制每个奇数元素
auto curr = l2.begin();
auto prev=l2.before_begin();
while (curr != l2.end()) {
if (*curr % 2) {
prev = l2.insert_after(prev,*curr);
prev++; // 指向了原来的curr
//curr=prev; // 可以注释掉,这里不会发生迭代器失效
curr++;
}
else {
curr=l2.erase_after(prev);
}
}
print(l2);
}
while (1);
return 0;
}
9.32
316页的程序中,向下面语句这样调用insert是否合法?如果不合法,为什么?
iter = vi.insert(iter, *iter++);
*从右到左
iter++ 从左到右.++ 操作的是iter
*iter++ 根据优先级 *iter 然后iter++
https://stackoverflow.com/questions/2934904/order-of-evaluation-in-c-function-parameters
无法确认是先执行 *iter++ 还是先 insert
或者返回后 先赋值给iter 还是先iter++,再返回给iter
9.33
在本节最后一个例子中,如果不将insert的结果赋予begin,将会发生什么?
编写程序,去掉此赋值语句,验证你的答案。
#include "include.h"
int main(int argc, const char** argv) {
vector<int> ivec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto iter = ivec.begin();
while (iter != ivec.end()) {
++ iter;
/* iter = */ivec.insert(iter, 42);
// 调试可以发现 刚开始 iter=2
// 执行玩insert后=0 失效了
++ iter;
}
print(ivec);
while(1);
return 0;
9.34
死循环
/*假定vi是一个保存int的容器,其中有偶数值也要奇数值,分析下面循环的行为,然后编写程序验证你的分析是否正确。*/
#include "include.h"
int main(int argc, const char** argv) {
vector<int> v1={1,2,3,4,5,6,7,8,9};
auto iter=v1.begin();
while(iter!=v1.end())
{
if(*iter%2)
{
iter=v1.insert(iter,*iter);
// ++iter; ///-----if里面也需要++一次
}
++iter;
}
print(v1);
while(1);
return 0;
}
9.35
解释一个vector的capacity和size有何区别
capacity 表示不用重新分配内存时占用的内存大小
size 表示已经存储的元素的大小
9.36
一个容器的capacity可能小于它的size吗
不会
capacity >= size
9.37
为什么list或array没有capacity成员函数?
list 是链表,插入的时候分配内存
array 是固定大小的
9.38
/**
编写程序,探究在你的标准库实现中,vector是如何增长的
*/
#include "include.h"
void printInfo(vector<int> &v)
{
cout <<"size="<<v.size()<<endl;
cout <<"capacity="<<v.capacity()<<endl;
}
int main(int argc, const char** argv) {
vector<int> v1;
printInfo(v1); //size=0,capacity=0
v1.push_back(1); //size=1,capacity=1
printInfo(v1);
v1.push_back(1); //size=2,capacity=2
printInfo(v1);
v1.push_back(1); //size=3,capacity=4
printInfo(v1);
while(1);
return 0;
}
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. 分配容量为1024的容器,如果超了的话再分配
2. 填充后1/4 为空串 最后使用resize只能改变vector的size,不能改变其capacity
9.40
如果上一题的程序读入了256个词,在resize之后容器的capacity可能是多少?
如果读入了512个、1000个或1048个词呢?
256---256+256/2=384-------1024
512---512+512/2=768-------1024
1000--1000+1000/2=1500----这个可能是2048,但实际是//size=1500 capacity=2000
1048--1024*2=1536---------2048吧
// 可以看出来 直接 resize 出来的 capacity= resize*2-----这里可能编译器做法不一样的
// 直接push一个个的是+1
#include "include.h"
template<typename T>
void printInfo(const T& v)
{
cout <<"size="<<v.size()<<endl;
cout <<"capacity="<<v.capacity()<<endl;
}
int main(int argc, const char** argv) {
vector<string> svec;
svec.reserve(1024);
string word;
for(int i=0;i<1000;i++){
svec.push_back("123");
}
svec.resize(svec.size() + svec.size()/2);
printInfo(svec);//size=1500 capacity=2000----------------------------
vector<string> svec2;
svec2.reserve(1024);
for(int i=0;i<1500;i++){
svec2.push_back("123");
}
printInfo(svec2);//size=1500 capacity=2048--------------------------
while(1);
return 0;
}
9.41
/*
从vector<char> 创建 string
*/
#include "include.h"
int main(int argc, char const *argv[])
{
vector<char> vstr={'1','2','3','