Как получить количество следующих комбинаций для данного набора? - PullRequest
3 голосов
/ 13 июня 2009
  • Я отредактировал оригинальный текст, чтобы сэкономить потенциальным читателям время и здоровье. Может быть, кто-то на самом деле будет использовать это.

Я знаю, что это основные вещи. Наверное, как очень, очень простой.
Как получить все возможные комбинации данного набора. Э.Г.
string set = "abc";
Я ожидаю получить:
a b c aa ab ac aaa aab aac aba abb abc aca acb acc baa bab ...
и этот список можно продолжить (если ограничение длины не установлено).

Я ищу очень чистый код для этого - все, что я нашел, было немного грязно и не работало правильно. То же самое я могу сказать о коде, который я написал.

Мне нужен такой код, потому что я пишу реализацию грубой силы (md5), работающую на нескольких потоках. Шаблон заключается в том, что есть родительский процесс, который подпитывает потоки частями своих собственных комбинаций, поэтому они будут работать над ними самостоятельно.
Пример: первый поток получает пакет из 100 перестановок, второй получает следующие 100 и т. Д.
Дайте мне знать, если я должен опубликовать финальную программу в любом месте.

РЕДАКТИРОВАТЬ # 2 Еще раз спасибо, ребята.
Благодаря вам, я закончил свое приложение Slave / Master Brute-Force, реализованное с MPICH2 (да, может работать под Linux и Windows, например, по сети), и так как день уже почти закончился, и я уже потратил много времени время (и солнце) я приступлю к следующему заданию ...:)
Вы показали мне, что сообщество StackOverflow потрясающее - спасибо!

Ответы [ 8 ]

7 голосов
/ 13 июня 2009

Вот некоторый код 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 );
  }
}
5 голосов
/ 13 июня 2009

C ++ имеет функцию next_permutation (), но я не думаю, что это то, что вы хотите.

Вы должны быть в состоянии сделать это довольно легко с помощью рекурсивной функции. например,

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 количество потоков) для проверки.

0 голосов
/ 14 июня 2009

пример 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']", чтобы уменьшить размер вывода)

0 голосов
/ 14 июня 2009

Я знаю, что у вас уже есть очень хороший ответ (на самом деле несколько), но я немного подумал об этой проблеме и придумал довольно аккуратный алгоритм, которым я мог бы поделиться.

По сути, вы можете сделать это, начав со списка символов, а затем добавив каждый символ к каждому символу, чтобы создать два слова символа, а затем добавив каждый символ к каждому слову. Это может не иметь особого смысла, вот как это выглядит:

Начните с символов '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;
        }
    }
}
0 голосов
/ 13 июня 2009

Вот странный и обычно не идеальный способ сделать это, но эй, он работает, и он не использует рекурсию: -)

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++;
    }
}
0 голосов
/ 13 июня 2009

Я не могу дать вам код, но вам нужен рекурсивный алгоритм, вот какой-то псевдокод

Идея проста: объединить каждую строку в вашем наборе с каждой другой строкой, а затем переставить строки. добавьте все ваши меньшие строки в ваш набор и повторите то же самое с новым набором. Продолжайте, пока не устанете:)

Может немного запутать, но немного подумать;)

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_combination любое условие, которое вам нравится (возможно, размер set?), Чтобы завершить рекурсию

0 голосов
/ 13 июня 2009

Другая версия перестановки находится в стандартной библиотеке Python, хотя вы задали вопрос на C ++.

http://docs.python.org/library/itertools.html#itertools.permutations

Но ваш список содержит бесконечную последовательность каждого символа, поэтому я думаю, что метод, который должен упорядочить их, должен быть определен в первую очередь, и четко изложить ваш алгоритм.

0 голосов
/ 13 июня 2009

То, что вы хотите, называется перестановкой.

Проверьте это для реализации перестановки в java

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...