实验1
任务一
- 源代码
// 现代C++标准库、算法库体验
// 本例用到以下内容:
// 1. 字符串string, 动态数组容器类vector、迭代器
// 2. 算法库:反转元素次序、旋转元素
// 3. 函数模板、const引用作为形参
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
// 模板函数声明
template<typename T>
void output(const T &c);
void test1();
void test2();
void test3();
int main() {
std::cout << "测试1: \n";
test1();
std::cout << "\n测试2: \n";
test2();
std::cout << "\n测试3: \n";
test3();
}
// 输出容器对象c中的元素
template <typename T>
void output(const T &c) {
for(auto &i : c)
std::cout << i << ' ';
std::cout << '\n';
}
// 测试1:组合使用算法库、迭代器、string反转字符串
void test1() {
using namespace std;
string s0{"0123456789"};
cout << "s0 = " << s0 << endl;
string s1(s0);
// 反转s1自身
reverse(s1.begin(), s1.end());
cout << "s1 = " << s1 << endl;
string s2(s0.size(), ' ');
// 将s0反转后结果拷贝到s2, s0自身不变
reverse_copy(s0.begin(), s0.end(), s2.begin());
cout << "s2 = " << s2 << endl;
}
// 测试2:组合使用算法库、迭代器、vector反转动态数组对象vector内数据
void test2() {
using namespace std;
vector<int> v0{2, 0, 4, 9};
cout << "v0: "; output(v0);
vector<int> v1{v0};
reverse(v1.begin(), v1.end());
cout << "v1: "; output(v1);
vector<int> v2{v0};
reverse_copy(v0.begin(), v0.end(), v2.begin());
cout << "v2: "; output(v2);
}
// 测试3:组合使用算法库、迭代器、vector实现元素旋转移位
void test3() {
using namespace std;
vector<int> v0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
cout << "v0: "; output(v0);
vector<int> v1{v0};
// 将[v1.begin(), v1.end())区间内元素循环左移1位
rotate(v1.begin(), v1.begin()+1, v1.end());
cout << "v1: "; output(v1);
vector<int> v2{v0};
// 将[v1.begin(), v1.end())区间内元素循环左移2位
rotate(v2.begin(), v2.begin()+2, v2.end());
cout << "v2: "; output(v2);
vector<int> v3{v0};
// 将[v1.begin(), v1.end())区间内元素循环右移1位
rotate(v3.begin(), v3.end()-1, v3.end());
cout << "v3: "; output(v3);
vector<int> v4{v0};
// 将[v1.begin(), v1.end())区间内元素循环右移2位
rotate(v4.begin(), v4.end()-2, v4.end());
cout << "v4: "; output(v4);
}
- 运行测试结果截图

- 问题回答
- Q1:reserve和reserve_copy的区别
reserve s1需要先对s1用s0初始化,然后对s1本身进行反转;而reserve_copy则是先对s2初始化为空,将s0先反转,再直接复制给s2 - Q2:rotate算法如何改变元素顺序,三个参数分别代表什么
如果需要整体左移a位,则利用迭代器v.begin()+a修改rotate的中间参数;如果需要整体右移a位,则利用迭代器v.end()-a修改rotate的中间参数;
第一个参数表示左边界(包含),第二个参数指向的元素变成整个区间的新起点,第三个参数表示右边界(不包含)【因为v.end表示的是最后一个元素的再后面一个位置】
- Q1:reserve和reserve_copy的区别
任务二
- 源代码
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <iomanip>
#include <cstdlib>
#include <ctime>
//模板函数声明
template<typename T>
void output(const T&c);
int generate_random_number();
void test1();
void test2();
int main(){
std::srand(std::time(0));//添加随机种子
std::cout<<"测试1:\n";
test1();
std::cout<<"测试2:\n";
test2();
}
//输出容器对象c中的元素
template <typename T>
void output(const T &c){
for(auto &i:c)
std::cout<<i<<" ";
std::cout<<"\n";
}
//返回[0,100]区间内的一个随机整数
int generate_random_number(){
return std::rand()%101;
}
//测试1:对容器类对象指定迭代器区间赋值、排序
void test1(){
using namespace std;
vector<int> v0(10);//创建一个动态数组对象v0,对象大小为10
generate(v0.begin(),v0.end(),generate_random_number);//生成随机数填充v0
cout<<"v0:";
output(v0);
vector<int> v1{v0};
sort(v1.begin(),v1.end());//对整个vector排序
cout<<"v1:";
output(v1);
vector<int> v2{v0};
sort(v2.begin()+1,v2.end()-1);//只对中间部分排序,不包含首尾元素
cout<<"v2:";
output(v2);
}
//测试2:对容器类对象指定迭代器区间赋值、计算最大值/最小值/均值
void test2(){
using namespace std;
vector<int> v0(10);
generate(v0.begin(),v0.end(),generate_random_number);
cout<<"v0:";
output(v0);
//求最大值和最小值
auto min_iter=min_element(v0.begin(),v0.end());
auto max_iter=max_element(v0.begin(),v0.end());
cout<<"最小值:"<<*min_iter<<endl;
cout<<"最大值:"<<*max_iter<<endl;
//同时求最大值和最小值
auto ans=minmax_element(v0.begin(),v0.end());
cout<<"最小值:"<<*(ans.first)<<endl;
cout<<"最大值:"<<*(ans.second)<<endl;
//求平均值
double avg1=accumulate(v0.begin(),v0.end(),0.0)/v0.size();
cout<<"均值:"<<fixed<<setprecision(2)<<avg1<<endl;
sort(v0.begin(),v0.end());
double avg2=accumulate(v0.begin()+1,v0.end()-1,0.0)/(v0.size()-2);
cout<<"去掉最大值、最小值后,均值:"<<avg2<<endl;
}
- 运行测试结果截图

- 问题回答
- Q1:generate算法作用
搭配srand(std::time(0))种子,return std::rand()%n,生成n以内的随机数
-Q2:minmax_element与分别调用min_element和max_element优势
只需要调用一次,就用ans存了最小最大值的迭代器,一次性求得最大最小值,简化运算,减少时间复杂度
-Q3:用法、与自定义函数generate_random_number相比的使用场景
用法:[]:捕获列表:抓取外部变量;():形参列表;std::rand():生成随机数;std::rand()%101:生成范围是0~100的随机数
lambda适用场景:1.需要捕获不在本函数内的局部变量为己所用;2.只使用一次,逻辑很短的小函数,就在当地定义使用;3.需要将这一串代码打包成可调用对象,传到别的地方晚点执行
- Q1:generate算法作用
任务三
- 源代码
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
unsigned char func(unsigned char c);
void test1();
void test2();
int main(){
std::cout<<"测试1:字符串大小写转换\n";
test1();
std::cout<<"\n测试2:字符变换\n";
test2();
}
unsigned char func(unsigned char c){
if(c=='z')
return 'a';
if(c=='Z')
return 'A';
if(std::isalpha(c))
return static_cast<unsigned char>(c+1);
return c;
}
void test1(){
std::string s1{"Hello World 2049!"};
std::cout<<"s1="<<s1<<'\n';
std::string s2;
for(auto c:s1)
s2+=std::tolower(c);//大写转换成小写,+表示连接字符串
std::cout<<"s2="<<s2<<"\n";
std::string s3;
for(auto c:s1)
s3+=std::toupper(c);//小写转换成大写,+表示连接字符串
std::cout<<"s3="<<s3<<"\n";
}
void test2(){
std::string s1{"I love cocmoc!"};
std::cout<<"s1="<<s1<<"\n";
std::string s2(s1.size(),' ');//创建字符串s2,长度为s1.size(),每个字符是空格
std::transform(s1.begin(),s1.end(),s2.begin(),func);//s1从头到尾开始进行func转化并从头复制到s2
std::cout<<"s2="<<s2<<'\n';
}
- 运行测试结果截图

- 问题回答
- Q1:func功能
输出已知字符+1(该字符的下一个字符) - Q2:tolower/toupper的功能
tolower:将大写字符转换成小写字符
toupper:将小写字符转换成大写字符 - Q3:transform函数的4个参数的意义及修改第3个参数为s1.begin()的区别
参数意义:第一个参数:修改对象的起始点(包含);第二个参数:修改对象的终止点(不包含,理由在任务二中提及);第三个参数:复制对象的起点;第四个参数:函数体是对修改对象做何种修改的修改函数
区别:修改成s1.begin()则表示在s1自身上修改,而s2.begin()则表示s1自身不变,将修改结果复制给s2
- Q1:func功能
任务四
- 源代码
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>//引入cctype使用tolower
bool is_palindrome(const std::string &s);
bool is_palindrome_ignore_case(const std::string &s);
int main() {
using namespace std;
string s;
// 多组输入,直到按下Ctrl+Z结束测试
/*while(getline(cin,s)){*///实现允许读入空格
while(cin >> s){
cout << boolalpha
<< "区分大小写: " << is_palindrome(s) << "\n"
<< "不区分大小写: " << is_palindrome_ignore_case(s) << "\n\n";
}
}
bool is_palindrome(const std::string &s){
std::string s1=s;
std::reverse(s1.begin(),s1.end());
if(s==s1){
return true;
}
else
return false;
}
bool is_palindrome_ignore_case(const std::string &s){
std::string s2;
for(auto c:s)
s2+=std::tolower(c);
std::string s3=s2;
std::reverse(s3.begin(),s3.end());//reserve是原地逆转!必须创建一个字符串=待逆转字符串,对这个字符串逆转再与原字符串比较
if(s2==s3)
return true;
else
return false;
}
- 运行测试结果截图

- 问题回答
- Q1:如何允许读入空格
将输入语句cin>>s改成getline(cin,s),使用getline读取空行(包括看空格)
- Q1:如何允许读入空格
任务五
- 源代码
#include <iostream>
#include <string>
#include <algorithm>
std::string dec2n(int x, int n = 2);
int main() {
int x;
while(std::cin >> x) {
std::cout << "十进制: " << x << '\n'
<< "二进制: " << dec2n(x) << '\n'
<< "八进制: " << dec2n(x, 8) << '\n'
<< "十二进制: " << dec2n(x, 12) << '\n'
<< "十六进制: " << dec2n(x, 16) << '\n'
<< "三十二进制: " << dec2n(x, 32) << "\n\n";
}
}
std::string dec2n(int x,int n){
std::string s;
if(x==0){
s='0'+0;
}
while(x>0){
int yu=x%n;
if(yu<10){
s+='0'+yu;
}
else{
s+='A'+yu-10;
}
x/=n;
}
std::reverse(s.begin(),s.end());
return s;
}
- 运行测试结果截图

任务六
- 源代码
#include <iostream>
#include <cctype>
#include <algorithm>
#include <iomanip>
int main(){
using namespace std;
string s{" a b c d e f g h i j k l m n o p q r s t u v w x y z"};
string v;
for(auto c:s)
v+=toupper(c);
cout<<" "<<s<<endl;
int i;
for(i=1;i<=26;i++){
rotate(v.begin(),v.begin()+2,v.end());
cout<<setw(2)<<right<<i<<" "<<v<<endl;
}
return 0;
}
+运行测试结果截图

任务七
- 源代码
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
using namespace std;
int main(){
srand(time(0));
int i;
int a,b;
int operate;
char op;
int res;
int count=0;
for(i=0;i<10;i++){
a=rand()%10+1;//随机生成1~10
b=rand()%10+1;
operate=rand()%4;//处理随机生成符号的小妙招,用数字作代号
if(operate==0){
op='+';
res=a+b;//正确运算结果在此处写,机器自己算的是对的
}
else if(operate==1){
op='-';
if(a<b){//不必再生成,直接交换,提高效率
int t;
t=a;
a=b;
b=t;
}
res=a-b;
}
else if(operate==2){
op='*';
res=a*b;
}
else if(operate==3){
op='/';
while(a%b!=0){//处理不符合要求再生成一遍直到符合(不要用continue将决定权交给for循环,就在此处再写一遍随机生成语句
a=rand()%10+1;
b=rand()%10+1;
}
res=a/b;
}
cout<<a<<op<<b<<'=';//注意先后顺序
int ans;
cin>>ans;
if(ans==res){
count++;
}
}
double rate;
rate=static_cast<double>(count)/10*100;
cout<<"正确率:"<<fixed<<setprecision(2)<<rate<<"%"<<endl;
return 0;
}
- 运行测试结果截图

实验总结
本节收获:
一、语法
1.反转:
1.1 自身变 reverse(s0.begin(),s0.end());
1.2拷贝到 reverse_copy(s0.begin(),s0.end(),s1.begin());-->algorithm
2.移位:
2.1 左移 rotate(s0.begin(),s0.begin()+a,s0.end());
2.2右移 rotate(s0.begin(),s0.begin-a,s0.end());,总之,不管左移还是右移,第二个参数都是目标的第一个元素-->algorithm
3.生成随机数:std::srand(std::time(0));generate_random_number(){return rand()%101;}/[](){return rand()%101;}
生成随机数填充:generate(v0.begin(),v0.end(),generate_random_number);-->algorithm
4.求最大值、最小值
1.1 单独求 int min_inter=min_element(v0.begin(),v0.end());
1.2 一起求
auto ans=minmax_element(v0.begin(),v0.end());最小:*(ans.first),最大:*(ans.second) ans是std::pair类型,存两个迭代器-->algorithm
5.求平均值
double avg=accumulate(v0.begin(),v0.end(),0.0)/v0.size();
-->numeric
6.大小写转换
std::string s;
for(auto c:s){
s+=std::tolower/toupper(c);
}
-->cctype
二、算法
1.想去掉最大最小值求平均值,可采取先排序,去掉首尾求均值
sort(v0.begin(),v0.end());
double avg2=accumulate(v0.begin()+1,v0.end()-1,0.0)/(v0.size()-2);
2.进制转换问题,只要思路一致,就合并起来写,特殊情况(十六进制中的1015:A/...用if语句单独写。对所有数字,统一转化成字符存(所以要先定义string,+表示连接),最后不要忘记reverse
3.处理随机生成符号的小妙招:用数字作代号,再对应起来

浙公网安备 33010602011771号