Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: Перестановки алфавита без рекурсии. Без массивов. PHP
Форумы портала PHP.SU » » Хранение данных, их вывод и обработка » Перестановки алфавита без рекурсии. Без массивов. PHP

Страниц (1): [1]
 

1. dcc0 - 06 Сентября, 2014 - 17:05:11 - перейти к сообщению
Ребята, если кому-то будет интересна эта тема, вот мои наработки.
Пока, вроде, получилось. Правда, есть ограничение на генерируемые размещения.
Собственно, заметка о том, как превратить размещения в перестановки.

Все алгоритмы, которые я встречал в Интернете на ключевые слова "перестановки и permutations" мне показались сложными для понимания. Заодно отталкивает использование рекурсии. Работая над другим скриптом, пришел к следующему выводу.
Чтобы получить все перестановки, которые, как известно, равны факториалу n!,
сначала надо получить все размещения с повторениями. Мной был найден такой скрипт и несколько переделан, взят с hashcode, автора не помню.
Мы генерируем все размещения в данном случае 4-х элементов - abcd. Для этого используется цикл до 4 в степени 4 (все размещения с повторением). Данные преобразуются в четверичную систему, дописываются нули слева. Затем с помощью strtr преобразование в abcd. Вот, с первым скриптом все.

PHP:
скопировать код в буфер обмена
  1. <?PHP
  2. /*Cоздать файл с набором алфавита. Исходный скрипта взят с hashcode*/
  3.  $handle = fopen("f.txt", "w");
  4. $a=-1;
  5. while(++$a<256) {
  6.    $c=str_pad(base_convert($a, 10, 4), 4, "0", STR_PAD_LEFT);
  7.  $b=strtr($c, "0123", "abcd");
  8. fwrite($handle, "$b\r\n");      
  9. }
  10.  fclose($handle);
  11.  ?>
  12.  


А дальше?! Надо удалить из всех размещений каждую строку, в который символ повторяется. Второй скрипт читает из файла f.txt построчно, проверяет количество одного символа в строке и записывает в промежуточный файл только те строки, в которых символ один. Когда цикл переберет все записи на одну букву, подставит другую. Первый цикл - перебора массива - будет иметь столько итераций, сколько всего букв в алфавите, т.е. n. Иначе говоря, есть abcd - 4 буквы, у цикла перебора массива будет 4 итерации.
Промежуточные вычисления записываются в дополнительный файлы, потом файлы удаляются и переименовываются.

PHP:
скопировать код в буфер обмена
  1.  
  2. <?PHP
  3. /*Входной алфавит*/
  4.  $arr = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h');
  5.  
  6. /*Количество символов*/
  7. $n=3;
  8. /*Перебор. Сброс на последнем символе*/
  9. foreach($arr as $k => $v) {
  10.     if($k==$n) {
  11.   break;
  12.  }
  13.  $handle = fopen("f.txt", "r");
  14.     $handl1 = fopen("f1.txt", "w");
  15.  /*Читаем из файла по строчно*/        
  16. while (!feof($handle)) {
  17.   $buffer = fgets($handle);
  18.  
  19.    /*Если символ встречается 1 раз пишем в другой файл. Переменная - шаблон
  20.    подставляется из цикла сверху*/     
  21. $c = preg_match_all("/$v{1}/",  $buffer, $out);
  22. if($c==1) {
  23. fwrite($handl1, "$buffer");
  24.  }
  25. }
  26.  fclose($handle);
  27. fclose($handl1);
  28. /*Переименовываем все файлы, удалем промежуточные*/
  29.  rename("f.txt", "old1_f.txt");
  30.   unlink ("old1_f.txt");
  31. rename("f1.txt", "f.txt");
  32. }
  33. $c=file('f.txt');
  34. print_r($c);
  35. ?>
  36.  
2. dcc0 - 07 Сентября, 2014 - 19:35:06 - перейти к сообщению
Еще такой вариант получения перестановок, полуавтоматический. Не знаю, где может пригодиться. Идея такая: можно генерировать любой набор букв рандомно.
Например, при помощи скрипта из этой статьи: http://www.php.su/articles/?cat=...les&page=052
Писать этот набор в файл, другим скриптом отсеивать все строчки, в которых 1 буква встречается более одного раза, а затем применять arrar_unique для поиска уникальных.

Таким образом поиск будет постепенным.

Спойлер (Отобразить)


Спойлер (Отобразить)
3. nkl - 08 Сентября, 2014 - 10:40:31 - перейти к сообщению
Это для чего вообще? Не понял
4. Tyoma5891 - 08 Сентября, 2014 - 11:02:33 - перейти к сообщению
nkl пишет:
Это для чего вообще? Не понял

у меня такое подозрение, для побора паролей, но для этого достаточно тупого перебора методом +1 )
5. dcc0 - 08 Сентября, 2014 - 11:09:13 - перейти к сообщению
nkl, практического применения пока не вижу, но интересны способы получения всех перестановок алфавита, например, abcd или ab02 или a+?& и т.д.

Наиболее оптимальным считается рекурсивный алгоритм.
Пример 1:
http://stackoverflow[dot]com/questio[dot][dot][dot]tations-in-a-set
Пример 2: http://tvolf[dot]blogspot[dot]ru/2013/09/php[dot]html
С хорошим объяснением.
Но для понимания довольно сложен (мое мнение). Рекурсивный будет работать с символами до 10, потом просто не хватит памяти (хотя тут зависит от машины и настроек).

Второй вариант без рекурсии, где сначала надо найти все размещения с повторениями, сгенерирует до 7 включительно, так как понятно разм. с повторениями намного больше.
Пример, если всех перестановок семи элементов abcdefg - 7! = 5040, то размещений 7⁷ = 823543. Т.е. вариант долгий и нудный, но он есть.

Вариант третий можно автоматизировать, он совсем долгий (почти бесконечный Улыбка) Один скрипт генерирует n-ое количество случайных выборок и сохраняет в файл, другой скрипт забирает результат удаляет то - что не попадает под перестановку, например aaabc, потом удаляет повторы, опять же можно сохранять в другой файл, который будет базой

Третий скрипт находит все перестановки 4 эл. за 100 рекурсивных вызовов.
(Добавление)
Tyoma5891 пишет:

у меня такое подозрение, для побора паролей, но для этого достаточно тупого перебора методом +1 )

Причем тут перестановки и перебор? При перестановках вы не получаете перебора всех значений.
Третий вариант интересен тем, что последовательность перестановок будет случайной.

 

Powered by ExBB FM 1.0 RC1