Do utworzenia wszystkich możliwych permutacji pewnego ciągu można zastosować algorytm z nawrotami (tzw. backtracking). Najprostsza implementacja wypisuje permutacje nawet jeśli się duplikują. W tym artykule zostanie dokładnie opisane jak napisać algorytm do generowania permutacji pewnego wyrażenia.
Generator permutacji dla wyrażenia 123 powinien zwrócić następujące wartości (w dowolnej kolejności):
Algorytm wykorzystujący algorytm z nawrotami działa następująco: wybierz kolejny, dotychczas niewybrany znak i umieść go na kolejnej pozycji. Następnie wywołaj funkcję do permutowania z nowoutworzonym słowem. Powtórz to dla każdego niewybranego znaku. Rekurencyjne wywoływanie funkcji kończy się, gdy wszystkie znaki słowa zostały ustalone.
Prześledźmy działanie algorytmu dla wyrażenia "ABC".
L.p. | Słowo | Znaki | Komentarz |
---|---|---|---|
1. | - | A, B, C | Wybieramy kolejno znaki na pierwszą pozycję i permutujemy pozostałe znaki |
1.1. | A | B, C | Wywołanie rekurencyjne polega na tym samym |
1.1.1. | AB | C | Kolejne wywołanie rekurencyjne |
1.1.1.1. | ABC | - | Brak wolnych znaków - wypisujemy lub zapisujemy wynik i kończymy wywołanie funkcji |
1.1.2. | AB | C | Brak innych znaków niż C, koniec wywołania |
1.2. | A | B, C | Tym razem wybieramy znak C |
1.2.1. | AC | B | Wybieramy kolejne znaki |
1.2.1.1. | ACB | - | Kolejne zakończenie rekurencji, powrót |
.. | .. | .. | .. |
Kontynuując ten algorytm wszystkie możliwe permutacje zostaną znalezione.
Podczas działania tego algorytmu nie jest sprawdzane czy dana permutacja już wcześniej wystąpiła. Oznacza to, że niektóre permutacje mogą się powtarzać jeśli jakiś znak występuje więcej niż jeden raz.
Podczas wykonywania tego algorytmu sprawdzane są wszystkie możliwe kombinacje, więc złożoność wynosi O(n·n!). Zakładając, że wszystkie elementy wyrażenia są unikalne nie istnieje algorytm o lepszej złożoności niż wspomniana.
Funkcja permutuj() przyjmuje dwa argumenty: slowo - tekst dla którego mają zostać wygenerowane permutacje oraz opcjonalny argument poz ile pierwszych znaków tekstu pominąć. W celu permutacji całego tekstu należy go ustawić na 0, a najlepiej skorzystać z domyślnej wartości.
Algorytm rekurencyjnie wybiera znak do ustawienia na pozycji poz, a następnie rekurencyjnie przechodzi do ustawienia następnego znaku. Zakłada się, że znaki o indeksie mniejszym od poz zostały już wybrane, a wszystkie znaki "wolne" są od indeksu poz do końca tekstu. Wszystkie znalezione permutacje są wypisywane od razu na konsolę.
W celu przetestowania kodu można skorzystać z poniższej fragmentu, który wczytuje wyrażenie, a następnie wypisuje wszystkie permutacje.