使用位掩码生成排列

时间:2017-10-29 09:48:23

标签: c++ algorithm

我使用位掩码生成字符串的所有排列。

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);
        }
    }
}

在此函数中,n是字符串的长度。我用跟踪变量跟踪到目前为止打印了多少个字符。 在我正在调用的主函数中

recurse(s,0,0);

但这不能正常工作。 输入

  

红色

它的输出是

  

红   德   ERD   博士   DRE   ER

我哪里错了?

更新 //下面的代码工作正常。

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]);
        }
    }
}

3 个答案:

答案 0 :(得分:2)

实际上,提问者自己提供了答案。 (祝贺。)

由于我已经开始摆弄(无法抗拒),我也想提出我的解决方案:

#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;
}

编译并测试:

 red rde erd edr dre der

recurse()遍历s的所有字符,查找尚未在mask中标记的字符。每个找到的字符都会添加到输出out。然后,递归调用会为所有未被捕获的字符重复它。

自己在ideone上查看示例代码。

答案 1 :(得分:0)

Permutation tree for 'abc'

您的第一个代码是访问此树的每个节点一次并打印一个字符。所以它提供了错误的输出。

另一方面,您使用了一些冗余变量。

而不是n,您应该使用s.size()

在第二个代码而不是taken中,您应该使用pref.size()

答案 2 :(得分:0)

这是另一个版本。它与发问者的代码有两种不同:

  1. 可以省略参数def join_paths(base_path, relative_paths): # Taking care of first case where base_path is "/" root if base_path == "/": return relative_paths # Convert the base_path to a list by splitting at "/" ["", "folder1", "folder2"] base_path_list = base_path.split("/") # Convert the relative_paths to a list by splitting at "/" ["", "folder1", "folder2"] relative_paths_list = relative_paths.split("/") # Take difference between length of base_path_list and length of relative_paths_list len_diff = len(relative_paths_list) - len(base_path_list) # Validate if difference in length is greater than 0 else it wont find # the sub list it needs to append if len_diff > 0: # Get last 'n' elements from relative_paths_list where n is len_diff list_to_append = relative_paths_list[-len_diff:] # Join the base path list with sub-list we just created above final_list = base_path_list + list_to_append # Join the elements in list with "/" return "/".join(final_list) elif len_diff == 0: final_list = base_path_list return "/".join(final_list) else: print("SOmething is really wrong") # run the code print(join_paths("/Windows/kin_test/path2", "/Windows/kin_dev/path2/path3")) ,而可以使用taken。它基本上检查mask + 1 == (1 << n)的{​​{1}}至1的位是否全部为1。如果是这样,则递归深度为n-1,我们将打印排列。

  2. 如果字符串的大小很大,则在每次迭代中复制mask可能会很慢。我们可以改为使用参考。

n

其中string pref是字符串的大小。输出是

#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);
        }
    }
}
相关问题