Inwersja jest to para liczb ai, aj w ciągu a1, a2, .., an, gdzie i < j, a aj > ai. W matematycę funkcję zliczania inwersji oznaczamy i(X), gdzie X to pewna permutacja ciągu. Jako liczbę inwersji uznajemy łączą ilość inwersji dla danej permutacji.
Łączna liczba inwersji pokazuje jak tablica jest daleko od bycia posortowaną. Warto tutaj zaznaczyć, że ciąg posortowany ma liczbę inwersji 0, a ciąg posortowany odwrotnie maksymalną wartość iwnersji. Poza tym liczenie inwersji dla dwóch dowolnych tablic może powiedzieć jak bardzo podobne są obydwie tablice.
Weźmy ciąg (1, 2, 3, 4) i utwórzmy jego permutacje: (3, 4, 1, 2). W celu zliczenia liczby inwersji należy teraz porównać każdą parę liczb o różnych indeksach i zliczyć ile razy większa liczba występuje przed mniejszą:
Indeks i | 1 | 1 | 1 | 2 | 2 | 3 |
---|---|---|---|---|---|---|
Indeks j | 2 | 3 | 4 | 3 | 4 | 4 |
Porównanie | 3 < 4 | 3 > 1 | 3 > 2 | 4 > 1 | 4 > 2 | 3 < 4 |
Czy inwersja? | Nie | Tak | Tak | Tak | Tak | Nie |
Zliczając ilość otrzymanych inwersji otrzymujemy 4. Oznacza to, że 4 z 6 par nie są ustawione w sposób rosnący.
Tym razem rozpatrzmy ciąg posortowany (1, 2, 3, 4). Wtedy otrzymujemy:
Indeks i | 1 | 1 | 1 | 2 | 2 | 3 |
---|---|---|---|---|---|---|
Indeks j | 2 | 3 | 4 | 3 | 4 | 4 |
Porównanie | 1 < 2 | 1 < 3 | 1 < 4 | 2 < 3 | 2 < 4 | 3 < 4 |
Czy inwersja? | Nie | Nie | Nie | Nie | Nie | Nie |
Łączna liczba inwersji to 0. Niezależnie od długości wybranego ciągu jeśli jest on posortowany to liczba inwersji wynosi dokładnie 0. Można to udowodnić następująco: niezależnie od wybranego indeksu i nie istnieje taki indeks j, aby wartość i indeksie j była mniejsza od tej na pozycji i.
Tym razem rozpatrzmy permutację (4, 3, 2, 1), która w myśl inwersji jest najdalej od posortowanej. Rozpisując tabelkę otrzymujemy:
Indeks i | 1 | 1 | 1 | 2 | 2 | 3 |
---|---|---|---|---|---|---|
Indeks j | 2 | 3 | 4 | 3 | 4 | 4 |
Porównanie | 4 > 3 | 4 > 2 | 4 > 1 | 3 > 2 | 3 > 1 | 2 > 1 |
Czy inwersja? | Tak | Tak | Tak | Tak | Tak | Tak |
Łączna liczba inwersji to 6. Otrzymaliśmy maksymalną liczbę inwersji dla ciągu czteroelementowego. Dla ciągu o innej długości maksymalna liczba jest inna.
Zauważmy, że w ciągu liczb a1, a2, .., an przestawienie an na pierwszą pozycję powoduje zwiększenie liczby inwersji o n - 1, przedstawiając element an - 1 na drugą pozycję zwiększymy o n - 2. Powtarzając ten proces otrzymamy ciąg posortowany odwrotnie an, an - 1, .., a1. Każdy element dodaje maksymalną liczbę inwersji jaką może utworzyć. Wtedy imax(X) = (n - 1) + (n - 2) + .. + 1 + 0 = n·(n - 1)/2 co wynika z sumy na ciąg arytmetyczny wyrazów od 0 do n - 1.
Chcą napisać program, który w naiwny sposób zlicza łączną liczbę inwersji pewnej permutacji jest bardzo podobny do sortowania bąbelkowego: porównujemy każdą możliwą parę elementów i jeśli istnieje potrzeba ich zamiany to zwiększamy licznik inwersji. Ze względu na fakt, że porównujemy każdą liczbę z każdą to łączna liczba porównań wyniesie n2, a że operacja porównania jest operacją dominującą to algorytm będzie miał złożoność O(n2).
Oto kod funkcji zliczającej inwersje zliczInwersje(), która na podstawie przekazanej tablicy tab sprawdza ile występuje inwersji. Uwaga: Algorytm zakłada, że dla tablicy długości n ciągiem wyjściowym jest a1, a2, .., an, gdzie ai jest liczbą całkowitą.
(2.) Inicjalizacja licznika. Następnie (3. - 4.) wybór indeksu i i j. Potem jeśli (5.) jest inwersja to (6.) zwiększamy licznik. Na koniec (9.) zwracamy łączną liczbę inwersji.
Nie jest to jednak najszybszy możliwy algorytm wyznaczania liczby inwersji. Istnieje szybszy, który opiera się na Sortowaniu Przez Scalanie.
Poniższy kod wczytuje od użytkownika tablicę liczb tab o pewnej długości n i pokazuje ile inwersji występuje w ciągu.