Реализации алгоритмов/Алгоритм Нарайаны: различия между версиями
Содержимое удалено Содержимое добавлено
Нет описания правки |
Добавлено описание алгоритма; усовершенствована реализация на Pascal, добавлен пример использования |
||
Строка 2:
'''Алгори́тм Нарайа́ны''' — нерекурсивный алгоритм, генерирующий по данной [[w:Перестановка|перестановке]] следующую за ней в [[w:Лексикографический порядок|лексикографическом порядке]] перестановку.
=Алгоритм=
Пусть <math>sequence</math> — последовательность из <math>count</math> элементов, для которых требуется найти очередную в лексикографическом порядке перестановку.
Алгоритм поиска очередной перестановки для последовательности с неубывающим (невозрастающим) '''изначальным''' порядком элементов:
# Найти наибольшее <math>i</math>, для которого выполняется условие <math>sequence_{i} < sequence_{i+1}</math> (<math>sequence_{i} > sequence_{i+1}</math>). Если такого нет, значит все перестановки были сгенерированы.
# Найти наибольшее <math>j</math>, для которого выполняется условие <math>sequence_{i} < sequence_{j}</math> (<math>sequence_{i} > sequence_{j}</math>). Затем поменять местами <math>sequence_{i}</math> и <math>sequence_{j}</math>.
# Записать последовательность <math>sequence_{i+1},...,sequence_{count}</math> в обратном порядке.
=Реализации=
В нижеприведённых реализациях <code>sequence</code> — последовательность из <code>count</code> элементов, в которой производятся перестановки (как правило — массив из count элементов), <code>compare(x, y)</code> — функция, которая должна возвращать <code>true</code> если x < y и <code>false</code> иначе (если исходный порядок элементов последовательности неубывающий; для невозрастающего исходного порядка условие меняется на x > y).
Если не оговорено другое, то функция поиска очередной перестановки возвращает ненулевое значение, если перестановка найдена, либо 0, если следующей перестановки не существует (перебор закончен).
==[[w:C (язык программирования)|C]]/[[w:C++|C++]]==
'''C:''' Тип <code>T</code> должен быть предварительно определён как:
<source lang="cpp">
typedef int T; /* Вместо int можно подставить любой тип */
</source>
'''C++:''' Обе функции следует предварить строкой:
<source lang="cpp">
template < typename T >
</source>
Собственно реализация:
<source lang="cpp">
void swapItems (T *sequence, unsigned index_1, unsigned index_2) {
T _ = sequence[index_1];
sequence[index_1] = sequence[index_2];
sequence[index_2] = _;
}
int nextPermutation (T *
int i, j, l;
/*
for (j =
/*
if (j == -1)
return 0;
for (l =
swapItems(
++j;
/*
for (i = 0; i < (
swapItems(
return j;
}
Строка 33 ⟶ 53 :
==[[w:Паскаль (язык программирования)|Pascal]]==
<source lang="pascal">
type T = Integer; { Вместо Integer можно использовать любой тип }
{ Функция, задающая отношение порядка для значений типа T (< либо >) }
TPredicate2 = function (const value_0, value_1: T): Boolean;
function NextPermutation (var
var
{ Обмен значениями двух элементов последовательности }
procedure SwapItems (index_1, index_2: Word);
var _: T; { _ — временная переменная }
begin
end;
begin
count := Length(sequence);
i := count;
if
begin
end;
until Compare(sequence[i - 1], sequence[i]);
{ Этап № 2 }
j := count;
while (j > i) and not Compare(sequence[i - 1], sequence[j - 1]) do
j := j - 1;
i := i - 1;
SwapItems(i, j - 1);
{ Этап № 3 }
for j := i + 1 to (count + i) shr 1 do { shr 1 — более быстрый вариант div 2 }
SwapItems(j, count + i - j);
NextPermutation := j
end;
</source>
Пример использования:
<source lang="pascal">
{ Возвращает true, если value_0 меньше value_1, иначе — false }
function Less (const value_0, value_1: T): Boolean;
begin
Less := value_0 < value_1
end;
{ Возвращает true, если value_0 больше value_1, иначе — false }
function Greater (const value_0, value_1: T): Boolean;
begin
Greater := value_0 > value_1
end;
procedure InitSequence (var sequence: array of T);
var i: Word;
begin
{ Заполнение последовательности значениями 1, 2, 3… }
for i := Length(sequence) downTo 1 do
sequence[i - 1] := i;
end;
{ Выводит содержимое последовательности }
procedure OutputSequence (sequence: array of T);
var i, count: Word;
begin
Write('[');
count := Length(sequence);
if count > 0 then { Если последовательность не пуста }
begin
Write(sequence[0]);
for i := 1 to count - 1 do
Write(' ', sequence[i])
end;
WriteLn(']')
end;
BEGIN
InitSequence(sequence); { Формирование исходной последовательности }
WriteLn('Неубывающая последовательность и её перестановки:');
repeat
OutputSequence(sequence)
until NextPermutation(sequence, @Less) = 0; { x < y — критерий сравнения для неубывающей последовательности }
WriteLn;
WriteLn('Невозрастающая последовательность и её перестановки:');
repeat
OutputSequence(sequence)
until NextPermutation(sequence, @Greater) = 0 { x > y — критерий сравнения для невозрастающей последовательности }
END.
</source>
Строка 72 ⟶ 146 :
===Вариант № 1===
<source lang="PHP">
function nextPermutation ($
$out = $
//
$k = $
while ($k >= 0 && $out[$k] >= $out[$k + 1]) {
--$k;
Строка 82 ⟶ 156 :
return false;
}
//
$t = $
while ($t >= 0 && $t >= $k + 1 && $out[$k] >= $out[$t]) {
--$t;
Строка 90 ⟶ 164 :
$out[$k] = $out[$t];
$out[$t] = $tmp;
//
for ($i = $k + 1; $i < ceil(($
$t = $
$tmp = $out[$i];
$out[$i] = $out[$t];
|