简体   繁体   English

使用位掩码生成排列

[英]Generate permutation using bitmask

I am generating all permutations of a string using bitmask.我正在使用位掩码生成字符串的所有排列。

void recurse(string s, int mask,int taken){

    if(taken == n){
        cout << " ";
        return;
    }
    for(int i = 0; i < n; i++){
        if(((1 << i) & mask) == 0){
            cout << s[i];
            recurse(s, (mask|(1 << i)), taken + 1);
        }
    }
}

In this function n is the length of the string.在这个函数中,n 是字符串的长度。 I am keeping track of how many characters are printed so far using taken variable.我正在使用 take 变量跟踪到目前为止打印了多少个字符。 In the main function I am calling在我调用的主函数中

recurse(s,0,0);

But this is not working correctly.但这不能正常工作。 For input对于输入

red红色

Its output is它的输出是

red de erd dr dre er红鹿博士 德雷尔博士

Where I am going wrong?我哪里出错了?


UPDATE // Below code works fine.更新// 下面的代码工作正常。

void recurse(string s, int mask,int taken, string pref){

    if(taken == n){
        cout << pref <<endl; 
        return;
    }
    for(int i = 0; i < n; i++){
        if(((mask >> i) & 1) == 0){
            recurse(s,(mask | (1 << i)),taken + 1, pref + s[i]);
        }
    }
}

Actually, the questioner provided the answer himself.其实,提问者自己给出了答案。 (Congratulation.) (恭喜。)

As I already started to fiddle (couldn't resist) I want to present my solution as well:由于我已经开始摆弄(无法抗拒),我也想提出我的解决方案:

#include <iostream>
#include <string>

using namespace std;

void recurse(
  const string &s, unsigned mask = 0, const string &out = string())
{
  size_t n = s.size();
  if (out.size() == n) cout << ' ' << out;
  for (size_t i = 0; i < n; ++i) {
    unsigned bit = 1 << i;
    if (mask & bit) continue;
    recurse(s, mask | bit, out + s[i]);
  }
}

int main()
{
  string test = "red";
  recurse(test);
  cout << endl;
  return 0;
}

Compiled and tested:编译和测试:

 red rde erd edr dre der

recurse() iterates through all characters of s looking for one which is not already marked in the mask as taken. recurse()遍历s所有字符,寻找mask尚未标记为已取的字符。 Each found characters is added to output out .每个找到的字符都被添加到输出out Then, the recursive call repeats it for all untaken characters.然后,递归调用对所有未使用的字符重复它。

Check out the sample code yourself on ideone .自己在ideone上查看示例代码。

Permutation tree for 'abc' 'abc' 的排列树

Your first code was visiting each node of this tree once and printing a character.您的第一个代码是访问该树的每个节点一次并打印一个字符。 So it was giving wrong output.所以它给出了错误的输出。

On a different note, you have used some redundant variables.另一方面,您使用了一些冗余变量。

Instead of n you should use s.size() .你应该使用s.size()而不是n

In the second code instead of taken you you should use pref.size() .在第二个代码中taken您应该使用pref.size()而不是pref.size()

Here is another version.这是另一个版本。 It's different from the questioner's code in 2 ways:它在两个方面与提问者的代码不同:

  1. The parameter taken can be omitted and we can use mask + 1 == (1 << n) instead.参数taken可以被省略,并且我们可以使用mask + 1 == (1 << n)而不是。 It basically checks if bits 1 to n-1 of mask are all 1's.它基本上检查,如果位1n-1mask全部为1。 If so, then the recursion depth is n and we print the permutation.如果是,则递归深度为n ,我们打印排列。

  2. Copying the string pref in each iteration can be slow if the size of the string is large.如果字符串的大小很大,则在每次迭代中复制string pref可能会很慢。 We can instead use a reference.我们可以改为使用引用。

#include <iostream>
#include <string>

using namespace std;

void recurse(string s, int mask, string &pref);

int n = 3;

int main()
{
    string pref("");
    recurse(string("abc"), 0, pref);
    return 0;
}

void recurse(string s, int mask, string &pref)
{
    if (mask + 1 == (1 << n)) {
        cout << pref << endl;
        return;
    }
    for (int i = 0; i < n; i++) {
        if (((mask >> i) & 1) == 0) {
            pref += s[i];
            recurse(s, (mask | (1 << i)), pref);
            pref.erase(pref.end() - 1);
        }
    }
}

where n is the size of the string.其中n是字符串的大小。 The output is输出是

abc
acb
bac
bca
cab
cba

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

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