Koszt zamortyzowany

by Jerry Sky

2020-04-22



Def\text {Def}

Koszt zamortyzowany (zamortyzowana złożoność obliczeniowa) operacji jest jej średnim kosztem w najgorszym przypadku.

Metody analizy kosztu zamortyzowanego

Metoda kosztu sumarycznego

Określa się górne ograniczenie T(n)T(n) na całkowitą złożoność obliczeniową (w pesymistycznym przypadku) ciągu nn badanych operacji. Koszt zamortyzowany każdej operacji rozumiemy wtedy przez T(n)/nT(n)/n.

Metoda księgowania

Rozpatrując ciąg operacji, zawyżamy koszt operacji znajdujących się na początku ciągu. Nadpłaty te zostają potem zużyte na „zapłacenie” za operacje, których złożoność jest mniejsza niż faktycznie poniesione koszty.

Metoda potencjału

Podobnie jak w metodzie księgowania, przypisujemy większy koszt wcześniejszym operacjom, aby skompensować późniejsze nadmierne wydatki. W metodzie potencjału „kredyt” jest reprezentowany jako „energia potencjalna” całej struktury danych i nie jest związana z pojedynczymi obiektami (jak to ma miejsce w metodzie księgowania).
Skupimy się na metodzie potencjału.

Stosujemy metodę potencjału

Będziemy rozpatrywali ciąg n+1n+1 struktur D0,D1,,DnD_0,D_1,\dots,D_n, gdzie DiD_i będzie strukturą danych powstałą ze struktury Di1D_{i-1} po wykonaniu ii-tej operacji.

Rozważmy funkcją potencjału Φ\Phi przyporządkowującą każdej strukturze DiD_i liczbę rzeczywistę nazywaną potencjałem struktury DiD_i.

Dla każdego i=1,,ni = 1,\dots,n niech cic_i oznacza faktyczną złożoność obliczeniową ii-tej operacji, a c^i\hat c_i oznacza koszt zamortyzowany dla ii-tej operacji i definiujemy go jako c^i=ci+Φ(Di)Φ(Di1)\hat c_i = c_i + \Phi(D_i) - \Phi(D_{i-1}).

Zatem po prostych przekształceniach koszt zamortyzowany ciągu nn operacji wynosi: i=1nc^i=i=1nci+Φ(Dn)Φ(D0) \sum_{i=1}^{n}\hat{c}_i = \sum_{i=1}^{n}c_i + \Phi(D_n) - \Phi(D_0) Zwykle dla wygody definiuje się Φ(D0)=0\Phi(D_0) = 0. Jeśli jesteśmy w stanie pokazać, że Φ(Dj)0\Phi(D_j) \ge 0 dla każdego j=1,,nj =1,\dots,n wówczas koszt zamortyzowany ciąg jj operacji (dla dowolnego jj) ogranicza z góry koszt faktyczny ciąg jj operacji: i=1jcii=1jc^i \sum_{i=1}^{j}c_i \le \sum_{i=1}^{j}\hat{c}_i

Koszt zamortyzowany zdefiniowany jak powyżej zależy od wybory funkcji potencjału Φ\Phi. Używając różnych funkcji potencjału, można otrzymać różne koszty zamortyzowane i mimo wszystko otrzymać górne ograniczenie faktycznej złożoności obliczeniowej ciągu operacji.

Przykład, Increment

W celu zilustrowania obliczania kosztu zamortyzowanego posłużymy się przykładem kk bitowego licznika binarnego, który zlicza od 00 za pomocą operacji Increment. Licznik jest przetrzymywany w tablicy bitów A[0k1]A[0\dots k-1] długości kk. Najmniej znaczący bit występuje w A[0]A[0], a najbardziej znaczący w A[k1]A[k-1], zatem jeśli licznik przechowuje liczbę xx to x=i=0k1A[i]2i x = \sum_{i=0}^{k-1}A[i]\cdot2^i Licznik inicjalizujemy ustawiając bit 00 w każdej komórce tablicy AA. Aby zwiększyć wartość licznika o 11 (modulo 2k2^k), używamy wcześniej wspomnianej procedury:

Increment(A):
  i = 0
  while i < k and A[i] == 1:
    A[i] = 0
    i++
  if i < k:
    A[i] = 1

Operacja ta dokonuje zmiany odpowiednich bitów (zaczynając od najmniej znaczących): 101\to0 i po natrafieniu na najmniej znaczący bit zerowy zamienia go na 11.
Koszt (złożoność obliczeniowa) każdej operacji Increment jest równy liczbie zmienionych bitów. Analizując złożoność obliczeniową pojedynczej operacji Increment w worst case scenario, widzimy, że asymptotycznie wynosi ona Θ(k)\Theta(k), bo w najgorszym przypadku w tablicy wszystkie bity będą ustawione na 11 i będziemy musieli je wyzerować lub wszystkie bity poza najbardziej znaczącym zostaną one wyzerowane, a bit A[k1]A[k-1] zostanie ustawiony na 11.

Zauważmy natomiast, że w innych przypadkach liczba modyfikowanych bitów będzie mniejsza, więc istnieje szansa, że da się ograniczyć pesymistyczną złożoność ciągu nn operacji Increment przez coś mniejszego niż O(nk)O(n\cdot k).

Wykorzystanie metody potencjału

Wykorzystajmy metodę potencjału do obliczenia kosztu zamortyzowanego operacji Increment.

  1. Wybór funkcji potencjału: Φ(Di)\Phi(D_i) będzie liczbą jedynek w liczniku po ii-tej operacji.

  2. Załóżmy, że ii-ta operacja Increment zeruje tit_i bitów. Faktyczny koszt tej operacji jest więc ograniczony przez citi+1c_i \le t_i + 1, ponieważ oprócz zerowania tit_i bitów może ona przypisać wartość co najwyżej jednemu bitowi.

  3. Z poprzedniego punktu możemy uzyskać ograniczenie na wyżej zdefiniowaną funkcję potencjału: Φ(Di)Φ(Di1)ti+1. \Phi(D_i) \le \Phi(D_{i-1}) - t_i + 1.

  4. Stąd koszt zamortyzowany ii-tej operacji możemy wyliczyć w następujący sposób: c^i=ci+Φ(Di)Φ(Di1)(ti+1)(ti+1)=2=Θ(1). \hat c_i = c_i + \Phi(D_i) - \Phi(D_{i-1}) \le (t_i + 1) - (-t_i + 1) = 2 = \Theta(1). Jeśli zaczynamy zliczać za pomocą licznika od zera, to Φ(D0)=0\Phi(D_0) = 0.

    Ponieważ Φ(Di)0\Phi(D_i) \ge 0 dla każdego ii, to koszt zamortyzowany ciągu nn operacji Increment jest górnym ograniczeniem kosztu faktycznego, co daje pesymistyczny koszt ciągu nn operacji równy O(n)O(n).

  5. Za pomocą metody potencjału łatwo jest również dokonać analizy w przypadku gdy licznik nie startuje od 00.

    Załóżmy, że początkowo było b0b_0 zer oraz po wykonaniu nn razy operacji Increment mamy bnb_n jedynek., gdzie 0b0bnk0 \le b_0 \land b_n \le k, wówczas: i=1n=i=1nc^iΦ(Dn)+Φ(D0). \sum_{i=1}^{n} = \sum_{i=1}^{n}\hat c_i - \Phi(D_n) + \Phi(D_0). Mamy 1in c^i2\forall_{1\le i\le n}~ \hat c_i \le 2. Skoro Φ(D0)=b0\Phi(D_0) = b_0 oraz Φ(Dn)=bn\Phi(D_n) = b_n, całkowity koszt wykonania nn razy operacji Increment wynosi i=1ni=1n2bn+b0=2nbn+b0. \sum_{i=1}^{n} \le \sum_{i=1}^{n}2 - b_n + b_0 = 2n - b_n + b_0. Należy zauważyć, że jeśli k=O(n)k = O(n) to b0kb_0 \le k co daje nam całkowity koszt równy O(n)O(n).

    Oznacza to tyle, że jeśli wykonamy przynajmniej n=Ω(k)n=\Omega(k) razy operację Increment całkowity koszt zawsze będzie złożoności O(n)O(n) niezależnie od początkowego stanu licznika.

    Section 17.3