我特意编写了一个非常简单的类,它封装了一个std::vector,使它基本上能够用随机生成的数字自我填充,仅仅是为了测试我正在研究的一些排序算法的结果。
这只是一个业余项目,它不是生产代码:-)所以我想知道是否有任何方法来改进这个设计或我的方法。
除了良好的做法、风格和设计之外,我最大的疑问是:
populate():如果我使用了std::iota()后面跟着std::shuffle,正如注释中所解释的那样,我相信代码会更小、更简单,并且会有相同的结果(它不允许重复的数字,就像现在一样)。std::mt19937和std::uniform_int_distribution:大多数情况下,如果它们的实现看起来..。好的。看起来,需要显式的种子向量是不可避免的,但我并不真的喜欢它。--(如果我使用我的std::iota()实现,显然可以避免这种情况。我觉得这打破了班上的“超能力”。编辑:忘了补充,关于2号,我也有点好奇我是如何播种引擎。看上去对吗?
以下是头文件:
#ifndef algorithmicVec_H
#define algorithmicVec_H
#include <vector>
#include <random>
#include <chrono>
#include <cstdint>
/**
* std::vector composition with pseudo-random number self-populating capabilities
*/
class algorithmicVec {
private:
std::vector<uint32_t> vec;
static std::mt19937 gen;
static std::uniform_int_distribution<uint32_t> uint_dist99;
/**
* Returns a random uint32_t within the range of 0..99
*/
uint32_t getRandomNumber();
public:
/**
* Seeds static std::mt19937 with the current time in milliseconds since epoch
*/
static void seed();
/**
* Populates the vector with n elements using a std::uniform_int_distribution
* fed with std::mt19937.
*
* Using std::iota() followed by std::shuffle was considered, but not implemented
* mostly because random generated numbers seemed more interesting at the time,
* even to observe the result of the tested algorithms with possible repeated numbers.
*/
void populate (int sz);
/**
* Returns item at position pos
*/
uint32_t at(int pos);
/**
* Returns an iterator to the first item of the vector
*/
std::vector<uint32_t>::iterator begin();
/**
* Returns an iterator past-to-the-end of the vector
*/
std::vector<uint32_t>::iterator end();
};
#endif实施文件:
#include "algorithmicVec.hpp"
std::mt19937 algorithmicVec::gen;
std::uniform_int_distribution<uint32_t> algorithmicVec::uint_dist99(0, 99);
void algorithmicVec::seed() {
unsigned long seed = std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
gen.seed(seed);
}
void algorithmicVec::populate (int sz) {
for (int i = 0; i < sz; ++i) {
vec.push_back(getRandomNumber());
}
}
uint32_t algorithmicVec::getRandomNumber() {
return uint_dist99(gen);
}
uint32_t algorithmicVec::at(int pos) {
return vec.at(pos);
}
std::vector<uint32_t>::iterator algorithmicVec::begin() {
return vec.begin();
}
std::vector<uint32_t>::iterator algorithmicVec::end() {
return vec.end();
}一个最小的测试用例:
#include <iostream>
#include "algorithmicVec.cpp"
int main() {
algorithmicVec::seed();
algorithmicVec myVec;
myVec.populate(10); // populates myVec with 10 random numbers
for (auto a: myVec) {
std::cout << a << std::endl;
}
}发布于 2014-06-02 06:41:16
我认为写一门课太过分了。这给您带来了许多问题,因为您必须重新实现vector的S接口。
在当前状态下,与只返回随机填充的向量的函数相比,我看不到任何优势:
#include <vector>
#include <random>
#include <chrono>
#include <algorithm>
#include <iterator>
std::vector<uint32_t> generateRandomVector(std::size_t size) {
static std::mt19937 gen(
std::chrono::system_clock::now().time_since_epoch()
/ std::chrono::milliseconds(1));
static std::uniform_int_distribution<uint32_t> uint_dist99(0, 99);
std::vector<uint32_t> result;
result.reserve(size);
std::generate_n(std::back_inserter(result), size,
[&] {return uint_dist99(gen);});
return result;
}像这样使用它:
#include <iostream>
int main() {
for (auto a : generateRandomVector(20)) {
std::cout << a << std::endl;
}
}这种方法的优点是干净地将vector的功能(即存储数据)与随机生成的功能(它只是操纵一个向量)分开。
当然,这个接口失去了一些灵活性,但是如果您需要它,那么您应该编写一个允许创建随机向量的类,而不是一个恰好充满随机数字的向量类。
iota和shuffle并不能真正缩短填充的代码,并且在某种程度上“混淆”正在发生的事情(因此您必须添加额外的注释来说明您想要实现什么以及为什么要限制自己的排列)。std::size_t getSeedFromCurrentTime() {
return std::chrono::system_clock::now().time_since_epoch() /
std::chrono::milliseconds(1);
}
std::mt19937 algorithmicVec::gen(getSeedFromCurrentTime);关于从那时开始获得种子,我没有经验,也帮不了你。
发布于 2014-06-01 19:32:47
begin()和end()之外,您还应该拥有用于const迭代器的cbegin()和cend()。这些也是由std::vector提供的。at(),也应该重载operator[]。用户可以选择任何一个,但主要的区别是at()应该抛出一个异常(您的不应该这样做),而operator[]不应该这样做,这也是在std::vector文档中指定的。sz的参数名populate()似乎不准确。因为这是一个public函数,用户可以随时调用它,所以它不仅仅用于对象构造。该函数还添加了新的随机数,而不是重新定义向量的大小。这个参数的更好的名称可以是类似于numNewRandElems的名称。getRandomNumber()应该是const,因为它没有修改任何数据成员。一定要阅读std::vector文档,以获得更多关于其定义的信息。
发布于 2014-06-01 19:33:08
主要是风格评论:
为了获得更好的可读性,我会将包含的标题按字母顺序排列:
#include <chrono>
#include <cstdint>
#include <random>
#include <vector>始终在“标准库”之前包含您自己的标题(这将更早地捕获错误):
#include "algorithmicVec.cpp"
#include <iostream>注释不清楚,因为您没有使用精确的间隔符号。您是指[0, 99] (99包括在内)还是[0, 99) (99独占)?
/**
* Returns a random uint32_t within the range of 0..99
*/应该在您的源代码管理或文档的基本原理部分中的注释:
* Using std::iota() followed by std::shuffle was considered, but not implemented
* mostly because random generated numbers seemed more interesting at the time,
* even to observe the result of the tested algorithms with possible repeated numbers.对于at()、begin()和end()的注释是多余的,您可以简单地对整个部分进行注释,表示它们转发了std::vector接口的这些部分。
此外,at()的注释是错误的,因为如果索引超出范围,它也会抛出异常。
最后,正如@Jamal所提到的,您转发的std::vector接口的部分是相当有选择性和不完整的(operator[],以及常量和反向开始/结束迭代器)。
https://codereview.stackexchange.com/questions/52213
复制相似问题