Obrót tablicy w prawo oznacza przeniesienie ostatni element na początek listy. Do takie operacji można zastosować algorytm przesuwania elementów tablicy, który wykona taką operację w czasie liniowym. Wpierw przeprowadźmy analizę zagadnienia.
Przypuśćmy, że mamy następującą tablicę danych:
1 | 2 | 3 | 4 | 5 |
---|
W celu przesunięcia elementów o 3 miejsca w prawo należałoby dopisać dodatkowe trzy miejsca za tablicą, a następnie przepisać je w wolne miejsce na początku tablicy. Oznacza to kolejno:
1 | 2 | 3 | 4 | 5 |
---|
3 | 4 | 5 | 1 | 2 |
---|
W podobny sposób działa przekręcanie elementów w lewo. Przykładowo przesunięcie wyjściowej tablicy o -2 zwraca następującą tablice:
1 | 2 | 3 | 4 | 5 |
---|
3 | 4 | 5 | 1 | 2 |
---|
Jest to dokładnie taka sama tablica jak w przypadku przesunięcia w prawo o 3. Nie jest to przypadek, ponieważ tablica ma dokładnie 5 elementów (-2 + 5 = 3).
Każde przesunięcie można zamienić na przesunięcie z przedziału [0, n - 1]. W tym celu należy wziąć resztę z dzielenia przesunięcia p przez n dla dodatnich przesunięć, a w przypadku ujemnych tak długo dodawać n, aż uzyska się wartość dodatnią.
Zadanie polega na napisaniu funkcji obroc(), która daną tablicę obróci o dowolne przesunięcie. Przedstawione zostaną dwie metody, które działają bardzo podobnie, ale różnią się złożonością pamięciową.
Proste rozwiązanie polega na utworzeniu dodatkowej tablicy. Następnie dla każdego elementu należy wyliczyć pozycję na której ma się znaleźć w ostatecznej tablicy. Tego typu rozwiązanie wymaga dodatkowego miejsca w pamięci na dodatkową tablicę długości n. Oto przykładowa funkcja obroc():
(2.) Normalizuj przesunięcie, a następnie (3.) przygotuj tablice wynikową. W dalszej części (4.) dla każdego jej elementu: (5.) oblicz, który element z tablicy wejściowej powinien znaleźć się na i-tej pozycji. (6.) Wynikiem działania funkcji jest obrócona tablica.
Optymalne rozwiązanie eliminuje problem potrzebnej dodatkowej pamięci. Jedyne czego będzie wymagać to dodatkowej zmiennej do przechowania elementu w celu zamiany dwóch elementów. Otóż zamianę rozpoczynamy od indeksu 0. Dla wybranego indeksu obliczamy, gdzie powinien się znaleźć. Następnie podmieniamy go z elementem na wyliczonej pozycji. Dla nowo ustawionego elementu powtarzamy proces, aż wrócimy do początkowego indeksu.
Weźmy nastepującą tablicę L:={1, 2, 3, 4, 5}. Przyjmujemy, że rozpoczynamy działanie od pierwszego elementu. W tabeli zostały wyjaśnione kolejne operacje dla przesunięcia p = 3:
Tablica | Indeks | Temp | Pozycja docelowa |
---|---|---|---|
{1, 2, 3, 4, 5} | 0 | 1 | 3 |
{1, 2, 3, 1, 5} | 3 | 4 | 1 |
{1, 4, 3, 1, 5} | 1 | 2 | 4 |
{1, 4, 3, 1, 2} | 4 | 5 | 2 |
{1, 4, 5, 1, 2} | 2 | 3 | 0 |
{3, 4, 5, 1, 2} | 0 | 1 | - |
Tablica po przesunięci elementów o p = 3 to L':={3, 4, 5, 1, 2}.
Oto przykładowy kod:
(2.) Normalizuj przesunięcie, a następnie (3.) rozpocznij zamiany od indeksu 0 i pobierz z tablicy element 0 i zapisz w zmiennej tymczasowej temp. Następnie (5.) oblicz gdzie wstawić element zapisany w temp i (6.) zamień go z elementem na wyliczonej pozycji poz. Przed zakończeniem iteracji (7.) zaktualizuj indeks pobranego elementu i (8.) wykonaj następną iterację jeśli wciaż istnieją elementy do zamiany.
W celu przetestowania kodu funkcji obroc() można skorzystać z poniższego fragmentu kodu. W zależności od wersji funkcji istnieje potrzeba dostosowania linijek wywołujące funkcję i wypisujące wynik.