Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是否可以编写一个类似next_置换的函数,但它只置换r值,而不是n值?_C++_Algorithm - Fatal编程技术网

C++ 是否可以编写一个类似next_置换的函数,但它只置换r值,而不是n值?

C++ 是否可以编写一个类似next_置换的函数,但它只置换r值,而不是n值?,c++,algorithm,C++,Algorithm,std::next_permutation(和std::prev_permutation)排列范围[第一,最后一个)中的所有值,总共n!个排列(假设所有元素都是唯一的) 是否可以编写如下函数: template<class Iter> bool next_permutation(Iter first, Iter last, Iter choice_last); bool NextPermutationIndices(std::vector<int> &I, in

std::next_permutation(和std::prev_permutation)排列范围
[第一,最后一个)
中的所有值,总共n!个排列(假设所有元素都是唯一的)

是否可以编写如下函数:

template<class Iter>
bool next_permutation(Iter first, Iter last, Iter choice_last);
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;
        }
    }
}
该函数非常复杂,因为所有可能的off-by-one错误,以及使用它的一切都比可能需要的更复杂


编辑:

事实证明,这比我想象的要容易得多。从中,我能够找到我需要的许多精确算法(组合、排列等)的精确实现

模板
布尔下一个部分置换(双向算子优先,
双向运算符中间,
双向运算符(最后一个)
{
标准::反向(中间,最后);
return std::next_置换(first,last);
}

此外,还有一种组合算法也以类似的方式工作。不过,它的实现要复杂得多。

Java组合生成器的源代码位于。去掉Java习惯用法,它几乎正是您所寻找的,实现为一个生成器,以保护您的内存圣人


这个问题来自被称为组合数学的数学领域,它是离散数学的一部分。离散数学对计算机科学实践者至关重要,因为它几乎包括我们日常使用的所有数学(如逻辑、算法、计数、关系、图论等).我强烈推荐 ,如果你能负担得起的话


(注意:这个问题与“,”有关,但不是完全重复,因为这个问题要求在一般情况下解决。)

为了迭代nPk置换,我使用了
for_each_permutation()
前面介绍的算法。它使用Knuth提供的一个很好的算法,原地旋转元素,使它们在最后保持原始顺序。因此,它满足您的无外部内存要求。它也适用于双向运算符。它不满足您看起来像
next_permutation()的要求
。然而,我认为这是一个胜利——我不喜欢有状态的API。

算法简化是将其分为两个单独的步骤

  • 从原始数据中生成所有可能选择的R元素的列表
  • 对于每个选择,创建所选元素的所有可能排列
通过交错这些操作,可以避免分配中间列表


通过跳过未选择的项,可以在双向迭代器上实现选择。生成所有选择,例如,通过排列一系列
R
1和
(N-R)
0。这将需要O(N)额外的内存,但使您能够在适当的位置排列原始序列。

不管它有什么价值,这里有一个可以正常工作的实现

它要求上面选择的元素以排序的顺序开始。它只有在序列中没有重复元素时才起作用(如果有,它会遗漏一些排列,并且不会以正确的排列结束)。它也可能遗漏一些边缘情况,因为我没有真正彻底地测试它,因为我没有实际使用它的计划

这种方法的一个好处是,这种方法不会按字典顺序访问排列,这可能(但可能不是)很重要。有时使用boost::bind创建一个函子来传递给每个人也是一种痛苦

template<class Iter>
bool next_choice_permutation(Iter first, Iter choice, Iter last)
{
    if (first == choice)
        return false;

    Iter i = choice;
    --i;
    if (*i < *choice) {
        std::rotate(i, choice, last);
        return true;
    }

    while (i != first) {
        Iter j = i;
        ++j;
        std::rotate(i, j, last);
        --i;
        --j;
        for (; j != last; ++j) {
            if (*i < *j)
                break;
        }
        if (j != last) {
            std::iter_swap(i, j);
            return true;
        }
    }
    std::rotate(first, ++Iter(first), last);
    return false;
}
模板
布尔下一次选择排列(Iter优先,Iter选择,Iter最后)
{
if(first==选项)
返回false;
Iter i=选择;
--一,;
如果(*i<*选择){
标准::旋转(i,选择,最后);
返回true;
}
而(i!=第一){
Iter j=i;
++j;
标准:旋转(i,j,最后);
--一,;
--j;
对于(;j!=last;++j){
如果(*i<*j)
打破
}
如果(j!=最后一个){
标准:国际热核聚变实验堆交换(i,j);
返回true;
}
}
标准::旋转(第一,++Iter(第一),最后);
返回false;
}

良好的链接。这基本上就是我正在使用的方法,尽管我可以通过将一些代码打包到类中而不是每次使用时所做的工作来消除一些浪费。让它检查和操作实际的数据数组是否没有办法做到这一点?如果你是指你认为我的意思——从N中选择任意R元素--您的方法的签名应该是
bool next\u排列(Iter first,Iter last,int result\u count)
以使意图更清楚。什么是“排列范围[first,last]中的元素,但只选择范围[first,choice\u last]中的元素?”意思?你只是从N中选择任意一个R元素并排列这些R元素吗?或者你真的是指该范围内的元素(如果是,其他元素会怎么样?)输入一个整数意味着它只能在随机访问迭代器上工作。如果可能的话,我希望避免这样的限制。很好的链接,尽管它有误导性,因为实现Iter+int操作确实需要随机访问迭代器而不是双向迭代器。但是他们没有明确说明这一点。我的道歉-不是looked过一会儿再看。也许advance()会解决它。
template<class Iter>
bool next_choice_permutation(Iter first, Iter choice, Iter last)
{
    if (first == choice)
        return false;

    Iter i = choice;
    --i;
    if (*i < *choice) {
        std::rotate(i, choice, last);
        return true;
    }

    while (i != first) {
        Iter j = i;
        ++j;
        std::rotate(i, j, last);
        --i;
        --j;
        for (; j != last; ++j) {
            if (*i < *j)
                break;
        }
        if (j != last) {
            std::iter_swap(i, j);
            return true;
        }
    }
    std::rotate(first, ++Iter(first), last);
    return false;
}