C++实现随机数生成的现代化封装

 更新时间:2024年11月18日 08:56:35   作者:T0uken  
在现代 C++ 中,随机数生成是许多程序设计中不可或缺的部分,例如游戏开发、算法设计、统计模拟等,本文将以一个封装好的随机工具类 Random 为例,深入剖析其功能的实现与使用,并引入相关知识,帮助读者触类旁通,掌握 C++ 随机数的核心技巧

背景知识

随机数的生成

C++ 的标准库提供了一套强大且灵活的随机数工具,主要通过以下几部分组成:

  • 随机数引擎:例如 std::mt19937,生成伪随机数序列。
  • 分布:例如 std::uniform_int_distribution,对随机数进行分布转换。
  • 随机数种子:用于初始化随机数引擎,保证随机性。

类的设计原则

在设计一个通用的随机工具类时,我们可以封装常见的随机操作,例如:

  • 生成指定范围内的整数或浮点数。
  • 按概率生成布尔值。
  • 对容器进行随机打乱。

类定义与功能分解

以下是 Random 类的完整定义:

#include <chrono>
#include <iostream>
#include <random>
#include <algorithm>

struct Random {
    std::mt19937 rnd;

    Random()
        : rnd(std::chrono::steady_clock::now().time_since_epoch().count()) {}
    
    void setSeed(unsigned int seed) {  
        rnd.seed(seed);  
    }

    int operator()(int l, int r) {
        return std::uniform_int_distribution(l, r)(rnd);
    }

    double operator()(double l, double r) {
        return std::uniform_real_distribution(l, r)(rnd);
    }

    bool operator()(double p) {
        return std::bernoulli_distribution(p)(rnd);
    }

    template<typename T>
    void operator()(std::vector<T>& vec) {  
        std::shuffle(vec.begin(), vec.end(), rnd);  
    }
};

下面,我们逐一拆解并讲解其核心部分。

随机数引擎的初始化

Random()
    : rnd(std::chrono::steady_clock::now().time_since_epoch().count()) {}
  • std::mt19937
    std::mt19937 是一种基于梅森旋转算法的伪随机数生成器,具有较好的性能和随机性。其名字来源于生成 19937 位的周期序列。

  • 初始化种子

    • 默认使用当前时间戳(以纳秒为单位)作为种子。
    • 时间戳通过 std::chrono::steady_clock 获取,保证种子不同步。

设置随机数种子

void setSeed(unsigned int seed) {  
    rnd.seed(seed);  
}
  • 种子控制随机性
    • 给定相同的种子,随机数生成序列是确定的。
    • 这种特性非常适合调试和可复现的实验。

生成随机整数

int operator()(int l, int r) {
    return std::uniform_int_distribution(l, r)(rnd);
}
  • std::uniform_int_distribution

    • 用于生成均匀分布的整数。
    • 构造函数参数为上下界 [l, r]
  • 调用方式
    分布对象 dist 是一个可调用对象。通过传入随机引擎 rnd,即可生成一个随机数。

示例:

Random random;
int number = random(1, 10); // 生成 [1, 10] 范围内的随机整数

生成随机浮点数

double operator()(double l, double r) {
    return std::uniform_real_distribution(l, r)(rnd);
}
  • std::uniform_real_distribution
    • 用于生成均匀分布的浮点数。
    • 构造函数参数为上下界 [l, r),即下界闭、上界开。

示例:

Random random;
double value = random(0.0, 1.0); // 生成 [0.0, 1.0) 范围内的随机浮点数

按概率生成布尔值

bool operator()(double p) {
    return std::bernoulli_distribution(p)(rnd);
}
  • std::bernoulli_distribution
    • 按照给定的概率 p 返回 true 或 false
    • 构造函数参数 p 表示返回 true 的概率,范围为 [0, 1]

示例:

Random random;
bool result = random(0.7); // 70% 概率返回 true,30% 概率返回 false

随机打乱容器

template<typename T>
void operator()(std::vector<T>& vec) {  
    std::shuffle(vec.begin(), vec.end(), rnd);  
}
  • std::shuffle

    • 对容器元素进行随机排列。
    • 使用 rnd 引擎,确保伪随机性。
  • 模板设计
    允许对任何 std::vector<T> 类型的容器进行操作。

示例:

Random random;
std::vector<int> vec = {1, 2, 3, 4, 5};
random(vec); // 随机打乱 vec

使用场景

随机分配任务

假设有 10 个任务需要随机分配给 3 名员工:

Random random;
std::vector<int> tasks = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
random(tasks);

for (int i = 0; i < tasks.size(); ++i) {
    std::cout << "Task " << tasks[i] << " -> Employee " << random(1, 3) << "\n";
}

模拟抛硬币

Random random;
int heads = 0, tails = 0;

for (int i = 0; i < 100; ++i) {
    if (random(0.5)) {
        ++heads; // 正面
    } else {
        ++tails; // 反面
    }
}

std::cout << "Heads: " << heads << ", Tails: " << tails << "\n";

小结

通过本文的剖析,我们从以下几个方面深入了解了 Random 类的设计与实现:

  • 使用 std::mt19937 随机数引擎生成高质量伪随机数。
  • 利用 C++ 标准库中的分布对象生成特定范围或分布的随机数。
  • 封装常用随机功能,提高代码的可读性和复用性。

到此这篇关于C++实现随机数生成的现代化封装的文章就介绍到这了,更多相关C++随机数现代化封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言数据结构之二叉树详解

    C语言数据结构之二叉树详解

    二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式。本文将通过示例详细讲解一下二叉树,需要的可以参考一下
    2022-03-03
  • C++入门教程之内联函数与extern "C"详解

    C++入门教程之内联函数与extern "C"详解

    C++中的内联函数与静态函数静态函数静态函数的定义静态函数又称为内部函数,下面这篇文章主要给大家介绍了关于C++入门教程之内联函数与extern "C"的相关资料,需要的朋友可以参考下
    2023-01-01
  • C语言 解压华为固件的实例代码

    C语言 解压华为固件的实例代码

    这是解压华为固件(update.app)的C语言。。其实这也是我翻115翻出来的。。。
    2013-08-08
  • C语言金币阵列问题解决方法

    C语言金币阵列问题解决方法

    这篇文章主要介绍了C语言金币阵列问题解决方法,主要涉及数组的灵活运算,是一类非常经典的算法,需要的朋友可以参考下
    2014-09-09
  • C语言实例真题讲解数据结构中单向环形链表

    C语言实例真题讲解数据结构中单向环形链表

    链表可以说是一种最为基础的数据结构了,而单向链表更是基础中的基础。链表是由一组元素以特定的顺序组合或链接在一起的,不同元素之间在逻辑上相邻,但是在物理上并不一定相邻。在维护一组数据集合时,就可以使用链表,这一点和数组很相似
    2022-04-04
  • C++判断矩形相交的方法

    C++判断矩形相交的方法

    这篇文章主要介绍了C++判断矩形相交的方法,涉及C++针对平面坐标数学运算的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • C++多态定义及实现深度剖析

    C++多态定义及实现深度剖析

    多态也是面向对象程序设计的重要特性,它都是配合继承来使用,多态可以增加程序设计的灵活性,这篇文章主要介绍了C++多态定义及实现的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-09-09
  • C++实现LeetCode(133.克隆无向图)

    C++实现LeetCode(133.克隆无向图)

    这篇文章主要介绍了C++实现LeetCode(133.克隆无向图),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++实现单链表删除倒数第k个节点的方法

    C++实现单链表删除倒数第k个节点的方法

    这篇文章主要介绍了C++实现单链表删除倒数第k个节点的方法,结合实例形式分析了C++单链表的定义、遍历及删除相关操作技巧,需要的朋友可以参考下
    2017-05-05
  • Qt数据库应用之实现数据打印到纸张

    Qt数据库应用之实现数据打印到纸张

    关于Qt打印内容到纸张,网上的办法非常多,比如有些直接用painter绘制,逐步控制分页打印。本文介绍的方法则是将内容作为html设置到文档对象,再调用文档对象的print方法传入QPrinter对象打印,感兴趣的同学可以了解一下
    2022-01-01

最新评论