Несмотря на то, что тема поста относится больше не к программированию, а к математике, определение всех перестановок в массиве (неважно какого типа) может потребоваться и при работе в Интернет. Простой пример — определть все возможные названия сайтов, составленных из 3 ключевых слов. Или провести синонимизацию какого-либо участа текста, используя заданные массивы слов-синонимов. Что касается количества перестановок, то тут все просто — количество перестановок будет равно факториалу количества элементов в массиве, т.е., если у нас есть массив M, то количество перестановок k будет равно:
k = Length(M)!
для трехэлементного массива k=1*2*3=6
для четырех элементов: k=1*2*3*4=24 и т.д.
Осталось только вывести все возможные перестановки.
Чтобы продемонстрировать вариант перебора всевозможных перестановок зададимся простой целью:
Есть набор чисел: 1, 2, 3. Необходимо вывести все возможные перестановки этих чисел.
Итак на входе у нас будет массив (1,2,3).
Нам надо переставить числа так, чтобы в итоге все числа выставились в ряд: 3, 2, 1.
Для достижения поставленой цели нам потребуется:
- Вспомогательная функция определения количества перестановок (вычисления факториала числа). Хоть у нас и есть чётко заданый масси, следует учитывать будущее этого алгоритма — вывести перестановки для массивов любой длины.
- Функция получения следующей перестановки.
- Функция перемещения двух элементов в массиве.
Самое простое — то написать функцию перестановки двух элементов в массиве (первая задача на первом курсе по информатике):
procedure Swap(var a, b: byte); var c: byte; begin c := a; a := b; b := c end;
Вычисление факториала — тоже не вызовет никаких проблем и затруднений:
function Factorial(n: Word): Longint; var f: LongInt; i: Integer; begin f := 1; for i := 2 to n do f := f * i; Result:=f; end;
Теперь подумаем как составить функцию получения следующей перестановки в массиве. В каком случае можно поменять два элемента массива местами? Логично предполоить, что в нашем случае менять местами элементы необходимо до тех пор пока все предудыщие элементы в массиве не станут меньше последующих.
Попробуем реализовать сказанное в виде процедуры:
type TSingleArray = array of byte; procedure Next(var X: TSingleArray; var Yes: boolean); var i,j: byte; begin i:=High(X)-1;//начинаем с предпоследнего элемента { поиск i } while (i >= Low(X)) and (X[i] > X[i + 1]) do dec(i); if (i >= Low(X))and(i<=high(X)) then begin j:=i+1;//следующий за X[i] элемент {поискj} while (j<high(X)) and (X[j+1]>X[i]) do inc(j); Swap(X[i], X[j]);//меняем местами for j:=i+1 to (high(X)+i) div 2 do Swap(X[j], X[high(X)-j+i+1]); Yes:=true end else Yes:=false;//все перестановки завершены end;
Итак, все вспомогательные методы готовы. Осталось собрать их воедино.
Будем делать так. Передаем в функцию одномерный массив для которого необходимо вывести все перестановки, на выходе будем получать двумерный массив у которого количество элементов в первом измерении равно количеству перестановок, а во втором измерении — количеству элементов в исходном массиве.
procedure GenerateBytes(const Key: array of byte); var i,j: integer; ByteArray: TByteArray; Yes:boolean; procedure Next(var X: TSingleArray; var Yes: boolean); var i, j: byte; begin i:=High(X)-1; { поиск i } while (i >= Low(X)) and (X[i] > X[i + 1]) do dec(i); if (i >= Low(X))and(i<=high(X)) then begin j:=i+1; { поиск j } while (j<high(X)) and (X[j+1]>X[i]) do inc(j); Swap(X[i], X[j]); for j:=i+1 to (high(X)+i) div 2 do Swap(X[j], X[high(X)-j+i+1]); Yes:=true end else Yes:=false; end; begin SetLength(ByteArray, Factorial(Length(Key)));//устанавливаем размер первого измерения SetLength(ByteArray[0],length(Key));//второе измерение i:=0; repeat SetLength(ByteArray[i],length(a));//добавляем элемент во второе измерение for j:=0 to length(a)-1 do ByteArray[i,j]:=a[j];//записываем перестановку inc(i); Next(a, Yes);//ищем следующую перестановку until not Yes; end;
После завершения процедуры массив ByteArray будет содержать следующие элементы:
((1,2,3), (1,3,2), (2,1,3), (2,3,1), (3,1,2), (3,2,1))
Немного видоизменив функцию Next можно составить массив перестановок, например, для нескольких слов.
Добрый день, Vlad.
Почитал ваши статьио авторизации и постинге с использованием Synapse. Попытался сделать свое подобное, но к сожалению не вышло. Не хотите рассмотреть авторизацию и постинг в движке википедии?(там много нового кирилические урл, как то генерируются «boundary=—————————14902356128489» и пр.). Если нужно могу предоставить сайт сустановленным движоком вики. Заранее спасибо.
Ответ отправил Вам на e-mail :)
Очень вовремя нашёл ваш пост!! Как раз в универе изучаем комбинаторику и пишем всё на паскале. Есть такая не большая просьба.. вы гуру в паскале а я , так сказать нуб, был бы рад увидеть подробные посты по написанию генераций сочетаний с повторениями и без.
Это я-то гуру? :))) Очень-очень грубая лесть :)))
Раз не нравится гуру, то мастер в делфи точно ;) и у меня есть одна просьба, мы в универе проходим абстрактные типы данных, не могли бы вы про это написать пару статей? для совсем нубов, было бы очень приятно и полезно!
Доброго времени суток. Влад подскажите пожалуйста, как сделать следующее. Есть 3 массива с наборами символов. Нужно сформировать все возможные варианты по трем массивам при условии, что в комбинации должно быть определенное число символов из 1 массива определенное из 2 и определенное из третьего. А то уже всю голову сломал. Пример: 1 массив (e, t, h, y, j…) 2 массив (ук, df, as, fg, vb…) 3 массив (KLP, FGH, LPK, FBI…..) и известно что в комбинации должно быть 5 элементов из 1 массива, 2 элемента из 2 массива и 9 элементов из третьего массива, длина комбинации будет фиксированная на время всего… Подробнее »
bgmt, незнаю :) Я программист больше по хобби, чем по профессии, поэтому задачи комбинаторики изучаю по мере того как передо мной встают такие задачи. Таких случаев как описан у Вас мне не попадалось.
Мне к сожалению тоже, ну ладно будем разбираться, а есть полный исходник вашей статьи?
К сожалению после падения винта осталось только всё, что есть в блоге
while (i >= Low(X)) and (X[i] > X[i + 1]) do
dec(i);
if (i >= Low(X))and(i<=high(X)) then
Что значат символы > в условии???
Разобрался, это так сайт некорректно отображает знаки меньше и больше)))
Вижу статья старая однако же отпишусь. В приведенном примере есть несколько ошибок. Например, процедуру нельзя называть «Next» система будет думать что это оператор, часть цикла for и будет ругаться) . В последнем листинге процедуры GenerateBytes и Next — перемешены, не будет работать. Да и > и < нужно что-то делать, вижу тут во всех статьях некорректно отражаются знаки больше и меньше. SetLength(ByteArray, Factorial(Length(Key)));//устанавливаем размер первого измерения делать массив размером Key факториал это круто безусловно))) при Key =11 массив будет весить 1,2 ГБ, при Key =12 — 1,2*12…. ну и так далее…. За процедуру Next — благодарю, шедевр, до сих пор… Подробнее »