Реализации алгоритмов/Алгоритм Нарайаны: различия между версиями
Поправки к коду реализации на C |
Добавлены реализации на VB.NET, Python и примеры их использования; скорректировано оформление программ на других языках |
||
Строка 11: | Строка 11: | ||
=Реализации= |
=Реализации= |
||
В нижеприведённых реализациях <code>sequence</code> — последовательность из <code>count</code> элементов, в которой производятся перестановки (как правило — массив из count элементов), <code>compare(x, y)</code> — функция, которая должна возвращать |
В нижеприведённых реализациях <code>sequence</code> — последовательность из <code>count</code> элементов, в которой производятся перестановки (как правило — массив из count элементов), <code>compare(x, y)</code> — функция, которая должна возвращать значение «истина» если x < y и «ложь» иначе (если исходный порядок элементов последовательности неубывающий; для невозрастающего исходного порядка условие меняется на x > y). |
||
Если не оговорено другое, то функция поиска очередной перестановки возвращает значение «истина», если перестановка найдена, либо «ложь», если следующей перестановки не существует (перебор закончен). |
Если не оговорено другое, то функция поиска очередной перестановки возвращает значение «истина», если перестановка найдена, либо «ложь», если следующей перестановки не существует (перебор закончен). |
||
==[[w:Бейсик|BASIC]]== |
|||
===[[w:Visual_Basic_.NET|VB.NET]]=== |
|||
<source lang="vb"> |
|||
' Narayana.vb |
|||
Module Narayana |
|||
''' <summary> |
|||
''' Функция, задающая отношение порядка для значений типа T: < либо > |
|||
''' </summary> |
|||
Public Delegate Function Predicate2 (Of T)(ByVal value_0 As T, ByVal value_1 As T) As Boolean |
|||
''' <summary> |
|||
''' Поиск очередной перестановки |
|||
''' </summary> |
|||
Public Function NextPermutation (Of T)(ByRef sequence As T(), compare As Predicate2(Of T)) As Boolean |
|||
' Этап № 1 |
|||
Dim i As Integer = sequence.Length |
|||
Do |
|||
If i < 2 Then Return False ' Перебор закончен |
|||
i -= 1 |
|||
Loop Until compare(sequence(i - 1), sequence(i)) |
|||
' Этап № 2 |
|||
Dim j As Integer = sequence.Length |
|||
Do While i < j And Not compare(sequence(i - 1), sequence(j - 1)) |
|||
j -= 1 |
|||
Loop |
|||
_SwapItems(Of T)(sequence, i - 1, j - 1) |
|||
' Этап № 3 |
|||
j = sequence.Length |
|||
Do While i < j And i < j - 1 |
|||
j -= 1 |
|||
_SwapItems(Of T)(sequence, i, j) |
|||
i += 1 |
|||
Loop |
|||
Return True |
|||
End Function |
|||
''' <summary> |
|||
''' Обмен значениями двух элементов последовательности |
|||
''' </summary> |
|||
Private Sub _SwapItems (Of T)(ByRef sequence As T(), ByVal index_0 As Integer, ByVal index_1 As Integer) |
|||
Dim item As T = sequence(index_0) |
|||
sequence(index_0) = sequence(index_1) |
|||
sequence(index_1) = item |
|||
End Sub |
|||
End Module |
|||
</source> |
|||
Пример использования: |
|||
<source lang="vb"> |
|||
' NarayanaTest.vb |
|||
Module NarayanaTest |
|||
''' <summary> |
|||
''' Возвращает True, если value_0 меньше value_1, иначе — False |
|||
''' </summary> |
|||
Function Less (Of T As IComparable)(ByVal value_0 As Integer, ByVal value_1 As Integer) As Boolean |
|||
Return value_0.CompareTo(value_1) < 0 |
|||
End Function |
|||
''' <summary> |
|||
''' Возвращает True, если value_0 больше value_1, иначе — False |
|||
''' </summary> |
|||
Function Greater (Of T As IComparable)(ByVal value_0 As Integer, ByVal value_1 As Integer) As Boolean |
|||
Return value_0.CompareTo(value_1) > 0 |
|||
End Function |
|||
''' <summary> |
|||
''' Инициализация последовательности |
|||
''' </summary> |
|||
Sub InitSequence (ByRef sequence As Integer()) |
|||
For i As Integer = sequence.Length To 1 Step -1 |
|||
sequence(i - 1) = i |
|||
Next |
|||
End Sub |
|||
''' <summary> |
|||
''' Вывод содержимого последовательности |
|||
''' </summary> |
|||
Sub OutputSequence (Of T)(ByVal sequence As T()) |
|||
Console.Write("["C) |
|||
If sequence IsNot Nothing And sequence.Length > 0 Then |
|||
Console.Write(sequence(0)) |
|||
For i As Integer = 1 To sequence.GetUpperBound(0) |
|||
Console.Write(", ") |
|||
Console.Write(sequence(i)) |
|||
Next |
|||
End If |
|||
Console.WriteLine("]"C) |
|||
End Sub |
|||
''' <summary> |
|||
''' Основная программа |
|||
''' </summary> |
|||
Public Sub Main () |
|||
Dim count As Integer = Integer.Parse(Console.ReadLine()) |
|||
Dim sequence(count - 1) As Integer |
|||
InitSequence(Of Integer)(sequence) |
|||
Console.WriteLine("Неубывающая последовательность и её перестановки:") |
|||
Do |
|||
OutputSequence(Of Integer)(sequence) |
|||
Loop While Narayana.NextPermutation(Of Integer)(sequence, AddressOf Less(Of Integer)) |
|||
Console.WriteLine("Невозрастающая последовательность и её перестановки:") |
|||
Do |
|||
OutputSequence(Of Integer)(sequence) |
|||
Loop While Narayana.NextPermutation(sequence, AddressOf Greater(Of Integer)) |
|||
End Sub |
|||
End Module |
|||
</source> |
|||
==[[w:C (язык программирования)|C]]== |
==[[w:C (язык программирования)|C]]== |
||
Строка 22: | Строка 129: | ||
/* Обмен значениями двух элементов последовательности */ |
/* Обмен значениями двух элементов последовательности */ |
||
static void _swapItems (T *sequence, unsigned index_1, unsigned index_2); |
static void _swapItems (T *sequence, unsigned index_1, unsigned index_2); |
||
/* Поиск очередной перестановки */ |
/* Поиск очередной перестановки */ |
||
unsigned nextPermutation (T *sequence, unsigned const count, int (*compare)(T const, T const)); |
unsigned nextPermutation (T *sequence, unsigned const count, int (*compare)(T const, T const)); |
||
Строка 32: | Строка 140: | ||
/* Обмен значениями двух элементов последовательности */ |
/* Обмен значениями двух элементов последовательности */ |
||
static void _swapItems (T *sequence, unsigned index_1, unsigned index_2) { |
static void _swapItems (T *sequence, unsigned index_1, unsigned index_2) { |
||
T |
T item = sequence[index_1]; |
||
sequence[index_1] = sequence[index_2]; |
sequence[index_1] = sequence[index_2]; |
||
sequence[index_2] = |
sequence[index_2] = item; |
||
} |
} |
||
/* Поиск очередной перестановки */ |
/* Поиск очередной перестановки */ |
||
unsigned nextPermutation (T *sequence, unsigned count, int (*compare)(T const, T const)) { |
unsigned nextPermutation (T *sequence, unsigned count, int (*compare)(T const, T const)) { |
||
Строка 94: | Строка 203: | ||
} |
} |
||
/* Основная программа */ |
|||
int main () { |
int main () { |
||
unsigned count; |
unsigned count; |
||
Строка 103: | Строка 213: | ||
outputSequence(sequence, count); |
outputSequence(sequence, count); |
||
} while (nextPermutation(sequence, count, &less)); /* x < y — критерий сравнения для неубывающей последовательности */ |
} while (nextPermutation(sequence, count, &less)); /* x < y — критерий сравнения для неубывающей последовательности */ |
||
putchar('\n'); |
|||
printf("Невозрастающая последовательность и её перестановки:\n"); |
printf("Невозрастающая последовательность и её перестановки:\n"); |
||
do { |
do { |
||
Строка 114: | Строка 223: | ||
==[[w:C++|C++]]== |
==[[w:C++|C++]]== |
||
На основе итераторов. В качестве последовательности могут выступать не только массивы, но и другие контейнеры, поддерживающие последовательный доступ, например, списки. |
|||
На основе итераторов. |
|||
<source lang="cpp"> |
<source lang="cpp"> |
||
// narayana.hpp |
// narayana.hpp |
||
Строка 125: | Строка 234: | ||
variable_1 = variable; |
variable_1 = variable; |
||
} |
} |
||
// Поиск очередной перестановки |
// Поиск очередной перестановки |
||
template < typename Iterator, typename T > |
template < typename Iterator, typename T > |
||
bool nextPermutation (Iterator const begin, Iterator const end, bool (*compare)(T const, T const)) { |
bool nextPermutation (Iterator const begin, Iterator const end, bool (*compare)(T const, T const)) { |
||
if (begin == end) // Если последовательность не содержит элементов |
if (begin == end) // Если последовательность не содержит элементов |
||
return false; |
return false; // Нечего перебирать |
||
// Этап № 1 |
// Этап № 1 |
||
Iterator i = end - 1, j = end; |
Iterator i = end - 1, j = end; |
||
do { |
do { |
||
if (i == begin) |
if (i == begin) |
||
return false; |
return false; // Перебор закончен |
||
} while (!(*compare)(*--i, *--j)); |
} while (!(*compare)(*--i, *--j)); |
||
// Этап № 2 |
// Этап № 2 |
||
Строка 163: | Строка 273: | ||
return value_0 < value_1; |
return value_0 < value_1; |
||
} |
} |
||
// Возвращает true, если value_0 больше value_1, иначе — false |
// Возвращает true, если value_0 больше value_1, иначе — false |
||
template < typename T > |
template < typename T > |
||
Строка 169: | Строка 280: | ||
} |
} |
||
// Инициализация последовательности |
|||
template < typename Iterator > |
|||
void initSequence (Iterator const begin, Iterator const end) { |
|||
int i = 0; |
|||
for (Iterator current = begin; current != end; ++current) |
|||
*current = ++i; |
|||
} |
|||
// Вывод содержимого последовательности |
|||
template < typename Iterator > |
template < typename Iterator > |
||
void outputSequence (Iterator const begin, Iterator const end) { |
void outputSequence (Iterator const begin, Iterator const end) { |
||
Строка 178: | Строка 298: | ||
} |
} |
||
(std::cout << ']') << '\n'; |
(std::cout << ']') << '\n'; |
||
} |
|||
template < typename Iterator > |
|||
void initSequence (Iterator const begin, Iterator const end) { |
|||
int i = 0; |
|||
for (Iterator current = begin; current != end; ++current) |
|||
*current = ++i; |
|||
} |
} |
||
Строка 209: | Строка 322: | ||
// Narayana.java |
// Narayana.java |
||
abstract class Narayana { |
abstract class Narayana { |
||
// Функция, задающая отношение порядка для значений типа T: < либо > |
|||
@FunctionalInterface |
@FunctionalInterface |
||
interface Predicate2<T extends Comparable> { |
interface Predicate2 <T extends Comparable> { |
||
boolean compare (final T value_0, final T value_1); |
boolean compare (final T value_0, final T value_1); |
||
} |
|||
// Обмен значениями двух элементов последовательности |
|||
static final private <T> void _swapItems (T[] sequence, int index_0, int index_1) { |
|||
T temp = sequence[index_0]; |
|||
sequence[index_0] = sequence[index_1]; |
|||
sequence[index_1] = temp; |
|||
} |
} |
||
// Поиск очередной перестановки |
|||
static final public <T extends Comparable> boolean nextPermutation (T[] sequence, Predicate2 comparator) { |
|||
public static final <T extends Comparable> boolean nextPermutation (T[] sequence, Predicate2 comparator) { |
|||
// Этап № 1 |
// Этап № 1 |
||
int |
int i = sequence.length; |
||
do { |
do { |
||
if ( |
if (i < 2) |
||
return false; |
return false; // Перебор закончен |
||
} while (!comparator.compare(sequence[ |
--i; |
||
} while (!comparator.compare(sequence[i - 1], sequence[i])); |
|||
// Этап № 2 |
// Этап № 2 |
||
j = sequence.length; |
int j = sequence.length; |
||
while (i < j && !comparator.compare(sequence[i], sequence[--j])); |
while (i < j && !comparator.compare(sequence[i - 1], sequence[--j])); |
||
_swapItems(sequence, i, j); |
_swapItems(sequence, i - 1, j); |
||
// Этап № 3 |
// Этап № 3 |
||
j = sequence.length; |
j = sequence.length; |
||
while ( |
while (i < j && i < --j) |
||
_swapItems(sequence, i, j); |
_swapItems(sequence, i++, j); |
||
return true; |
return true; |
||
} |
|||
// Обмен значениями двух элементов последовательности |
|||
private static final <T> void _swapItems (T[] sequence, int index_0, int index_1) { |
|||
T temp = sequence[index_0]; |
|||
sequence[index_0] = sequence[index_1]; |
|||
sequence[index_1] = temp; |
|||
} |
} |
||
} |
} |
||
Строка 252: | Строка 368: | ||
return value_0.compareTo(value_1) < 0; |
return value_0.compareTo(value_1) < 0; |
||
} |
} |
||
// Возвращает true, если value_0 больше value_1, иначе — false |
// Возвращает true, если value_0 больше value_1, иначе — false |
||
static final <T extends Comparable> boolean greater (final T value_0, final T value_1) { |
static final <T extends Comparable> boolean greater (final T value_0, final T value_1) { |
||
return value_0.compareTo(value_1) > 0; |
return value_0.compareTo(value_1) > 0; |
||
} |
} |
||
// Инициализация последовательности |
// Инициализация последовательности |
||
static final void initSequence (Integer[] sequence) { |
static final void initSequence (Integer[] sequence) { |
||
Строка 261: | Строка 379: | ||
sequence[value - 1] = value; |
sequence[value - 1] = value; |
||
} |
} |
||
// Основная программа |
// Основная программа |
||
public static void main (String[] args) { |
public static void main (String[] args) { |
||
Строка 291: | Строка 410: | ||
{ Поиск очередной перестановки } |
{ Поиск очередной перестановки } |
||
function NextPermutation (var sequence: array of T; Compare: TPredicate2): |
function NextPermutation (var sequence: array of T; Compare: TPredicate2): Boolean; |
||
IMPLEMENTATION |
IMPLEMENTATION |
||
Строка 300: | Строка 419: | ||
{ Обмен значениями двух элементов последовательности } |
{ Обмен значениями двух элементов последовательности } |
||
procedure SwapItems (index_1, index_2: Word); |
procedure SwapItems (index_1, index_2: Word); |
||
var |
var item: T; |
||
begin |
begin |
||
item := sequence[index_1]; |
|||
sequence[index_1] := sequence[index_2]; |
sequence[index_1] := sequence[index_2]; |
||
sequence[index_2] := |
sequence[index_2] := item |
||
end; |
end; |
||
begin |
begin |
||
Строка 315: | Строка 434: | ||
NextPermutation := false; |
NextPermutation := false; |
||
Exit |
Exit |
||
{ Перебор закончен } |
|||
end; |
end; |
||
i := i - 1 |
i := i - 1 |
||
Строка 322: | Строка 442: | ||
while (j > i) and not Compare(sequence[i - 1], sequence[j - 1]) do |
while (j > i) and not Compare(sequence[i - 1], sequence[j - 1]) do |
||
j := j - 1; |
j := j - 1; |
||
i |
SwapItems(i - 1, j - 1); |
||
SwapItems(i, j - 1); |
|||
{ Этап № 3 } |
{ Этап № 3 } |
||
j := count; |
|||
for j := i + 1 to (count + i) shr 1 do { shr 1 — более быстрый вариант div 2 } |
|||
while (i < j) and (i < j - 1) do |
|||
begin |
|||
j := j - 1; |
|||
SwapItems(i, j); |
|||
i := i + 1 |
|||
end; |
|||
NextPermutation := true |
NextPermutation := true |
||
end; |
end; |
||
Строка 339: | Строка 463: | ||
var sequence: array of T; |
|||
var sequence: array [0..3] of T; { Последовательность. Границы индексов могут быть и другими } |
|||
count: Word; |
|||
{ Возвращает true, если value_0 меньше value_1, иначе — false } |
{ Возвращает true, если value_0 меньше value_1, иначе — false } |
||
Строка 379: | Строка 504: | ||
{ Основная программа } |
{ Основная программа } |
||
BEGIN |
BEGIN |
||
ReadLn(count); |
|||
SetLength(sequence, count); |
|||
InitSequence(sequence); { Формирование исходной последовательности } |
InitSequence(sequence); { Формирование исходной последовательности } |
||
WriteLn('Неубывающая последовательность и её перестановки:'); |
WriteLn('Неубывающая последовательность и её перестановки:'); |
||
Строка 384: | Строка 511: | ||
OutputSequence(sequence) |
OutputSequence(sequence) |
||
until not NextPermutation(sequence, @Less); { x < y — критерий сравнения для неубывающей последовательности } |
until not NextPermutation(sequence, @Less); { x < y — критерий сравнения для неубывающей последовательности } |
||
WriteLn; |
|||
WriteLn('Невозрастающая последовательность и её перестановки:'); |
WriteLn('Невозрастающая последовательность и её перестановки:'); |
||
repeat |
repeat |
||
Строка 403: | Строка 529: | ||
} |
} |
||
if (-1 == $k) { |
if (-1 == $k) { |
||
return false; |
return false; // Перебор закончен |
||
} |
} |
||
// Этап № 2 |
// Этап № 2 |
||
Строка 451: | Строка 577: | ||
print ‘<br/>’; |
print ‘<br/>’; |
||
} |
} |
||
</source> |
|||
==[[w:Python|Python]]== |
|||
<source lang="python"> |
|||
# narayana.py |
|||
"""Поиск очередной перестановки""" |
|||
def next_permutation (sequence, compare): |
|||
count = len(sequence) |
|||
i = count |
|||
# Этап № 1 |
|||
while True: |
|||
if i < 2: |
|||
return False # Перебор закончен |
|||
i -= 1; |
|||
if compare(sequence[i - 1], sequence[i]): |
|||
break |
|||
# Этап № 2 |
|||
j = count |
|||
while j > i and not compare(sequence[i - 1], sequence[j - 1]): |
|||
j -= 1 |
|||
sequence[i - 1], sequence[j - 1] = sequence[j - 1], sequence[i - 1] |
|||
# Этап № 3 |
|||
j = count |
|||
while i < j and i < j - 1: |
|||
j -= 1 |
|||
sequence[i], sequence[j] = sequence[j], sequence[i] |
|||
i += 1 |
|||
return True |
|||
</source> |
|||
Пример использования на Python 3.x (в Python 2.x надо убрать скобки в операторах <code>print</code>): |
|||
<source lang="python"> |
|||
# narayana_test.py |
|||
import narayana |
|||
"""Возвращает True, если value_0 меньше value_1, иначе — False""" |
|||
def less (value_0, value_1): |
|||
return value_0 < value_1 |
|||
"""Возвращает True, если value_0 больше value_1, иначе — False""" |
|||
def greater (value_0, value_1): |
|||
return value_0 > value_1 |
|||
# Основная программа |
|||
count = int(input()); |
|||
sequence = list(range(1, count + 1)) # Формирование исходной последовательности |
|||
print("Неубывающая последовательность и её перестановки:") |
|||
while True: |
|||
print(sequence) |
|||
if not narayana.next_permutation(sequence, less): # x < y — критерий сравнения для неубывающей последовательности |
|||
break |
|||
print("Невозрастающая последовательность и её перестановки:") |
|||
while True: |
|||
print(sequence) |
|||
if not narayana.next_permutation(sequence, greater): # x > y — критерий сравнения для невозрастающей последовательности |
|||
break |
|||
</source> |
</source> |
||
Строка 461: | Строка 643: | ||
let mut i = count; |
let mut i = count; |
||
// Этап № 1 |
// Этап № 1 |
||
while { |
|||
if i < 2 { |
if i < 2 { |
||
return false; |
return false; // Перебор закончен |
||
} |
} |
||
i -= 1; |
i -= 1; |
||
!compare(sequence[i - 1], sequence[i]) |
|||
} { } // Пустое тело цикла (имитация цикла с постусловием) |
|||
break; |
|||
} |
|||
} |
|||
// Этап № 2 |
// Этап № 2 |
||
let mut j = count; |
let mut j = count; |
||
Строка 475: | Строка 655: | ||
j -= 1; |
j -= 1; |
||
} |
} |
||
i - |
sequence.swap(i - 1, j - 1); |
||
sequence.swap(i, j - 1); |
|||
// Этап № 3 |
// Этап № 3 |
||
j = |
j = count; |
||
while |
while i < j && i < j - 1 { |
||
j -= 1; |
|||
sequence.swap(i, j); |
|||
i += 1; |
|||
} |
} |
||
true |
true |
||
Строка 493: | Строка 673: | ||
value_0 < value_1 |
value_0 < value_1 |
||
} |
} |
||
// Возвращает true, если value_0 больше value_1, иначе — false |
// Возвращает true, если value_0 больше value_1, иначе — false |
||
fn greater <T: PartialOrd> (value_0: T, value_1: T) -> bool { |
fn greater <T: PartialOrd> (value_0: T, value_1: T) -> bool { |
||
value_0 > value_1 |
value_0 > value_1 |
||
} |
} |
||
// Инициализация последовательности |
// Инициализация последовательности |
||
fn init_sequence (sequence: &mut [usize]) { |
fn init_sequence (sequence: &mut [usize]) { |
||
Строка 506: | Строка 688: | ||
} |
} |
||
} |
} |
||
// Функция для ввода данных |
|||
fn read_var <Type: std::str::FromStr> (var: &mut Type) -> bool { |
|||
let mut input_text = String::new(); |
|||
std::io::stdin() |
|||
.read_line(&mut input_text) |
|||
.expect("failed to read from stdin"); |
|||
match input_text.trim().parse::<Type>() { |
|||
Ok(value) => { *var = value; true }, |
|||
Err(..) => { false } |
|||
} |
|||
} |
|||
// Основная программа |
// Основная программа |
||
fn main () { |
fn main () { |
||
let mut count = 0usize; |
|||
let mut sequence = [0usize; 4]; // Длина последовательности - 4. Может быть и любой другой |
|||
read_var(&mut count); |
|||
let mut sequence = vec![0usize; count]; |
|||
init_sequence(&mut sequence); // Формирование исходной последовательности |
init_sequence(&mut sequence); // Формирование исходной последовательности |
||
println!("Неубывающая последовательность и её перестановки:"); |
println!("Неубывающая последовательность и её перестановки:"); |
||
Строка 515: | Строка 712: | ||
narayana::next_permutation(&mut sequence, less::<usize>) // x < y — критерий сравнения для неубывающей последовательности |
narayana::next_permutation(&mut sequence, less::<usize>) // x < y — критерий сравнения для неубывающей последовательности |
||
} { } |
} { } |
||
println!(""); |
|||
println!("Невозрастающая последовательность и её перестановки:"); |
println!("Невозрастающая последовательность и её перестановки:"); |
||
while { |
while { |
Версия от 11:37, 27 мая 2017
Алгори́тм Нарайа́ны — нерекурсивный алгоритм, генерирующий по данной перестановке следующую за ней в лексикографическом порядке перестановку.
Алгоритм
Пусть — последовательность из элементов, для которых требуется найти очередную в лексикографическом порядке перестановку.
Алгоритм поиска очередной перестановки для последовательности с неубывающим (невозрастающим) изначальным порядком элементов:
- Найти наибольшее , для которого выполняется условие (). Если такого нет, значит все перестановки были сгенерированы.
- Найти наибольшее , для которого выполняется условие (). Затем поменять местами и .
- Элементы переставить в обратном порядке.
Реализации
В нижеприведённых реализациях sequence
— последовательность из count
элементов, в которой производятся перестановки (как правило — массив из count элементов), compare(x, y)
— функция, которая должна возвращать значение «истина» если x < y и «ложь» иначе (если исходный порядок элементов последовательности неубывающий; для невозрастающего исходного порядка условие меняется на x > y).
Если не оговорено другое, то функция поиска очередной перестановки возвращает значение «истина», если перестановка найдена, либо «ложь», если следующей перестановки не существует (перебор закончен).
BASIC
VB.NET
' Narayana.vb
Module Narayana
''' <summary>
''' Функция, задающая отношение порядка для значений типа T: < либо >
''' </summary>
Public Delegate Function Predicate2 (Of T)(ByVal value_0 As T, ByVal value_1 As T) As Boolean
''' <summary>
''' Поиск очередной перестановки
''' </summary>
Public Function NextPermutation (Of T)(ByRef sequence As T(), compare As Predicate2(Of T)) As Boolean
' Этап № 1
Dim i As Integer = sequence.Length
Do
If i < 2 Then Return False ' Перебор закончен
i -= 1
Loop Until compare(sequence(i - 1), sequence(i))
' Этап № 2
Dim j As Integer = sequence.Length
Do While i < j And Not compare(sequence(i - 1), sequence(j - 1))
j -= 1
Loop
_SwapItems(Of T)(sequence, i - 1, j - 1)
' Этап № 3
j = sequence.Length
Do While i < j And i < j - 1
j -= 1
_SwapItems(Of T)(sequence, i, j)
i += 1
Loop
Return True
End Function
''' <summary>
''' Обмен значениями двух элементов последовательности
''' </summary>
Private Sub _SwapItems (Of T)(ByRef sequence As T(), ByVal index_0 As Integer, ByVal index_1 As Integer)
Dim item As T = sequence(index_0)
sequence(index_0) = sequence(index_1)
sequence(index_1) = item
End Sub
End Module
Пример использования:
' NarayanaTest.vb
Module NarayanaTest
''' <summary>
''' Возвращает True, если value_0 меньше value_1, иначе — False
''' </summary>
Function Less (Of T As IComparable)(ByVal value_0 As Integer, ByVal value_1 As Integer) As Boolean
Return value_0.CompareTo(value_1) < 0
End Function
''' <summary>
''' Возвращает True, если value_0 больше value_1, иначе — False
''' </summary>
Function Greater (Of T As IComparable)(ByVal value_0 As Integer, ByVal value_1 As Integer) As Boolean
Return value_0.CompareTo(value_1) > 0
End Function
''' <summary>
''' Инициализация последовательности
''' </summary>
Sub InitSequence (ByRef sequence As Integer())
For i As Integer = sequence.Length To 1 Step -1
sequence(i - 1) = i
Next
End Sub
''' <summary>
''' Вывод содержимого последовательности
''' </summary>
Sub OutputSequence (Of T)(ByVal sequence As T())
Console.Write("["C)
If sequence IsNot Nothing And sequence.Length > 0 Then
Console.Write(sequence(0))
For i As Integer = 1 To sequence.GetUpperBound(0)
Console.Write(", ")
Console.Write(sequence(i))
Next
End If
Console.WriteLine("]"C)
End Sub
''' <summary>
''' Основная программа
''' </summary>
Public Sub Main ()
Dim count As Integer = Integer.Parse(Console.ReadLine())
Dim sequence(count - 1) As Integer
InitSequence(Of Integer)(sequence)
Console.WriteLine("Неубывающая последовательность и её перестановки:")
Do
OutputSequence(Of Integer)(sequence)
Loop While Narayana.NextPermutation(Of Integer)(sequence, AddressOf Less(Of Integer))
Console.WriteLine("Невозрастающая последовательность и её перестановки:")
Do
OutputSequence(Of Integer)(sequence)
Loop While Narayana.NextPermutation(sequence, AddressOf Greater(Of Integer))
End Sub
End Module
C
/* narayana.h */
typedef int T; /* Вместо int можно подставить любой тип */
/* Обмен значениями двух элементов последовательности */
static void _swapItems (T *sequence, unsigned index_1, unsigned index_2);
/* Поиск очередной перестановки */
unsigned nextPermutation (T *sequence, unsigned const count, int (*compare)(T const, T const));
/* narayana.c */
#include "narayana.h"
/* Обмен значениями двух элементов последовательности */
static void _swapItems (T *sequence, unsigned index_1, unsigned index_2) {
T item = sequence[index_1];
sequence[index_1] = sequence[index_2];
sequence[index_2] = item;
}
/* Поиск очередной перестановки */
unsigned nextPermutation (T *sequence, unsigned count, int (*compare)(T const, T const)) {
unsigned i = count, j;
/* Этап № 1 */
do {
if (i < 2)
return 0; /* Перебор закончен */
--i;
} while (!(*compare)(sequence[i - 1], sequence[i]));
/* Этап № 2 */
for (j = count; j > i && !(*compare)(sequence[i - 1], sequence[j - 1]); --j);
_swapItems(sequence, i - 1, j - 1);
/* Этап № 3 */
for (j = count; i < j && i < --j; )
_swapItems(sequence, i++, j);
return 1;
}
Пример использования:
/* narayana_test.c */
#include <malloc.h>
#include <stdio.h>
#include "narayana.h"
/* Возвращает 1, если value_0 меньше value_1, иначе — 0 */
int less (T const value_0, T const value_1) {
return value_0 < value_1;
}
/* Возвращает 1, если value_0 больше value_1, иначе — 0 */
int greater (T const value_0, T const value_1) {
return value_0 > value_1;
}
/* Инициализация последовательности */
void initSequence (T *sequence, unsigned count) {
/* Заполнение последовательности значениями 1, 2, 3… */
unsigned i;
for (i = count; i; --i)
sequence[i - 1] = i;
}
/* Вывод содержимого последовательности */
void outputSequence (T const *sequence, unsigned count) {
putchar('[');
if (count) { /* Если последовательность не пуста */
unsigned i;
printf("%d", sequence[0]);
for (i = 1; i < count; ++i)
printf(", %d", sequence[i]);
}
putchar(']');
putchar('\n');
}
/* Основная программа */
int main () {
unsigned count;
scanf("%d", &count);
T *sequence = (T*)malloc(count * sizeof(T));
initSequence(sequence, count); /* Формирование исходной последовательности */
printf("Неубывающая последовательность и её перестановки:\n");
do {
outputSequence(sequence, count);
} while (nextPermutation(sequence, count, &less)); /* x < y — критерий сравнения для неубывающей последовательности */
printf("Невозрастающая последовательность и её перестановки:\n");
do {
outputSequence(sequence, count);
} while (nextPermutation(sequence, count, &greater)); /* x > y — критерий сравнения для невозрастающей последовательности */
free(sequence);
return 0;
}
C++
На основе итераторов. В качестве последовательности могут выступать не только массивы, но и другие контейнеры, поддерживающие последовательный доступ, например, списки.
// narayana.hpp
namespace Narayana {
// Обмен значениями двух элементов последовательности
template < typename T >
static void _swap (T &variable_0, T &variable_1) {
T variable = variable_0;
variable_0 = variable_1;
variable_1 = variable;
}
// Поиск очередной перестановки
template < typename Iterator, typename T >
bool nextPermutation (Iterator const begin, Iterator const end, bool (*compare)(T const, T const)) {
if (begin == end) // Если последовательность не содержит элементов
return false; // Нечего перебирать
// Этап № 1
Iterator i = end - 1, j = end;
do {
if (i == begin)
return false; // Перебор закончен
} while (!(*compare)(*--i, *--j));
// Этап № 2
j = end;
while (j != i && !(*compare)(*i, *--j));
_swap(*i, *j);
// Этап № 3
++i;
j = end;
for ( ; (i != j) && (i != --j); ++i)
_swap(*i, *j);
return true;
}
}
Пример использования:
// narayana_test.cpp
#include <iostream>
#include "narayana.hpp"
// Возвращает true, если value_0 меньше value_1, иначе — false
template < typename T >
bool less (T value_0, T value_1) {
return value_0 < value_1;
}
// Возвращает true, если value_0 больше value_1, иначе — false
template < typename T >
bool greater (T value_0, T value_1) {
return value_0 > value_1;
}
// Инициализация последовательности
template < typename Iterator >
void initSequence (Iterator const begin, Iterator const end) {
int i = 0;
for (Iterator current = begin; current != end; ++current)
*current = ++i;
}
// Вывод содержимого последовательности
template < typename Iterator >
void outputSequence (Iterator const begin, Iterator const end) {
std::cout << '[';
if (begin != end) {
std::cout << *begin;
for (Iterator current = begin; ++current != end; )
((std::cout << ',') << ' ') << *current;
}
(std::cout << ']') << '\n';
}
int main () {
unsigned count;
std::cin >> count;
int *sequence = new int[count], *sequence_end = sequence + count;
initSequence(sequence, sequence_end); // Формирование исходной последовательности
std::cout << "Неубывающая последовательность и её перестановки:\n";
do {
outputSequence(sequence, sequence_end);
} while (Narayana::nextPermutation(sequence, sequence_end, &less<int>)); // x < y — критерий сравнения для неубывающей последовательности
std::cout << "Невозрастающая последовательность и её перестановки:\n";
do {
outputSequence(sequence, sequence_end);
} while (Narayana::nextPermutation(sequence, sequence_end, &greater<int>)); // x > y — критерий сравнения для невозрастающей последовательности
delete [] sequence;
return 0;
}
Java
// Narayana.java
abstract class Narayana {
// Функция, задающая отношение порядка для значений типа T: < либо >
@FunctionalInterface
interface Predicate2 <T extends Comparable> {
boolean compare (final T value_0, final T value_1);
}
// Поиск очередной перестановки
public static final <T extends Comparable> boolean nextPermutation (T[] sequence, Predicate2 comparator) {
// Этап № 1
int i = sequence.length;
do {
if (i < 2)
return false; // Перебор закончен
--i;
} while (!comparator.compare(sequence[i - 1], sequence[i]));
// Этап № 2
int j = sequence.length;
while (i < j && !comparator.compare(sequence[i - 1], sequence[--j]));
_swapItems(sequence, i - 1, j);
// Этап № 3
j = sequence.length;
while (i < j && i < --j)
_swapItems(sequence, i++, j);
return true;
}
// Обмен значениями двух элементов последовательности
private static final <T> void _swapItems (T[] sequence, int index_0, int index_1) {
T temp = sequence[index_0];
sequence[index_0] = sequence[index_1];
sequence[index_1] = temp;
}
}
Пример использования:
// NarayanaTest.java
import java.util.Arrays;
import java.util.Scanner;
public class NarayanaTest {
// Возвращает true, если value_0 меньше value_1, иначе — false
static final <T extends Comparable> boolean less (final T value_0, final T value_1) {
return value_0.compareTo(value_1) < 0;
}
// Возвращает true, если value_0 больше value_1, иначе — false
static final <T extends Comparable> boolean greater (final T value_0, final T value_1) {
return value_0.compareTo(value_1) > 0;
}
// Инициализация последовательности
static final void initSequence (Integer[] sequence) {
for (int value = sequence.length; value > 0; --value)
sequence[value - 1] = value;
}
// Основная программа
public static void main (String[] args) {
Scanner scanner = new Scanner(System.in);
int count = scanner.nextInt();
Integer[] sequence = new Integer[count];
initSequence(sequence); // Формирование исходной последовательности
System.out.println("Неубывающая последовательность и её перестановки:");
do {
System.out.println(Arrays.deepToString(sequence));
} while (Narayana.nextPermutation(sequence, NarayanaTest::less)); // x < y — критерий сравнения для неубывающей последовательности
System.out.println("Невозрастающая последовательность и её перестановки:");
do {
System.out.println(Arrays.deepToString(sequence));
} while (Narayana.nextPermutation(sequence, NarayanaTest::greater)); // x > y — критерий сравнения для невозрастающей последовательности
}
}
Pascal
{ Narayana.pas }
UNIT Narayana;
INTERFACE
type T = Integer; { Вместо Integer можно использовать любой тип }
{ Функция, задающая отношение порядка для значений типа T: < либо > }
TPredicate2 = function (const value_0, value_1: T): Boolean;
{ Поиск очередной перестановки }
function NextPermutation (var sequence: array of T; Compare: TPredicate2): Boolean;
IMPLEMENTATION
{ Поиск очередной перестановки }
function NextPermutation (var sequence: array of T; Compare: TPredicate2): Boolean;
var count, i, j: Word;
{ Обмен значениями двух элементов последовательности }
procedure SwapItems (index_1, index_2: Word);
var item: T;
begin
item := sequence[index_1];
sequence[index_1] := sequence[index_2];
sequence[index_2] := item
end;
begin
count := Length(sequence);
{ Этап № 1 }
i := count;
repeat
if i < 2 then
begin
NextPermutation := false;
Exit
{ Перебор закончен }
end;
i := i - 1
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;
SwapItems(i - 1, j - 1);
{ Этап № 3 }
j := count;
while (i < j) and (i < j - 1) do
begin
j := j - 1;
SwapItems(i, j);
i := i + 1
end;
NextPermutation := true
end;
END.
Пример использования:
{ NarayanaTest.pas }
uses Narayana;
var sequence: array of T;
count: Word;
{ Возвращает 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 (const 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
ReadLn(count);
SetLength(sequence, count);
InitSequence(sequence); { Формирование исходной последовательности }
WriteLn('Неубывающая последовательность и её перестановки:');
repeat
OutputSequence(sequence)
until not NextPermutation(sequence, @Less); { x < y — критерий сравнения для неубывающей последовательности }
WriteLn('Невозрастающая последовательность и её перестановки:');
repeat
OutputSequence(sequence)
until not NextPermutation(sequence, @Greater) { x > y — критерий сравнения для невозрастающей последовательности }
END.
PHP
Вариант № 1
function nextPermutation ($sequence, $count) {
$out = $sequence;
// Этап № 1
$k = $count - 2;
while ($k >= 0 && $out[$k] >= $out[$k + 1]) {
--$k;
}
if (-1 == $k) {
return false; // Перебор закончен
}
// Этап № 2
$t = $count - 1;
while ($t >= 0 && $t >= $k + 1 && $out[$k] >= $out[$t]) {
--$t;
}
$tmp = $out[$k];
$out[$k] = $out[$t];
$out[$t] = $tmp;
// Этап № 3
for ($i = $k + 1; $i < ceil(($count + $k) / 2); ++$i) {
$t = $count + $k - $i;
$tmp = $out[$i];
$out[$i] = $out[$t];
$out[$t] = $tmp;
}
return $out;
}
Вариант № 2
Вариант с выводом справа налево:
$b = "123456789";
$a = strrev($b);
while ($a !=$b) {
$i = 0;
while($a[$i] > $a[$i - 1]) {
$i++;
}
$j = 0;
while($a[$j] < $a[$i]) {
++$j;
}
$c = $a[$j];
$a[$j] = $a[$i];
$a[$i] = $c;
$x = strrev(substr($a, 0, $i));
$y = substr($a, $i);
print $a = $x . $y;
print ‘<br/>’;
}
Python
# narayana.py
"""Поиск очередной перестановки"""
def next_permutation (sequence, compare):
count = len(sequence)
i = count
# Этап № 1
while True:
if i < 2:
return False # Перебор закончен
i -= 1;
if compare(sequence[i - 1], sequence[i]):
break
# Этап № 2
j = count
while j > i and not compare(sequence[i - 1], sequence[j - 1]):
j -= 1
sequence[i - 1], sequence[j - 1] = sequence[j - 1], sequence[i - 1]
# Этап № 3
j = count
while i < j and i < j - 1:
j -= 1
sequence[i], sequence[j] = sequence[j], sequence[i]
i += 1
return True
Пример использования на Python 3.x (в Python 2.x надо убрать скобки в операторах print
):
# narayana_test.py
import narayana
"""Возвращает True, если value_0 меньше value_1, иначе — False"""
def less (value_0, value_1):
return value_0 < value_1
"""Возвращает True, если value_0 больше value_1, иначе — False"""
def greater (value_0, value_1):
return value_0 > value_1
# Основная программа
count = int(input());
sequence = list(range(1, count + 1)) # Формирование исходной последовательности
print("Неубывающая последовательность и её перестановки:")
while True:
print(sequence)
if not narayana.next_permutation(sequence, less): # x < y — критерий сравнения для неубывающей последовательности
break
print("Невозрастающая последовательность и её перестановки:")
while True:
print(sequence)
if not narayana.next_permutation(sequence, greater): # x > y — критерий сравнения для невозрастающей последовательности
break
Rust
// narayana.rs
// Поиск очередной перестановки
fn next_permutation <T: Copy + PartialOrd> (sequence: &mut[T], compare: fn (T, T) -> bool) -> bool {
let count = sequence.len();
let mut i = count;
// Этап № 1
while {
if i < 2 {
return false; // Перебор закончен
}
i -= 1;
!compare(sequence[i - 1], sequence[i])
} { } // Пустое тело цикла (имитация цикла с постусловием)
// Этап № 2
let mut j = count;
while j > i && !compare(sequence[i - 1], sequence[j - 1]) {
j -= 1;
}
sequence.swap(i - 1, j - 1);
// Этап № 3
j = count;
while i < j && i < j - 1 {
j -= 1;
sequence.swap(i, j);
i += 1;
}
true
}
Пример использования:
// narayana_test.rs
// Возвращает true, если value_0 меньше value_1, иначе — false
fn less <T: PartialOrd> (value_0: T, value_1: T) -> bool {
value_0 < value_1
}
// Возвращает true, если value_0 больше value_1, иначе — false
fn greater <T: PartialOrd> (value_0: T, value_1: T) -> bool {
value_0 > value_1
}
// Инициализация последовательности
fn init_sequence (sequence: &mut [usize]) {
// Заполнение последовательности значениями 1, 2, 3…
let mut i = sequence.len();
while i > 0 {
sequence[i - 1] = i;
i -= 1;
}
}
// Функция для ввода данных
fn read_var <Type: std::str::FromStr> (var: &mut Type) -> bool {
let mut input_text = String::new();
std::io::stdin()
.read_line(&mut input_text)
.expect("failed to read from stdin");
match input_text.trim().parse::<Type>() {
Ok(value) => { *var = value; true },
Err(..) => { false }
}
}
// Основная программа
fn main () {
let mut count = 0usize;
read_var(&mut count);
let mut sequence = vec![0usize; count];
init_sequence(&mut sequence); // Формирование исходной последовательности
println!("Неубывающая последовательность и её перестановки:");
while {
println!("{:?}", sequence);
narayana::next_permutation(&mut sequence, less::<usize>) // x < y — критерий сравнения для неубывающей последовательности
} { }
println!("Невозрастающая последовательность и её перестановки:");
while {
println!("{:?}", sequence);
narayana::next_permutation(&mut sequence, greater::<usize>) // x > y — критерий сравнения для невозрастающей последовательности
} { }
}