实验1

任务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自身不变
    // 创建一个字符串 s2,长度和 s0 一样,每个字符都是空格 ' '
    reverse_copy(s0.begin(),s0.end(),s2.begin());
    // s0.begin(), s0.end():要反转的源区间,即整个 s0
    // s2.begin():拷贝的目标起始位置
    // 作用:把 s0 的字符从后往前依次写入 s2
    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());
    // rotate(first, middle, last) 有三个参数:
    // first:区间起点
    // middle:新的“第一个元素”所在位置(关键点)
    // last:区间终点(开区间)
    cout<<"v1:";    output(v1);

    vector<int> v2{v0};
    // 将[v1.begin(),v2.begin()]区间内元素循环左移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);

    
}

运行截图

task1

问题

· 问题1: reverse()是将区间里面的元素直接反转,不产生新的内存分配,只需要传入两个参数,一个是反转区间起点,另一个是反转区间终点;reverse_copy()则是将区间里面的元素反转后复制在另一个目标区间,要传入三个参数:源区间起点,源区间终点,目标区间起点
· 问题2:rotate(first,middle,last):将区间[first,last)内的元素循环移动,让middle指向的元素成为新的第一个元素,first:区间起点,middle:新的第一个元素所在位置,last:区间终点(开区间)

任务2

源代码

#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));   // 添加随机种子
    // srand是seed random的缩写,time(0)相当于time(nullptr)只要返回值,不存储
    std::cout<<"测试1:\n";
    test1();
    std::cout<<"\n测试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
    // v0.begin(),v0.end() 指定要填充的区间,即整个容器 v0(从头到尾)
    // generate_random_number 这是一个可调用对象(callable),必须满足:无参数、有返回值。每填充一个元素就调用它一次
    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;
}

运行截图

image

问题

· 问题1:generate(fist,last,generator):first,last指定要填充的区间;generator是一个可调用对象,必须满足无参数,有返回值;generator会给区间内每一个元素调用一次generator,并把返回值赋给当前元素
· 问题2:只需要调用一次minmax_element就可以同时得到最大值和最小值,而min_element和max_element则需要分别调用才可以得到对应的最大值和最小值,用minmax_element只需要遍历一次容器,而min_element和max_element则需要遍历两次,所以minmax_element效率更高
· 问题3:效果相同,lamba写法:[捕获列表] (参数列表) -> 返回类型 { 函数体 }
以题目中的为例::
· []:捕获列表,空的,表示不需要从外界捕获任何变量;
· ():参数列表,空的,因为generate要求generator要满足无参数;
· ->:返回类型,被省略了,因为c++11起支持自动推导返回类型,因为std::rand()%101返回的是int,所以lamba自动推导出返回类型是int;
· {return std::rand()%101}:函数体,产生从0到100的随机数

任务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;
}
// 字母都往后移1位,不是字母的原样返回


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 cosmos!"};
    std::cout<<"s1="<<s1<<'\n';

    std::string s2(s1.size(),' ');
    std::transform(s1.begin(),s1.end(),
                   s2.begin(),
                   func);
                   std::cout<<"s2="<<s2<<'\n';
    // 它是 <algorithm> 里的标准算法,作用一句话:遍历一个区间,对每个元素施加一个操作,把结果写到另一个区间。
    // std::transform(first, last, d_first, op);
    // 对 [first,last) 每个元素 *it,算 op(*it),写到 *d_first:
}

运行截图

image

问题

· 问题1:func()自定义此函数是为了让c里面的每一个字母都向后移一位,其中z变成a,Z变成A;如果不是字母的话就原样返回。
· 问题2:tolower(c):如果c是大写字母,那就转小写,如果c不是大写字母,就原样返回;toupper(c):如果c是小写字母,那就转大写,如果c不是小写字母,就原样返回。
· 问题3:transform()是里面的标准算法,作用是:遍历一个区间,对每个元素施加一个操作,把结果写到另一个区间;
transform(first,last,d_first,op) 表示对[first,last)每个元素it,算op(it),写到*d_first。如果把把第三个参数从s2.begin()改成s1.begin(),就相当于对s1进行修改,那么后面的cout语句就应该改成std::cout<<"s1="<<s1<<'\n';

任务4

源代码

#include <iostream>
#include <string>
#include <algorithm>

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(cin >> s) {
        cout << boolalpha 
             << "区分大小写: " << is_palindrome(s) << "\n"
             << "不区分大小写: " << is_palindrome_ignore_case(s) << "\n\n";
    }     
}


// 函数is_palindrome定义
// 待补足
// ×××
bool is_palindrome(const std::string &s) {
    std::string s1(s);
    std::reverse(s1.begin(),s1.end());
    if(s1==s)   
        return true;
    return false;
}


// 函数is_palindrome_ignore_case定义
// 待补足
// ×××
bool is_palindrome_ignore_case(const std::string &s) {
    std::string s1(s);
    std::reverse(s1.begin(),s1.end());
    std::string s2;
    for(auto c:s)
        s2+=static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
    std::string s3;
    for(auto c:s1)
        s3+=static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
    if(s2==s3)
        return true;
    return false;

}

运行截图

image

问题

·可以把while(cin>>s)改为wihle(getline(s))
这样运行截图就这样:
image
getline()会读取换行符之前的所有内容并丢弃换行符,所以输入的hello oop就可以原样保留。

任务5

源代码

#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"; 
    }
}

// 函数dec2n定义
// 待补足
// ×××
 std::string dec2n(int x,int n) {
    if(x==0)    return "0";
    const char digits[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    std::string result="";
    while(x>0)
    {
        int remainder=x%n;
        result+=digits[remainder];
        x/=n;
    }
    std::reverse(result.begin(),result.end());
    return result;
 }

运行截图

image

任务6

源代码

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<iomanip>
int main() {
    // vector<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"};
    std::string s{"ABCDEFGHIJKLMNOPQRSTUVWXYZ"};
    std::string s0;
    for(auto c:s)
        s0+=std::tolower(c);
    std::cout<<"  ";
    for(auto c:s0)
        std::cout<<" "<<c;
    std::cout<<'\n';
    for(int i=1;i<=26;i++) {
        std::string s1{s};
        rotate(s1.begin(),s1.begin()+i,s1.end());
        std::cout<<std::right<<std::setw(2)<<i;
        for(auto c:s1)
            std::cout<<" "<<c;
        std::cout<<'\n';
    }
    return 0;
}

运行截图

image

任务7

源代码

#include<iostream>
 #include<iomanip>
 #include<iomanip>
 #include<cstdlib>
 
 int main() {
    std::srand(std::time(0));
    int correct_count=0;
    const int TOTAL_QUESTIONS=10;

    for(int i=1;i<=10;i++)
    {
        int op=std::rand()%4;

        int a,b;
        int user_ans,correct_ans;
        char operator_;

        if(op==0) {
            operator_='+';
            a=std::rand()%10+1;
            b=std::rand()%10+1;
            correct_ans=a+b;
        }
        else if(op==1) {
            operator_='-';
            a=std::rand()%10+1;
            b=std::rand()%10+1;
            if(a<b)
                std::swap(a,b);
            correct_ans=a-b;
        }
        else if(op==2) {
            operator_='*';
            a=std::rand()%10+1;
            b=std::rand()%10+1;
            correct_ans=a*b;
        }
        else {
            operator_='/';
            b=std::rand()%10+1;
            correct_ans=std::rand()%10+1;
            a=correct_ans*b;
            while(a>10) {
                b=rand()%5+1;
                correct_ans=rand()%(10/b)+1;
                a=correct_ans*b;
            }
        }
        std::cout<<a<<" "<<operator_<<" "<<b<<" "<<"="<<" ";
        std::cin>>user_ans;
        if(user_ans==correct_ans) 
            correct_count++;
    }
    double accuracy=(double)correct_count/TOTAL_QUESTIONS*100;
    std::cout<<"正确率:"<<std::fixed<<std::setprecision(2)<<accuracy<<"%"<<std::endl;

 }

 

运行截图

· 第一次
image
·第二次
image

实验总结

· 在最后一个实验里面本来想用min(),max()来解决减法中要保证前一个数字大于后一个数字的问题的,但是用了之后发现这个样没办法交换a和b的位置,导致打印出来还是a<b的减法问题,不知道有没有什么方法可以比较简便地运用它

posted @ 2026-10-20 16:54  psycheddd  阅读(6)  评论(0)    收藏  举报