【发布时间】:2010-09-19 06:12:39
【问题描述】:
std::next_permutation(和std::prev_permutation)置换[first, last)范围内的所有值,总共n!排列(假设所有元素都是唯一的)。
可以这样写函数吗:
template<class Iter>
bool next_permutation(Iter first, Iter last, Iter choice_last);
这会置换[first, last) 范围内的元素,但只选择[first, choice_last) 范围内的元素。即我们可能有 20 个元素,并且想要遍历其中 10 个选项的所有排列,20 P 10 个选项与 20 P 20 个选项。
- Iter 对我来说是一个随机访问迭代器,但如果它可以实现为双向迭代器,那就太好了!
- 所需的外部内存越少越好,但对我而言这并不重要。
- 每次迭代中选择的元素都会输入到序列的第一个元素中。
这样的功能可以实现吗?有谁知道任何现有的实现?
这基本上就是我正在做的事情来解决这个问题。也欢迎就如何改进这一点提出建议。
- 从
N元素的向量V开始,我想访问其中选择的R元素的每个排列(R <= N)。 - 用值
{ 0, 1, 2, ... R - 1 }构建一个长度为R的向量I,作为V元素的索引 - 在每次迭代中,构建一个长度为
R的向量C,其值为{ V[I[0]], V[I[1]], ... V[I[R - 1]] } - 使用
C中的值做一些事情。 - 应用一个函数来置换
I的元素,如果可以的话再次迭代。
该函数如下所示:
bool NextPermutationIndices(std::vector<int> &I, int N)
{
const int R = I.size();
for (int i = R - 1; ; --i) {
if (I[i] < N - R + i) {
++I[i];
return true;
}
if (i == 0)
return false;
if (I[i] > I[i-1] + 1) {
++I[i-1];
for (int j = i; j < R; ++j)
I[j] = I[j-1] + 1;
return true;
}
}
}
由于所有可能的错误,该函数非常复杂,而且使用它的所有内容都比可能需要的复杂。
编辑:
事实证明,这比我想象的要容易明显。从here,我能够找到许多我需要的精确算法(组合、排列等)的精确实现。
template<class BidirectionalIterator>
bool next_partial_permutation(BidirectionalIterator first,
BidirectionalIterator middle,
BidirectionalIterator last)
{
std::reverse(middle, last);
return std::next_permutation(first, last);
}
此外,还有一种以类似方式工作的组合算法。但是,实现起来要复杂得多。
【问题讨论】:
-
如果你的意思是我的意思——从 N 中选择 any R 元素——你的方法的签名应该是
bool next_permutation(Iter first, Iter last, int result_count)以使意图更清晰。跨度> -
“置换[first, last)范围内的元素,但只选择[first,choice_last)范围内的元素”是什么意思?您是否只是从 N 中选择 any R 元素并排列这些 R 元素?或者您真的是指该范围内的元素(如果是,其他元素会怎样?)
-
输入一个整数意味着它只适用于随机访问迭代器。如果可能的话,我希望避免这样的限制。