C - создание всех возможностей символьных слов X

EDIT: Я имел в виду перестановки, а не комбинации. Спасибо.

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

Не совсем уверен, где я начну, возможно, использование хеш-таблицы? Конечно, нужны петли, но я не уверен, как их проектировать для создания комбинаций. До сих пор это всегда был случай, цикл до 1000 вещей, например, произошло.

Любые советы очень ценятся!

Приветствия,

Т.

Ответ 1

Для перестановок вы можете использовать такое рекурсивное решение (которое, вероятно, может быть оптимизировано и улучшено):

unordered_set<string> permute_string(int n) {    
    static const char chars[] = {
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    };

    unordered_set<string> s;

    if (n == 0) {
        s.insert("");

        return s;
    }

    unordered_set<string> perms = permute_string(n - 1);

    for (auto c = std::begin(chars); c < std::end(chars); ++c)
        for (auto i = perms.begin(); i != perms.end(); ++i)
            for (int pos = 0; pos < n; ++pos)
                s.insert(string(*i).insert(pos, 1, *c));

    return s;
}

Обратите внимание, что выход этой функции (независимо от того, как вы ее реализуете) составляет 26 n что составляет 456 976, когда n (вход для этой функции) равен 4.

Ответ 2

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

Ответ 3

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

pick the next letter from the alphabet
  generate all N-l-length words starting with that letter    

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

Важный вопрос: уверены ли вы, что вам нужна всякая комбинация всех символов ASCII (включая знаки препинания, контрольные символы и т.д.)? Или все возможные комбинации альфаномерных строк? Или строго алфавитные строки?

Вы можете указать свой алфавит в своем коде, например

char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

и просто проиндексируйте это, вместо предположения о конкретном символьном представлении:

char *p;
for (p = alphabet; *p != 0; p++)
  // generate all words starting with *p

Ответ 4

Здесь полное и рабочее решение, которое я только что преобразовал в С++ из документации метода python itertools.permutations. http://docs.python.org/library/itertools.html#itertools.permutations. В исходной форме python это генератор (просто подумайте об итераторе), но я не стал беспокоиться об этом сейчас, хотя это будет иметь большой смысл.

Метод перестановок является шаблоном, поэтому он работает с любым объектом, который вы можете сохранить в векторе, а не только char. С помощью этого кода:

vector<char> alphab={'a','b','c','d'};
auto perms=permutations(alphab,3);'

результат представляет собой вектор "вектор", представляющий все не повторяющиеся 3-комбинации abcd:

abc abd acb acd adb adc bac bad bca bcd bda bdc
cab cad cba cbd cda cdb dab dac dba dbc dca dcb 

Здесь код (С++ 11):

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

size_t nperms(size_t n,size_t k){
   if(k<=0) return 1; // one empty set
   if(k>n) return 0;  // no possible ways
   size_t out=1;
   for (size_t i=n-k+1;i<=n;i++) out*=i;
   return out;
}

template<class T>
vector<T > permutations(T & iterable, size_t r=-1){    
   vector<T> out;
   T & pool = iterable;
   size_t n = pool.size();
   r = r>=0 ? r : n;
   if (r > n)
      return out;
   vector<size_t> indices;
   for (size_t i=0;i<n;++i) indices.push_back(i);
   vector<size_t> cycles;
   for (size_t i=n;i>(n-r);--i) cycles.push_back(i);

   vector<typename T::value_type> line; //e.g. vector of char
   line.reserve(r);

   for (size_t i=0;i<r;++i)
      line.push_back(pool[i]);
   out.reserve(nperms(n,r));    
   // first permutation:
   out.push_back(line);   
   while (1){
     bool done=1;
     for (size_t irev=0;irev<r;++irev){
       size_t i=r-1-irev;
       cycles[i] -= 1;
       if(cycles[i] == 0){
         // cycle upper part one step
         rotate(begin(indices)+i,begin(indices)+i+1,end(indices));
         cycles[i] = n-i;
       }else{
         int j = cycles[i];
         swap(indices[n-j],indices[i]);         
         for (size_t k=0;k<r;++k)
           line[k]=pool[indices[k]];
         out.push_back(line);
         done=0;
         break ;
       }
     }
     if(done) break;
   }
   return out;
}    
int main(){

   vector<char> alphab={'a','b','c','d'};
   auto perms=permutations(alphab,3);

   // print:
   cout <<"perms of size " <<perms.size()<<endl;
   for (auto &i : perms){
      for (auto &j : i){
     cout << j<<"";
      }
      cout <<" ";
   }
   cout <<endl;
   return 0;
}

Как примечание:

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