实验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);
}
  • 运行测试结果截图

屏幕截图 2026-10-18 113827

  • 问题回答
    • 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表示的是最后一个元素的再后面一个位置】

任务二

  • 源代码
#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; 
} 
  • 运行测试结果截图

屏幕截图 2026-10-20 142521

  • 问题回答
    • 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.需要将这一串代码打包成可调用对象,传到别的地方晚点执行

任务三

  • 源代码
#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';
}
  • 运行测试结果截图

屏幕截图 2026-10-20 155052

  • 问题回答
    • Q1:func功能
      输出已知字符+1(该字符的下一个字符)
    • Q2:tolower/toupper的功能
      tolower:将大写字符转换成小写字符
      toupper:将小写字符转换成大写字符
    • Q3:transform函数的4个参数的意义及修改第3个参数为s1.begin()的区别
      参数意义:第一个参数:修改对象的起始点(包含);第二个参数:修改对象的终止点(不包含,理由在任务二中提及);第三个参数:复制对象的起点;第四个参数:函数体是对修改对象做何种修改的修改函数
      区别:修改成s1.begin()则表示在s1自身上修改,而s2.begin()则表示s1自身不变,将修改结果复制给s2

任务四

  • 源代码
#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;
}
  • 运行测试结果截图

屏幕截图 2026-10-20 171624

  • 问题回答
    • Q1:如何允许读入空格
      将输入语句cin>>s改成getline(cin,s),使用getline读取空行(包括看空格)

任务五

  • 源代码
#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; 
}
  • 运行测试结果截图

屏幕截图 2026-10-20 174627

任务六

  • 源代码
#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;
}

+运行测试结果截图

屏幕截图 2026-10-20 194904

任务七

  • 源代码
#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; 
} 
  • 运行测试结果截图

屏幕截图 2026-10-20 202313

实验总结

本节收获:
一、语法
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.处理随机生成符号的小妙招:用数字作代号,再对应起来

posted @ 2026-10-20 22:55  Rae188  阅读(5)  评论(0)    收藏  举报