实验1 现代C++编程初体验

任务一:

1.源代码task1.cpp

#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();
    
}
template <typename T>
void output(const T &c){
    for(auto &i : c)
        std::cout << i << ' ';
    std::cout << '\n';
}

void test1(){
    using namespace std;
    string s0{"0123456789"};
    cout << "s0 = " << s0 << endl;
    string s1(s0);
    reverse(s1.begin(),s1.end());
    cout << "s1 = " << s1 << endl;
    string s2(s0.size(),' ');
    reverse_copy(s0.begin(),s0.end(),s2.begin());
    cout << "s2 = " << s2 << endl;
}

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);
}

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};
    rotate(v1.begin(),v1.begin()+1,v1.end());
    cout << "v1: "; output(v1);
    
    vector<int> v2{v0};
    rotate(v2.begin(),v2.begin()+2,v2.end());
    cout << "v2: "; output(v2);
    
    vector<int> v3{v0};
    rotate(v3.begin(),v3.end()-1,v3.end());
    cout << "v3: "; output(v3);
    
    vector<int> v4{v0};
    rotate(v4.begin(),v4.end()-2,v4.end());
    cout << "v4: "; output(v4);
}

2.实验测试代码运行结果如下:

屏幕截图 2025-10-11 160614

3.观察与思考:

(1)reverse和reverse_copy就代码参数来看,前者为两个参数,而后者是三个,两者都有共同类型的参数;后者较前者而言多了一个“复制”值对象迭代器的开端;

(2)就功能而言,reverse是将原字符串倒置,而reverse_copy正如英文含义一样,反转后复制给另一个事先准备好的字符串变量;

(3)对于rotate算法,当第二个参数是第一个元素位置时,它是将前n个元素反转后,再整体移动至数据末尾;而当第二个参数是最后一个元素位置时,它是将后n个元素反转后,再整体移动至数据前端;

(4)rotate算法的三个参数中,第一个表示第一个元素的起始位置,第三个表示末尾元素的位置,而第二个参数则表示完成移动后,更新的字符串的第一个元素位置。

任务二:

1.源代码task2.cpp

#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 << "\n测试2:\n";
    test2(); 
}

template <typename T>
void output(const T&c){
    for(auto &i:c)
        std::cout << i << ' ';
    std::cout << '\n';
}

/*int generate_random_number(){
    return std::rand() % 101;
}
*/
void test1(){
    using namespace std;
    
    vector<int> v0(10);
    //generate(v0.begin(),v0.end(),generate_random_number);
    //lamda表达式: 
    generate(v0.begin(),v0.end(),[](){return std::rand()%101;});
    cout << "v0: ";output(v0);
    
    vector<int> v1{v0};
    sort(v1.begin(),v1.end());
    cout << "v1: ";output(v1);
    
    vector<int> v2{v0};
    sort(v2.begin()+1,v2.end()-1);
    cout << "v2: ";output(v2);
    
}

void test2(){
    using namespace std;
    
    vector<int> v0(10);
    //generate(v0.begin(),v0.end(),generate_random_number);
    //lamda表达式: 
    generate(v0.begin(),v0.end(),[](){return std::rand()%101;});
    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();
    cout << "去掉最大值、最小值之后,均值:" << avg2 << endl; 
}

 

2.实验测试代码运行结果如下:

(1)使用原代码运行结果:

屏幕截图 2025-10-12 151923

(2)使用lamda表达式运行结果:

 

屏幕截图 2025-10-12 152755

3.观察与思考:

(1)generate算法的作用是给创建的动态数组对象填充数据;

(2)一方面,代码量减少;另一方面,不需要增加多余的变量,节省空间;

(3)使用lamda表达式后,逻辑仍然未变。

 任务三:

1.源代码task3.cpp

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

2.实验测试代码运行结果如下:

屏幕截图 2025-10-12 154729

3.观察与思考:

(1)func的功能为将每个字母转换为按照26字母表的下一位字母;

(2)tolower是将大写字母变为小写字母,toupper是将小写字母变为大写字母;

(3)transform的前两个参数表示原字符串,而三个则表示从新字符串的起始位置开始复制该字符串转换后的串,最后一个则是字符串转换的依据(样式);改变后,相当于不保留原串,把转换的串保存在这个原字符串中。

任务四:

1.源代码task4.cpp

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

bool is_palindrome(const std::string &s){
    for (int i = 0;i < s.size() / 2; i++){
        if(s[i] != s[s.size() - i - 1]){
            return false;
        }
    }
    return true;
    
}
bool is_palindrome_ignore_case(const std::string &s){
    for (int i = 0;i < s.size() / 2; i++){
        if(std::tolower(s[i])!= std::tolower(s[s.size() - i - 1])){
            return false;
        }
    }
    return true;
    
}

 

2.实验测试代码运行结果如下:

屏幕截图 2025-10-12 161605

3.观察与思考:

(1)可以使用getline(cin,s)来处理这样的问题。

任务五:

1.源代码task5.cpp

#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){
    if(x == 0) return "0"; 
    if (n < 2 || n > 36) return "";
    char stand[36] = {'0','1','2','3','4','5','6','7','8',
                        '9','A','B','C','D','E','F','G',
                        'H','I','J','K','L','M','N','O','P',
                        'Q','R','S','T','U','V','W','X','Z'};
    std::string res = "";
    
    while(x > 0){
        res += stand[x % n];
        x /= n;
    }
    std::reverse(res.begin(),res.end());
    return res;
}

2.实验测试代码运行结果如下:

屏幕截图 2025-10-12 170043

任务六:

1.源代码task6.cpp

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

int main(){
    std::string s{"abcdefghijklmnopqrstuvwxyz"};
    std::cout<< std::right << std::setw(2) << " ";
    for(int i = 0;i < 26; i++){
        std::cout << std::right << std::setw(2) << s[i];
        s[i] = std::toupper(s[i]);
    }
    std::cout << '\n'; 
    for(int i = 1;i <= 26; i++){
        std::cout << std::right << std::setw(2) << i;
        std::rotate(s.begin(),s.begin() + 1,s.end());
        for(int j = 0;j < 26; j++){
            std::cout << std::right << std::setw(2) << s[j];
        }
        if(i <26)
            std::cout << '\n'; 
    }
    
}

2.实验测试代码运行结果如下:

屏幕截图 2025-10-12 172218

任务七:

1.源代码task7.cpp

#include <iostream>
#include <iomanip>
#include <algorithm>

double calculate(int a,int b,char sig){
    switch(sig){
        case '+': return a + b;
        case '-': return a - b;
        case '*': return a * b;
        case '/': return a / b;
        default: return 0;
    }
}

int main(){
    std::srand(std::time(0)); 
    char signal[4] = {'+','-','*','/'};
    int cnt = 10,yes = 0;
    int total = cnt;
    while(cnt--){
        double res;
        int sig_pos = std::rand() % 4;
        int fir,sec;
        double test;
        bool status = true;
        while(status){
            fir = std::rand() % 11;
            sec = std::rand() % 11;
            if((signal[sig_pos] == '-') && (fir >= sec)){
                status = false;
            }
            if((signal[sig_pos] == '/') && (fir >= sec) && (sec != 0)&& (fir % sec == 0)){
                status = false;
            }
            if((signal[sig_pos] != '-' ) && (signal[sig_pos] != '/')){
                status = false;
            }
        }
        std::cout << fir << " " << signal[sig_pos] << " " << sec << " = ";
        std::cin >> res;
        test = calculate(fir,sec,signal[sig_pos]);
        if(res == test)
            yes++;
    }
    std::cout << "正确率:" << std::fixed << std::setprecision(2) << 1.0 * yes / total * 100 << "%" << std::endl;
} 

2.实验测试代码运行结果如下:

屏幕截图 2025-10-12 183038

屏幕截图 2025-10-12 182951

 

总结:

  通过此次实验,我了解了许多c++自带标准库组件,并且能够较为熟练的掌握,体会到了其便捷性,但是仍然有一些不懂的地方,例如对于迭代器的理解,以及随机种子对于随机数生成的影响。

posted @ 2025-10-12 18:37  Likgon  阅读(24)  评论(1)    收藏  举报