我知道这是基本的东西。可能非常非常基本
如何获得给定集合的所有可能组合。
例如
string set =“abc”;
我希望得到:
a b c aa ab ac aaa aab aac aba abb abc aca acb ac baa bab ...
并且列表继续(如果没有设置长度限制)。
我正在寻找一个非常干净的代码 - 我发现的所有东西都很脏而且工作不正常。关于我写的代码我也可以说。
我需要这样的代码,因为我正在编写在多个线程上工作的强力(md5)实现。模式是父进程使用自己的组合块来提供线程,因此他们可以自己处理这些组件。
示例:第一个线程得到100个排列的包,第二个得到下一个100等。
如果我应该在任何地方发布最终节目,请告诉我。
答案 0 :(得分:7)
这是一些C ++代码,用于生成给定长度的功率集的排列。
函数getPowPerms
采用一组字符(作为字符串向量)和最大长度,并返回置换字符串的向量:
#include <iostream>
using std::cout;
#include <string>
using std::string;
#include <vector>
using std::vector;
vector<string> getPowPerms( const vector<string>& set, unsigned length ) {
if( length == 0 ) return vector<string>();
if( length == 1 ) return set;
vector<string> substrs = getPowPerms(set,length-1);
vector<string> result = substrs;
for( unsigned i = 0; i < substrs.size(); ++i ) {
for( unsigned j = 0; j < set.size(); ++j ) {
result.push_back( set[j] + substrs[i] );
}
}
return result;
}
int main() {
const int MAX_SIZE = 3;
string str = "abc";
vector<string> set; // use vector for ease-of-access
for( unsigned i = 0; i < str.size(); ++i ) set.push_back( str.substr(i,1) );
vector<string> perms = getPowPerms( set, MAX_SIZE );
for( unsigned i = 0; i < perms.size(); ++i ) cout << perms[i] << '\n';
}
运行时,此示例打印
a b c aa ba ca ab bb cb ... acc bcc ccc
更新:我不确定这是否有用,但这里有一个名为next
的“生成器”函数,它会在给定当前项目的情况下创建列表中的下一个项目。
也许你可以生成第一个 N 项并将它们发送到某个地方,然后生成下一个 N 项并将它们发送到其他地方。
string next( const string& cur, const string& set ) {
string result = cur;
bool carry = true;
int loc = cur.size() - 1;
char last = *set.rbegin(), first = *set.begin();
while( loc >= 0 && carry ) {
if( result[loc] != last ) { // increment
int found = set.find(result[loc]);
if( found != string::npos && found < set.size()-1 ) {
result[loc] = set.at(found+1);
}
carry = false;
} else { // reset and carry
result[loc] = first;
}
--loc;
}
if( carry ) { // overflow
result.insert( result.begin(), first );
}
return result;
}
int main() {
string set = "abc";
string cur = "a";
for( int i = 0; i < 20; ++i ) {
cout << cur << '\n'; // displays a b c aa ab ac ba bb bc ...
cur = next( cur, set );
}
}
答案 1 :(得分:5)
C ++有一个函数next_permutation(),但我认为这不是你想要的。
你应该可以使用递归函数轻松完成。 e.g。
void combinations(string s, int len, string prefix) {
if (len<1) {
cout << prefix << endl;
} else {
for (int i=0;i<s.size();i++) {
combinations(s, len-1, prefix + s[i])
}
}
}
编辑:对于线程部分,我假设您正在使用密码暴力破解程序?
如果是这样,我想密码测试部分就是你想要加速的而不是密码生成。
因此,您可以简单地创建一个生成所有组合的父进程,然后将每个 k 密码提供给线程 k mod N (其中 N < / em>是用于检查的线程数。
答案 2 :(得分:0)
另一个版本的排列是在Python的标准库中,尽管你在C ++中提出质疑。
http://docs.python.org/library/itertools.html#itertools.permutations
但是你的列表包含每个字符的不定式序列,所以我认为应该首先定义如何排序的方法,并清楚地说明你的算法。
答案 3 :(得分:0)
我不能给你代码,但你需要的是一个递归算法,这里有一些伪代码
这个想法很简单,用你的每个字符串连接集合中的每个字符串,然后置换字符串。将所有较小的字符串添加到您的集合中,并使用新集合再次执行相同的操作。继续走,直到你累了:)
可能有点混乱,但想一点;)
set = { "a", "b", "c"}
build_combinations(set)
{
new_set={}
for( Element in set ){
new_set.add(Element);
for( other_element in set )
new_element = concatinate(Element, other_element);
new_set.add(new_element);
}
new_set = permute_all_elements(new_set);
return build_combinations(new_set);
}
这显然会导致堆栈溢出,因为没有终止条件:)所以在build_combinations函数中放入你喜欢的条件(可能是set的大小?)来终止递归
答案 4 :(得分:0)
这是一种奇怪且通常不理想的做法,但是嘿,它有效,并且它不使用递归: - )
void permutations(char c[], int l) // l is the length of c
{
int length = 1;
while (length < 5)
{
for (int j = 0; j < int(pow(double(l), double(length))); j++) // for each word of a particular length
{
for (int i = 0; i < length; i++) // for each character in a word
{
cout << c[(j / int(pow(double(l), double(length - i - 1))) % l)];
}
cout << endl;
}
length++;
}
}
答案 5 :(得分:0)
我知道你已经得到了一个非常好的答案(实际上是多个答案),但我正在考虑这个问题,我想出了一个非常简洁的算法,我也可以分享。
基本上,您可以通过从符号列表开始,然后将每个符号附加到每个其他符号以生成两个符号字,然后将每个符号附加到每个单词。这可能没有多大意义,所以这就是它的样子:
以'a','b'和'c'作为符号开头,并将它们添加到列表中:
a
b
c
将“a”,“b”和“c”附加到列表中的每个单词。该列表看起来像:
a
b
c
aa
ab
ac
ba
bb
bc
ca
cb
cc
然后在列表中的每个新单词后附加'a','b'和'c',这样列表将如下所示:
a
b
c
aa
ab
ac
ba
bb
bc
ca
cb
cc
aaa
aab
aac
aba
abb
... and so on
您可以使用迭代器轻松完成此操作,让迭代器从一开始就继续运行。
此代码打印出添加到列表中的每个单词。
void permutations(string symbols)
{
list<string> l;
// add each symbol to the list
for (int i = 0; i < symbols.length(); i++)
{
l.push_back(symbols.substr(i, 1));
cout << symbols.substr(i, 1) << endl;
}
// infinite loop that looks at each word in the list
for (list<string>::iterator it = l.begin(); it != l.end(); it++)
{
// append each symbol to the current word and add it to the end of the list
for (int i = 0; i < symbols.length(); i++)
{
string s(*it);
s.push_back(symbols[i]);
l.push_back(s);
cout << s << endl;
}
}
}
答案 6 :(得分:0)
Python示例:
import itertools
import string
characters = string.ascii_lowercase
max_length = 3
count = 1
while count < max_length+1:
for current_tuple in itertools.product(characters, repeat=count):
current_string = "".join(current_tuple)
print current_string
count += 1
输出正是您期望得到的: a b c aa ab ac aaa aab aac aba abb abc aca acb acc baa bab ... (示例使用整个ASCII小写字符集,更改“characters = ['a','b','c']”以减小输出的大小)
答案 7 :(得分:-1)
你想要的是被称为排列。
在java中查看Permutation implementation