23-24C++(39)——随机函数、函数模板、自动类型、匿名函数

一、随机函数  

C++中使用 random 头文件的 random_device 类型变量产生随机数。该随机 数生成器使用梅森旋转算法(Mersenne twister),用于快速产生高质量伪随机无 符号整数(unsigned int)。  

1、伪随机数和真随机数 伪随机数:看似随机的数字,具有可重复性和可预见性 真随机数:以非确定方式出现,具有不可重复性和不可预见性  

2、计算机不适合生成真正的随机数,只能由公式生成伪随机数。对于大多数应 用而言,伪随机数已足够用。真正的随机数可以用放射性元素的衰变周期、噪声 频率,实现难度大。

 3、评价伪随机数发生器性能的标准:伪随机序列的周期。

4、案例

(1)产生 20 个随机无符号整数值

说明:

如果想要生成有符号的整数, 那么可以把     cout << rd() << endl;

修改为:      cout << (int)rd() << endl;

或者        int a = rd(); cout << a << endl;

#include <iostream>
#include <random>
using namespace std;
int main()
{
	random_device rd;
	for (int i = 0; i < 20; i++)
	{
		cout << rd() << endl;
	}
	return 0;
}

(2)产生 0~99 之间的随机整数

把第(1)题中的 rd()修改为 rd() % 100

说明:一个无符号整数除以 100 的余数,范围在 0~99 之间。

(3)产生 a~b 之间的随机整数(范围包含 a 和 b) 把第(1)题中的 rd()修改为 rd() % (b - a + 1) + a

说明:b - a + 1 表示 a~b 范围内的不同整数数量,rd() % (b - a + 1)生成 0~b-a 之间的随机整数。  

(4)产生 1.0~9.9 之间的随机浮点数(一位小数部分) 把第(1)题中的 rd()修改为(rd() % 90 + 10) / 10.0

说明:先考虑生成 10~99 之间的整数,再除以 10.0。

(5)产生-20~10 之间的随机整数 把第(1)题中的 rd()修改为(int)(rd() % 31) -20

注意:rd()类型是无符号的,要在取余数后转化为有符号的 int。

二、函数模板  

模板是 C++泛型编程的基础。泛型程序独立于特性的数据类型来编写代码, 在程序编译时确定具体的数据类型。

假设需要编写一个函数比较两个值,如果两个值相等则返回 0,如果参数 1 小于参数 2 则返回-1,如果 参数 1 大于参数 2 则返回 1。如果两个值都是整数,

则函数可以写成:

int compare(int a, int b)
{
	if (a == b)
	{
		return 0;
	}
	else if (a < b)
	{
		return -1;
	}
	else
	{
		return 1;
	}
}

当 if、for、while 的大括号里只有一句话,则可以不写大括号(但不建议)。 为了节省空间,上面的代码也可以写成:

int compare(int a, int b)
{
	if (a == b) return 0;
	else if (a < b) return -1;
	else return 1;
}

但如果是比较两个浮点数的大小,则函数又要写成:

int compare(double a, double b)
{
	if (a == b) return 0;
	else if (a < b) return -1;
	else return 1;
}

还有可能是更多类型的数据比较,虽然 C++允许参数类型不同的同名函数 (下节课的重载),但这不是好的解决方案。

1、定义函数模板

可以定义一个通用的函数模板(function template),而不是为每种数据类型 都定义一个新函数。 一个函数模板就是一个公式,用来生成针对特定数据类型的 函数版本。 模板定义以关键字 template 开始,后面跟着一个模板参数列表,表示函数定 义中用到的特定数据类型。

当使用模板时,可以隐式或者显式指定模板实参,将 其绑定到模板参数上。

compare 函数可以写成模板:

#include <iostream>
using namespace std;
template<typename T>
int compare(T a, T b)
{
	if (a == b) return 0;
	else if (a < b) return -1;
	else return 1;
}

说明:

compare 函数的模板参数列表声明了一个名为 T 的类型参数,用 T 表示一 个数据类型。T 具体表示哪一种数据类型,是由编译时根据 compare 函数的调用 来确定。

例如在 main 函数中

int main()
{
	cout << compare(1, 0) << endl;
	return 0;
}

实参类型是 int,编译器会推断出模板实参 a 和 b 为 int,并把 int 绑定到模 板参数 T 中。

编译器用推断出的模板参数来实例化一个特定版本的函数。

如果 main 函数的代码是:

int main()
{
	cout << compare(1, 0) << endl;
	cout << compare(1.5, 2.1) << endl;
	return 0;
}

那么编译器会实例化出两个不同版本的 compare 函数。

对于第一个调用,编译器生成的 compare 中,T 被替换为 int。

对于第二个调用,编译器生成的 compare 中,T 被替换为 double。

2、多个模板参数的情况

在上述代码中,如果在主函数中 cout << compare(1.5, 2) << endl; ,则会引 发编译报错,原因是根据 1.5 和 2 推断出 T 的类型不一致。 如果要支持不同类型的两个实参比较大小则需要在模板参数列表中定义两 个模板参数,比如命名为 T1 和 T2。

#include<iostream>
using namespace std;
template<typename T1, typename T2>
int compare(T1 a, T2 b)
{
	if (a == b) return 0;
	else if (a < b) return -1;
	else return 1;
}
int main()
{
	cout << compare(1, 0) << endl;
	cout << compare(1.5, 2.1) << endl;
	return 0;
}

运行结果如下——

3、案例

(1)求两个相同类型数的总和

#include<iostream>
using namespace std;
template <typename T>
T getSum(T a, T b)
{
	return a + b;
}
int main()
{
	cout << getSum(4, 5);
	return 0;
}

运行结果如下——

(2)交换两个相同类型的数

#include<iostream>
using namespace std;
template <typename T>
void f(T& a, T& b)
{
	T c;
	c = a;
	a = b;
	b = c;
}
int main()
{
	int a = 5, b = 10;
	f(a, b);
	cout << a << "\n" << b << "\n";
	return 0;
}

运行结果如下——

【练习】以下程序的运行结果是 ,其中字母 A 的 ASCII 码为 65 

#include<iostream>
using namespace std;
template<class T1, class T2>
T1 f(T1 x, T2 y)
{
	return x + y;
}
int main()
{
	cout << f('A', 1) << f(1, 'A') << endl;
	return 0;
}

T1决定了输出的类型——

运行结果如下——

三、自动类型

1、auto 自动类型变量

编程时经常需要把表达式的值赋给变量,这要求声明变量时清楚地知道表达式的类型。有时要做到这一点并不容易,甚至根本做不到。为了解决这个问题, 从 C++11 标准开始,引入了 auto 类型,能让编译器去自动分析表达式所属的类 型。和原来那些只定义一种特定类型的说明符(例如 double)不同,auto 让编 译器通过初始值来推算变量的类型。显然,auto 定义的变量必须有初始值。  

auto c = a + b;

此时编译器将根据 a 和 b 相加的结果来推断 c 的类型。

如果 a 和 b 都是 int,则 c 是 int 类型;

如果 a 是 double,b 是 int,则 c 是 double 类型。

使用 auto 也可以在一条语句中定义多个变量。因为一条变量声明语句只能 有一个数据类型,所以该语句中所有变量的数据类型都必须一样

auto a = 0.5, b = 1.0;

2、函数中的自动返回类型

当函数的返回值类型为 auto 类型时,会根据 return 的值自动推断返回值的类型。要注意的是,一个返回值类型是 auto 的函数里如果存在多处 return 语句, 每处 return 语句返回值都要能推断成同一种类型

例:求两个任意类型数的总和(C++14 开始的语法,OJ 不支持)

#include<iostream>
using namespace std;
template<typename T1, typename T2>
auto getMax(T1 x, T2 y)
{
	return x + y;
}
int main()
{
	cout << getMax(1, 2) << endl;
	cout << getMax('A', 1) << endl;
	cout << getMax(1.5, 2) << endl;
	return 0;
}

运行结果如下——

四、匿名函数

匿名函数又称为𝜆函数,使用 lambda 表达式定义函数,是函数式编程的基础。 匿名函数定义在函数内部,仅在所在函数中可见。

1、lambda 函数语法

[capture](parameter)->return-type{statement}

[capture]:捕捉列表,捕捉上下文中的变量以供 lambda 函数使用。

(parameter):参数列表,与普通函数的参数列表一致。如果无参数,可以连同括 号一起省略。

->return-type:返回类型,如果无返回值则可以连同->一起省略。返回类型明确 时,也可以省略,由编译器负责对返回类型进行推导。

{statement}:函数体。与普通函数一样,不过除了可以使用参数外,还可以使用 所有捕捉的变量。

2、变量捕捉列表

匿名函数语法中[capture]变量捕获模块,可以捕捉的匿名函数外部作用域中 的变量,以供匿名函数的函数体使用。

[ ] 函数不需要访问外部作用域中任何变量

[&] 函数引用调用外部作用域中所有变量

引用调用——可以访问并且可以修改外围变量的值 (&)引用符号

[=] 函数传值调用外部作用域中所有变量

传值调用——可以访问但是不能修改外围变量的值

[=, &y] 函数传值调用外部作用域中所有变量,但是引用调用 y 变量

[&, x] 函数引用调用外部作用域中所有变量,但是传值调用 x 变量

[x, &y] 函数传值调用 x 变量,引用调用 y 变量

3、案例

(1)使用匿名函数实现求和函数

#include<iostream>
using namespace std;
int main()
{
	auto sum = [](int a, int b)->int {return a + b; };
	int x = 5, y = 10;
	cout << sum(x, y) << endl;
	cout << sum(x, x) << endl;
	return 0;
}

运行结果如下——

理解这句代码!

[capture](parameter)->return-type{statement}

(2)使用匿名函数计算 n 的阶乘

代码如下——

#include <iostream>
using namespace std;
int main()
{
	int n;
	cin >> n;
	auto fac = [=]()->int {
		int f = 1;
		for (int i = 1; i <= n; i++)
		{
			f = f * i;
		}
		return f;
	};
	cout << fac() << endl;
	return 0;
}

运行结果如下——

(3)使用匿名函数生成 x~y 之间的随机整数

代码如下——

#include<iostream>
#include<random>
using namespace std;
int main()
{
	int x, y;
	cin >> x >> y;
	random_device rd;
	auto getRand = [&]()->int
	{
		return rd() % (y - x + 1) + x;
	};
	int a = getRand();
	int b = getRand();
	int c = getRand();
	cout << "a=" << a << "\tb=" << b << "\tc=" << c << endl;
	return 0;
}

运行结果如下——

重点理解!!!!!!!!!!!!!!!

上文中均有提及!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拔刀能留住落樱吗、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值