【发布时间】:2012-06-24 07:53:20
【问题描述】:
我无法找到一种体面的方法来随机打乱std::vector 中的元素,并在进行一些操作后恢复原始顺序。我知道这应该是一个相当琐碎的算法,但我想我太累了……
由于我被限制使用自定义随机数生成器类,我想我不能使用std::random_shuffle,这无论如何也无济于事,因为我还需要保留原始顺序。所以,我的方法是创建一个std::map,作为原始位置和随机位置之间的映射,如下所示:
std::map<unsigned int, unsigned int> getRandomPermutation (const unsigned int &numberOfElements)
{
std::map<unsigned int, unsigned int> permutation;
//populate the map
for (unsigned int i = 0; i < numberOfElements; i++)
{
permutation[i] = i;
}
//randomize it
for (unsigned int i = 0; i < numberOfElements; i++)
{
//generate a random number in the interval [0, numberOfElements)
unsigned long randomValue = GetRandomInteger(numberOfElements - 1U);
//broken swap implementation
//permutation[i] = randomValue;
//permutation[randomValue] = i;
//use this instead:
std::swap(permutation[i], permutation[randomValue]);
}
return permutation;
}
我不确定上述算法是否是随机排列的正确实现,因此欢迎任何改进。
现在,这就是我如何设法利用这个排列图:
std::vector<BigInteger> doStuff (const std::vector<BigInteger> &input)
{
/// Permute the values in a random order
std::map<unsigned int, unsigned int> permutation = getRandomPermutation(static_cast<unsigned int>(input.size()));
std::vector<BigInteger> temp;
//permute values
for (unsigned int i = 0; i < static_cast<unsigned int>(input.size()); ++i)
{
temp.push_back(input[permutation[i]]);
}
//do all sorts of stuff with temp
/// Reverse the permutation
std::vector<BigInteger> output;
for (unsigned int i = 0; i < static_cast<unsigned int>(input.size()); ++i)
{
output.push_back(temp[permutation[i]]);
}
return output;
}
有些东西告诉我,我应该只能使用一个 std::vector<BigInteger> 来进行该算法,但是,现在,我无法找出最佳解决方案。老实说,我并不关心input 中的数据,所以我什至可以将其设为非常量,覆盖它,然后跳过创建它的副本,但问题是如何实现算法?
如果我做这样的事情,我最终会射中自己的脚,对吗? :)
for (unsigned int i = 0; i < static_cast<unsigned int>(input.size()); ++i)
{
BigInteger aux = input[i];
input[i] = input[permutation[i]];
input[permutation[i]] = aux;
}
编辑:在史蒂夫关于使用“Fisher-Yates”洗牌的评论之后,我相应地更改了我的getRandomPermutation 函数:
std::map<unsigned int, unsigned int> getRandomPermutation (const unsigned int &numberOfElements)
{
std::map<unsigned int, unsigned int> permutation;
//populate the map
for (unsigned int i = 0; i < numberOfElements; i++)
{
permutation[i] = i;
}
//randomize it
for (unsigned int i = numberOfElements - 1; i > 0; --i)
{
//generate a random number in the interval [0, numberOfElements)
unsigned long randomValue = GetRandomInteger(i);
std::swap(permutation[i], permutation[randomValue]);
}
return permutation;
}
【问题讨论】:
-
我可以推荐 bogosort 它将解决您的两个问题。 en.wikipedia.org/wiki/Bogosort
-
为什么不保存原始列表的状态;完成洗牌后,只需将您保存的列表重新分配给洗牌的列表?
-
@Brendan 我只需要保留订单,而不是列表的内容。这是安全交互协议的一部分,它要求列表中的项目在进行交互之前随机打乱,并且在协议完成后,我需要恢复原始顺序。
-
@RTS 你能详细说明你的想法吗?
标签: c++ algorithm random mapping permutation