实验一

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

	std::cout << "测试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());//将s0反转后的结果拷贝到s2,s0自身不变
	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);

}
  • 运行截图

image

  • 观察与思考
1.reverse和reverse_copy有什么区别?

reverse:是原地修改。
reverse_copy:是把反转的结果拷贝到新的变量里,原变量不变。

2.rotate算法是如何改变元素顺序的?它的三个参数分别代表什么?

rotate函数是包含在的标准库里
std::rotate(first,middle,last)
旋转前元素顺序:[first,middle)[middle,last)
旋转后元素顺序:[middle,last)[first,middle)
它相当于把元素划分为first、middle、last三部分。

任务2

  • 程序源代码
task2.cpp
#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<cstdlib>
#include<ctime>
#include<iomanip>

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

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;//返回[0,100]区间内的一个随机整数
}
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());
	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);
	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;//老师给的代码少了#include<iomanip>

	sort(v0.begin(), v0.end());
	double avg2 = accumulate(v0.begin() + 1, v0.end() - 1, 0.0) / (v0.size () - 2);
	cout << "去掉最大值、最小值之后,均值:" << avg2 << endl;
}
  • 运行截图

屏幕截图 2026-10-16 113749

  • 观察与思考

1.generate算法的作用是什么?

generate(v.begin(),v.end(),num)

用num填充数组,第一个参数是起始位置,第二个参数是终止位置,第三个参数是填充物。

2.minmax_element和分别调用min_element、max_elemnet相比,有什么优势?

minmax_element只扫描一遍容器,时间开销更小。分别调用min_element、max_element需要扫描两遍容器。
减少内存访问,缓存友好。分开调用要读两遍,容易造成更多cache miss
代码更简洁,一次性拿到两个迭代器。

3.把代码中函数generate_random_number的声明和定义注释起来,把两处调用改成如下写法,观察效果是否等同?查阅c++中lambda表达式用法。

//test1()模块和test2()模块:
generate(v0.begin(),v0.end(),generate_random_number);
---->改成
generate(v0.begin(),v0.end(),[](){return std::rand()%101;});

效果等同。

完整语法格式
[捕获列表](参数列表) mutable -> 返回值类型 { 函数体 }
  • []:捕获列表,用来捕获外面作用域的变量
  • ():形参列表,和普通函数参数一样
  • mutable(可选):允许修改值捕获的变量
  • ->类型(可选):尾置返回类型;能自动推导时可以省略
  • {}:函数体
一、捕获列表(最常用4种)
  1. [] 不捕获任何外部变量(generate代码就是这个)
[](){ return rand()%101; }
  1. [=] 值捕获:把外部变量拷贝一份进来,默认不能修改
int a=10;
auto f = [=](){ return a+1; };
  1. [&] 引用捕获:直接引用外部原变量,可以修改原值
int a=10;
auto f = [&](){ a++; };
  1. [x, &y] 混合捕获:x值捕获,y引用捕获

捕获只能捕获当前作用域的变量,不能跨函数随便抓。

二、generate代码例子拆解
generate(v0.begin(), v0.end(), []() {return std::rand() % 101; });
  • []:不捕获外部变量
  • ():无参数
  • 省略返回值:编译器自动推导int
  • {return std::rand()%101;}:函数体,返回0~100随机数>

generate会反复调用这个lambda,给vector每个元素赋值

任务三

  • 程序源代码
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;//只要执行了return函数立马结束
}

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 <<std::endl;
	
	std::string s3;
	for (auto c : s1)
		s3 += std::toupper(c);
	std::cout << "s3=" << s3 << "\n";


	//什么是迭代器

	//for (auto it1 = s1.begin(), it2 = s2.begin();
		//it1 != s1.end();
		//++it1, ++it2) {
		//*it2 = func(*it1);
	//}这个代码里面最后一行为什么有* 是表示引用类型吗
	//这表示取迭代器里的参数,取出it1指向的参数


}

void test2() {
	std::string s1{ "I love cosmos!" };
	std::cout << "s1=" << s1 << '\n';

	std::string s2(s1.size(), ' ');//先为s2分配足够大内存,它不会自动扩容
	std::transform(s1.begin(), s1.end(), s2.begin(), func);//对s1的每个字符调用func,并将返回值填入s2中
	//若第三个参数是s1.begin(),他也可以修改原字符串
	std::cout << "s2=" << s2 << '\n';

	//std::string s3;
	//std::transform(s1.begin(), s1.end(), std::back_inserter(s3), func);//自动追加,更安全
	//std::cout << "s3=" << s3 << '\n';

}
  • 运行截图

屏幕截图 2026-10-18 213451

  • 观察与思考
1.自定义函数func功能是什么?

将字符串加密,加密方法就是将所有字母按照字母表顺序往后顺延一位,并且转换为a

2.tolower和toupper功能分别是什么?

tolowr:将所有字母转换成小写
toupper:将所有字母转换成大写

3.transform的4个参数意义分别是什么?如果把第三个参数s2.begin()改成s1.begin(),有何区别?

第一个参数是读取的起始位置,第二个参数是读取的终止位置,第三个参数是新元素的存放起始位置,第四个参数是修改元素的规则。
task.3cpp代码中表示对s1中每一个字符都调用函数func,并将修改后元素保存在s2中
若改成s1.begin(),那么就变成原地修改,修改后的元素在s1中。

任务四

  • 程序源代码
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) {
		cout << boolalpha << "区分大小写:" << is_palindrome(s) << "\n"
			<< "不区分大小写:" << is_palindrome_ignore_case(s) << "\n\n";
		//多组输入,直到按下crl+z结束测试
	}
}
bool is_palindrome(const std::string& s) {
	int left = 0;
	int right = s.size() - 1;//获取字符串长度
	while (left < right) {
		//if (left == right == 1)
			//return true;
		if (s[left] != s[right]) {//字符串可以直接通过下标访问
			return false;
		}
		left++;
		right--;
	}
	return true;
}

bool is_palindrome_ignore_case(const std::string& s) {
	std::string s2( s.size(),' ' );
	std::transform(s.begin(), s.end(), s2.begin(), std::tolower);
	return  is_palindrome(s2);
}
  • 运行截图

image

  • 观察与思考
使用cin>>s输入时,输入在字符串中不能包含空格。如果希望测试字符串包含空格(如hello opp),代码应如何调整?

cin>>s遇到空格、回车就停止读取,没法读入带空格字符串。换成getline(cin,s)读取一整行(包含空格)
注意:如果前面混用cin,缓冲区会残留换行符,要cin.ignore()清空。

int main(){
  using namespace std;
  string str;
  while(getline(cin,str)){
		cout << boolalpha << "区分大小写:" << is_palindrome(str) << "\n"
			<< "不区分大小写:" << is_palindrome_ignore_case(str) << "\n\n";
		//多组输入,直到按下crl+z结束测试
	}
}

任务5

  • 程序源代码
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' << std::endl;
	}
}
std::string dec2n(int x, int n) {
	if (x == 0) {
		return "0";
	}
	std::string table = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//字符串赋值
	std::string res;
	while (x > 0) {
		int rem = x % n;
		res += table[rem];//字符串可以通过通过下标找到
		x = x / n;
	}
	std::reverse(res.begin(), res.end());
	return res;
}
  • 运行截图

image

任务6

  • 程序源代码
task6.cpp
#include<iostream>
#include<string>

using namespace std;

void printTable() {
	cout << "   ";
	for (char ch = 'a'; ch <= 'z'; ch++)
		cout << ch << " ";
	cout << "\n";

	for (int i = 1; i <= 26; i++) {
		if (i < 10)
			cout <<" "<< i << " ";
		else
			cout << i << " ";
		for (int j = 0; j < 26; j++) {
			char ch = 'A' + (i - 1 + j) % 26;
			cout << ch << " ";
		}
		cout << endl;
	}
}
int main() {
	printTable();
}
  • 运行截图

image

任务7

  • 程序源代码
task7.cpp
#include <iostream>
#include <cstdlib>
#include <ctime>
#include<iomanip>
using namespace std;

int main()
{
    srand((unsigned)time(NULL));
    const int total = 10;
    int correct = 0;

    for (int i = 0; i < total; ++i)
    {
        int op = rand() % 4;
        int a, b, std_ans;
        char op_ch;

        if (op == 0)
        {
            op_ch = '+';
            a = rand() % 10 + 1;
            b = rand() % 10 + 1;
            std_ans = a + b;
        }
        else if (op == 1)
        {
            op_ch = '-';
            do
            {
                a = rand() % 10 + 1;
                b = rand() % 10 + 1;
            } while (a < b);
            std_ans = a - b;
        }
        else if (op == 2)
        {
          
            op_ch = '*';
            a = rand() % 10 + 1;
            b = rand() % 10 + 1;
            std_ans = a * b;
        }
        else
        {
           
            op_ch = '/';
            do
            {
                a = rand() % 10 + 1;
                b = rand() % 10 + 1;
            } while (a % b != 0);
            std_ans = a / b;
        }

        int user_ans;
        cout << a << " " << op_ch << " " << b << " = ";
        cin >> user_ans;
        if (user_ans == std_ans)
        {
            correct++;
        }
    }

    double rate = 100.0 * correct / total;
    cout << "正确率:" << fixed<<setprecision(2) <<rate<< "%" << endl;
  

    return 0;
}
  • 运行截图
    image
posted @ 2026-10-22 15:02  周怡嘉  阅读(5)  评论(0)    收藏  举报