繁体   English   中英

排列算法

[英]permutations algorithm

这是一个类,所以请不要太具体,但我正在寻找一种方法来列出数字数组的所有排列。

我们必须在不同的柱子(如锁)上排列不同的数字来解锁组合。 4 根柱子上的每根柱子上可能有 6 个数字。 但只要 n>r,它就应该适用于 r 上的任何 n。

我有办法随机生成一个组合,并有条不紊地在列表中查找它,但我无法生成生成所有排列的算法。

我能够在 C++ 中使用它获得数字 1-6 的所有组合:

//n = number of digits - 1; list = list of digits to work with; 
//number=finalized list of digits
void permute(int n, vector<int> list, vector<vector<int>>* number)
{
    if(n==1)
    {
        number->push_back(list);

    }else
    {
        for(int i = 1;i<n;i++)
        {
            permute(n-1,list, number);
            if(n%2 == 0)
            {
                swap(list[1],list[n]);
            }else
            {
                swap(list[i],list[n]);
            }
        }
    }

};

但是后来我得到了一个列表,例如 123456 163452 等,其中 1 始终是第一位数字,但我还需要在第一位数字切换并且只有 4 位数字出现时获取。

例子

6341

4163

等等,其中有 4 位数字,范围从 1 到 6,并且您有所有可能的组合。

谁能指出我正确的方向,让另一种算法补充这一点?

C++ 为此提供了一个完美的解决方案 - 它是std::next_permutation (您需要包含<algorithms>才能使用它)。

vector<int> list;
std::sort(list.begin(), list.end());
do {
    // use the current permutation of the list
} while (std::next_permutation(list.begin(), list.end()));

关于此函数的重要一点是,如果您想遍历范围的所有排列,则必须在第一次调用next_permuration之前对范围进行排序,否则您将在用完所有排列之前停止。

如果您需要自己实现,这可能没有帮助,但是 C++ 内置了next_permutation

http://www.cplusplus.com/reference/algorithm/next_permutation/

该函数背后的算法解释如下: std::next_permutation Implementation Explanation

从 N 项列表递归生成 N 长度排列的通用算法是:

对于列表中的每个元素 x

复制一个没有元素 x 的列表; 称之为 newList 查找 newList 的所有排列(这是递归,顺便说一句)

将元素 x 添加到 newList 的每个排列的开头

#include <iostream>
#include <list>

typedef std::list<int> IntList;
void iterlist(IntList& lst)
{
    for (IntList::iterator it=lst.begin(); it!=lst.end(); it++)
        cout << " " << *it;
    cout << endl;
}

std::list<IntList> permute(IntList& L1)
{
    if (L1.size() == 1)
        return std::list<IntList>(1,L1);

    std::list<IntList> res;
    for (IntList::iterator i = L1.begin(); i != L1.end();)
    {
        // remember this
        int x = (*i);

        // make a list without the current element
        IntList tmp(L1.begin(), i++);
        tmp.insert(tmp.end(), i, L1.end());

        // recurse to get all sub-permutations
        std::list<IntList> sub = permute(tmp);

        // amend sub-permutations by adding the element
        for (std::list<IntList>::iterator j=sub.begin(); j!=sub.end();j++)
            (*j).push_front(x);

        // finally append modified results to our running collection.
        res.insert(res.begin(), sub.begin(), sub.end());
    }
    return res;
}

int main()
{
    IntList lst;
    for (int i=0;i<4;i++)
        lst.push_back(i);
    std::list<IntList> res = permute(lst);
    for (std::list<IntList>::iterator i=res.begin(); i!=res.end(); i++)
        iterlist(*i);
    return 0;
}

首先,让我们谈谈您的问题,打印集合 {1,2,3,4,5,6} 中的所有P(6,4)数组,但 std::next_permutation 仅适用于所有元素的排列( P(6,6) ),不适合您的问题( P(6,4) )。 我认为使用 std::next_permutation 可以很容易地得到组合,因为我们知道P(6,4)=C(6,4)*P(4,4) ,简单的代码实现可能是这样的:

 1 #include <iostream>
  2 #include <vector>
  3
  4 int main()
  5 {
  6     std::vector<int> list;
  7     std::vector<int> subList;
  8     std::vector<bool> flag;
  9
 10     for (int i=1; i<=6; ++i)
 11         list.push_back(i);
 12     flag.insert(flag.end(),4,1);
 13     flag.insert(flag.end(),2,0);
 14     std::sort(flag.begin(), flag.end());
 15     do
 16     {
 17         subList.clear();
 18         for(int i=0; i<flag.size(); ++i)
 19         {
 20             if(flag[i])
 21             {
 22                 subList.push_back(list[i]);
 23             }
 24         }
 25         do
 26         {
 27             for(std::vector<int>::iterator it=subList.begin(); it!=subList.end(); ++it)
 28             {
 29                 std::cout << *it << " ";
 30             }
 31             std::cout << std::endl;
 32         }while(std::next_permutation(subList.begin(), subList.end()));
 33         std::cout << std::endl;
 34     } while(std::next_permutation(flag.begin(), flag.end()));
 35     return 0;
 36 }

这显然是C(6,4)的外循环查找和P(4,4)的内循环查找。 没有花太多时间在你的代码上,对于组合,你可以像DFS一样使用搜索方法,参考:组合

此函数使用 bitset 列出所有排列

#include <iostream>
#include <string>
#include <bitset>

using namespace std;

const int N = 3;

void permute(string_view s, bitset<N> &mask, string &pref)
{
    if (mask.all()) {
        cout << pref << endl;
        return;
    }
    for (int i = 0; i < N; i++) {
        if (!mask[i]) {
            mask.set(i);
            pref.push_back(s[i]);
            permute(s, mask, pref);
            pref.pop_back();
            mask.reset(i);
        }
    }
}

int main()
{
    string pref;
    bitset<N> mask;
    permute(string("abc"), mask, pref);
    return 0;
}

并进行一些修改后,它会打印所有组合

#include <iostream>
#include <string>
#include <bitset>

using namespace std;

const int N = 3;
const int M = 2;

void permute(string_view s, bitset<N> &mask, string &pref)
{
    if (pref.size() == M) {
        cout << pref << endl;
        return;
    }
    for (int i = 0; i < N; i++) {
        if (!mask[i]) {
            mask.set(i);
            permute(s, mask, pref);
            pref.push_back(s[i]);
            permute(s, mask, pref);
            pref.pop_back();
            mask.reset(i);
            break;
        }
    }
}

int main()
{
    string pref;
    bitset<N> mask;
    permute(string("abc"), mask, pref);
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM