• 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

  • 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

  • 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

C++ – 随机洗牌算法,std::random_shuffle和std::shuffle

C++ 发布于2022-06-06 阅读 7,060次 0次评论 2次点赞 本文共2986个字,阅读需要8分钟。

1 std::random_shufflestd::shuffle

std::random_shufflestd::shuffle处于头文件#include<algorithm>中。

std::random_shufflestd::shuffle都用于对给定容器范围内的元素重新进行洗牌,打乱顺序重新排序。不过由于std::random_shuffle在迭代器版本(不指定随机函数的情况下)通常依赖std::srand,并且依赖于全局状态,这导致元素洗牌后的不会很理想,所以std::random_shuffleC++14中已经被弃用,在C++17中被剔除。我们可以使用std::shuffle替代std::random_shuffle

函数形式

template< class RandomIt >
void random_shuffle( RandomIt first, RandomIt last );

template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc& r );

template< class RandomIt, class RandomFunc >
void random_shuffle( RandomIt first, RandomIt last, RandomFunc&& r );

template< class RandomIt, class URBG >
void shuffle( RandomIt first, RandomIt last, URBG&& g );

参数含义

  • first : 随机洗牌元素范围第一个元素
  • lats:随机洗牌元素范围最后一个元素
  • r:返回一个随机选择的可转换类型的值的函数对象
  • g:结果类型可转换为UniformRandomBitGenerator的参数

1.1 std::random_shuffle的使用

1.1.1 默认迭代器版本

#include <iostream>
#include <random>
#include <algorithm>
#include <vector>

template <typename T>
void PrintVector(const std::vector<T>& vector)
{
    for_each(vector.begin(), vector.end(), [](T x) {
        std::cout << x << " ";
        });
    std::cout << std::endl;
}


int main()
{
    for (int i = 0; i < 5; ++i)
    {
        std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        std::random_shuffle(vec.begin(), vec.end());
        PrintVector(vec);
    }

    return 0;
}

运行结果:

9 2 10 3 1 6 8 4 5 7
7 5 10 8 4 1 2 9 6 3
3 10 6 4 8 1 7 9 5 2
6 7 10 4 3 2 9 5 1 8
1 3 8 10 7 6 5 2 4 9

1.1.2 指定随机函数

#include <iostream>
#include <random>
#include <algorithm>
#include <vector>

template <typename T>
void PrintVector(const std::vector<T>& vector)
{
    for_each(vector.begin(), vector.end(), [](T x) {
        std::cout << x << " ";
        });
    std::cout << std::endl;
}

int random(int i)
{
    return std::rand() % i;
}


int main()
{
    for (int i = 0; i < 5; ++i)
    {
        std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        std::random_shuffle(vec.begin(), vec.end(),random);
        PrintVector(vec);
    }

    return 0;
}

运行结果:

9 2 10 3 1 6 8 4 5 7
7 5 10 8 4 1 2 9 6 3
3 10 6 4 8 1 7 9 5 2
6 7 10 4 3 2 9 5 1 8
1 3 8 10 7 6 5 2 4 9

从上述两个程序的输出结果上看,在使用默认std::srand()下虽然每一次循环输出的顺序不一样,但是程序内部容器的顺序已经是一样的,这就是std::random_shuffle被弃用的原因。

1.2 std::shuffle的使用

1.2.1 使用非确定性随机整数作为随机种子

#include <iostream>
#include <random>
#include <algorithm>
#include <vector>

template <typename T>
void PrintVector(const std::vector<T>& vector)
{
    for_each(vector.begin(), vector.end(), [](T x) {
        std::cout << x << " ";
        });
    std::cout << std::endl;
}

int main()
{
    for (int i = 0; i < 5; ++i)
    {
        std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        std::random_device rd;
        std::shuffle(vec.begin(), vec.end(), std::default_random_engine(rd()));
        PrintVector(vec);
    }

    return 0;
}

运行结果:

5 2 8 1 6 4 9 10 7 3
4 3 10 9 5 2 6 1 7 8
9 8 3 4 2 5 10 1 6 7
5 1 8 10 4 3 7 2 9 6
5 8 9 4 10 2 1 6 7 3

1.2.2 使用时间作为随机种子

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

template <typename T>
void PrintVector(const std::vector<T>& vector)
{
    for_each(vector.begin(), vector.end(), [](T x) {
        std::cout << x << " ";
        });
    std::cout << std::endl;
}

int main()
{
    for (int i = 0; i < 5; ++i)
    {
        std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
        std::shuffle(vec.begin(), vec.end(), std::default_random_engine(seed));
        PrintVector(vec);
    }

    return 0;
}

运行结果:

8 6 1 4 7 3 10 9 2 5
4 10 1 6 2 8 3 9 5 7
1 8 2 3 4 5 7 6 10 9
9 4 5 10 1 6 7 8 2 3
3 4 9 7 1 6 2 10 5 8

std::shuffle两个示例的输出结果上看,其输出的容器元素顺序完全不一样,与std::random_shuffle的结果相比,是真正的顺序重排,这就是为什么使用std::shuffle替代std::random_shuffle的原因。

欢迎扫码关注我的微信公众号,及时获取文章更新

微信公众号二维码

本文作者:StubbornHuang

版权声明:本文为站长原创文章,如果转载请注明原文链接!

原文标题:C++ – 随机洗牌算法,std::random_shuffle和std::shuffle

原文链接:https://www.stubbornhuang.com/2156/

发布于:2022年06月06日 10:59:09

修改于:2023年06月26日 20:05:32

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
WordPress - 防止用户在登录页面重复点击登录按钮造成重复登录
WordPress
下一篇
TortoiseGit - 本地仓库更改远程仓库URL
TortoiseGit
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号