C++ – 随机洗牌算法,std::random_shuffle和std::shuffle
本文作者:StubbornHuang
版权声明:本文为站长原创文章,如果转载请注明原文链接!
原文标题:C++ – 随机洗牌算法,std::random_shuffle和std::shuffle
原文链接:https://www.stubbornhuang.com/2156/
发布于:2022年06月06日 10:59:09
修改于:2022年06月06日 10:59:59

1 std::random_shuffle和std::shuffle
std::random_shuffle
和std::shuffle
处于头文件#include<algorithm>
中。
std::random_shuffle
和std::shuffle
都用于对给定容器范围内的元素重新进行洗牌,打乱顺序重新排序。不过由于std::random_shuffle
在迭代器版本(不指定随机函数的情况下)通常依赖std::srand
,并且依赖于全局状态,这导致元素洗牌后的不会很理想,所以std::random_shuffle
在C++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
的原因。
当前分类随机文章推荐
- C++ - websocket++库的可使用的所有事件总结 阅读78次,点赞0次
- C++STL容器 - std::map容器修改、元素操作总结 clear,insert,emplace,erase,swap,merge,extract,insert_or_assign等 阅读1358次,点赞0次
- C++ - std::numeric_limits
简介与使用,用于获取指定数据类型的最大值与最小值 阅读213次,点赞0次 - C++ – 字节数组byte[]或者unsigned char[]与long double的相互转换 阅读904次,点赞0次
- C++ - 将一维数组/二维数组/三维数组作为函数参数传递给函数 阅读1375次,点赞0次
- C++ - RAII机制 阅读237次,点赞0次
- CMake - 设置Debug或者Release编译模式 阅读2083次,点赞0次
- C++ - 常用的C++命令行参数解析第三方库 阅读2300次,点赞2次
- C++ - Windows下字符串UTF8编码转ANSI,ANSI转UTF8编码 阅读334次,点赞0次
- C++ - 我在项目实际开发中用到的第三方库/开源项目,涵盖网络、加密解密、GUI、网络、音视频、图片等等 阅读119次,点赞0次
全站随机文章推荐
- FFmpeg - 音频处理基本概念以及音频重采样(采样率转换) 阅读4919次,点赞0次
- Windows - OneDrive登录出现0x8019001错误 阅读192次,点赞0次
- 书籍翻译 - Cloth Simulation for Computer Graphics,Abstract中文翻译 阅读422次,点赞0次
- 书籍翻译 – Fundamentals of Computer Graphics, Fourth Edition,第3章 Raster Images中文翻译 阅读2003次,点赞3次
- Pytorch - torch.optim优化器 阅读540次,点赞0次
- 资源分享 - 深入应用C++ 11代码优化与工程级应用(祁宇著)PDF下载 阅读5415次,点赞0次
- Pytorch - 模型保存与加载以及如何在已保存的模型的基础上继续训练模型 阅读426次,点赞0次
- 资源分享 - Artificial Intelligence for Games , Third Edition 英文高清PDF下载 阅读533次,点赞0次
- 姿态估计 - COCO-WholeBody数据集骨骼关节keypoint标注对应 阅读2700次,点赞0次
- Python - 列表list遍历方法总结 阅读412次,点赞0次
评论
167