Obliczanie złożności algorytmów

0

Witam was, mam pytanie odnośnie tego jak się oblicza złożoność obliczeniową algorytmów z dwoma i trzema pętlami zależnymi i niezależnymi od siebie. Mam z tego kartkówki co tydzień a mam z tym problemu z racji tego że nasz prowadzący słabo tłumaczy.

Tutaj mam algorytmy, których złożoności mam obliczyć:

 

for i:=1 to n-1 do
   for j = 1 to i+1 do
       x:= x+1;

for i:=0 to n do
begin
  j:=1;
    while j < n do
      j:=j+1;
end;

for i:=1 to n do
   if x > 3 then
     for j:=1 to n do
        for k:=5 to n do
           x:=x+1;
   else
       for j:=1 to n do
          x:=x+1;

Próbowałem ksiażek, materiałów z internetu ale nic mi to nie daje bo potrafię obliczyć złożoności tylko niektórych prostych algorytmów, przeważnie na wyczucie a nie tędy droga. Byłbym wdzięczny, gdyby ktoś był w stanie wytłumaczyć w jaki sposób się takie złożoności liczy i czy istnieje jakiś konkretny sposób lub sposoby ich rozwiązywania, czy trzeba po prostu patrzeć na te algorytmy i od razu widzieć jaką mają złożoność tak jak to robi nas rewelacyjny prowadzący. Zależy mi tylko na tym żeby to zrozumieć. Z góry dzięki za pomoc.

0

Rozpisz sobie te pętle jako ciągi/szeregi liczbowe i wyznacz sumę tych ciągów/szeregów. To jest metoda uniwersalna.

2

Trudno to ująć w sposób prosty do zrozumienia - Wikipedia zdecydowanie nie pomaga ;) pl.wikipedia.org/wiki/Asymptotyczne_tempo_wzrostu (Mówimy, że f jest dokładnie rzędu g, gdy istnieją takie stałe że n0 > 0 i c1 > 0 i c2 > 0 ...)

Ta złożoność to inaczej ilość wykonywanych operacji w zależności od wielkości danych wejściowych.

Na przykład (przykłady w C zamiast Pascala...)

int foo()
{
    return 2;
}

jest oczywiście złożoności O(1) - bo zawsze jest wykonywana jedna operacja.

int foo(int var) // przekazujemy parametr typu int
{
    return 2*var + 1234;
}

ten kod też jest złożoności T(3) - zawsze wykonuje 3 operacje (mnożenie, dodawanie i zwrócenie wartości). Ale przy mierzeniu złożoności liczy się tylko rząd wielkości, dlatego jest to funkcja O(1) (formalnie - istnieje taka stała c że c*1 > 3 - logiczne, prawda? :>)

Ok, coś ciekawszego:

int sum(int *array, int count)
{
    int s = 0;
    for(int i = 0; i < count; i++)
    { s += array[i]; }
    return s;
}

jak widać, ta funkcja służy do sumowania tablicy (int *array to tablica liczb całkowitych, w zmiennej count jest liczba elementów w tablicy)
Nie możemy tutaj podać żadnej skalarnej złożoności, na przykład T(1000), ponieważ ilość operacji zależy od wielkości danych wejściowych.
Dlatego przyjmujemy n jako wielkość danych wejściowych. Teraz możemy podać złożoność - wynosi ona T(n + 2) (n dodawań + przypisanie 0 + zwrócenie wartości). Po zredukowaniu zbędnych wyrazów, otrzymujemy rząd wielkości O(n).

A coś takiego:

int abc(int *array, int count)
{
   int x = 1;
   for(int i = 0; i < count; i++)
   { x *= array[i]; }

   for(int i = 0; i < count - 1; i++)
   { x += array[i] - array[i+1]; }

   return x / 5;
}

Ta funkcja nie robi nic sensownego. Policzmy jej złożoność - przegląda tablicę wejściową (rozmiaru n) dwa razy - czyli mamy n*(dodawanie) + n*(dodawanie i odejmowanie) czyli w sumie 3*n operacji. Po poprzednich przykładach powinieneś dość łatwo wyliczyć T(3n + 3) i O(n).

I jeszcze:

int zzz(int *array, int count)
{
    int s = 0;
    for(int i = 0; i < count; i+=10);
    { s += array[i]; }
    return s;
}

Sumujemy co 10 element tablicy złożoność to mniej-więcej T(n/10) - ale złożoność to i tak O(n).

W rzeczywistości każda funkcja która przegląda dane wejściowe stałą ilość razy (raz, dwa razy, sto razy, jedną dziesiątą raza) ma złożoność O(n).
To może dalszy przykład:

int foo(int *array, int count)
{
   int x = 0;
   for(int i = 0; i < count; i++)
      for(int j = 0; j < count; j++)
      {
         x += array[i] / array[j];
      }
   return x;
}

Ta funkcja sumuje wszystkie możliwe ilorazy w tablicy.
Jak pisałem, każda funkcja która przegląda dane wejściowe stałą ilość razy ma złożoność O(n) - ale ta funkcja nie przegląda danych stałą ilość razy - właściwie to przegląda je n razy!
Czyli wykonujemy n razy n operacji - mamy złożoność O(n*n) == O(n^2)!

Albo taki kod (wyjątkowo kod skopiowany z wiki)

void bubblesort(int table[], int size)
{
        int i, j, temp;
        for (i = 0; i<size; i++)
                for (j=i; j<size-1; j++)
                        {
                                if (table[j] > table[j+1])
                                {
                                        temp = table[j+1];
                                        table[j+1] = table[j];
                                        table[j] = temp;
                                }
                        }
}

Jest to procedura sortowania bąbelkowego.
Pierwsza pętla wykonuje się n razy, a zagnieżdżona pętla wykonuje się za każdym razem coraz mniej razy.
Tutaj również jest O(n^2) operacji!
Dlaczego? Dla tablicy 3-elementowej ilość operacji wyniesie 3 (pierwszy raz)+2 (druga pętla, j zaczyna się od 1)+1 (ostatni obrót).
Dla 4-el wyniesie 4+3+2+1 operacji.
Dla n-el wyniesie n+(n-1)+...+3+2+1 = (n*(n+1))/2 operacji (suma ciągu arytmetycznego). Czyli złożonośc algorytmu to T(n*(n+1)/2)! Teraz pomijamy nieznaczące wyrazy i otrzymujemy O(n^2).

Ogólnie jeśli wykonujesz jakąś czynność pewną ilość razy zależną od wielkości wejścia złożoność wynosi O(n). A jeśli wykonujesz czynność o złożoności O(n) n razy, masz zlożoność O(n^2)
Złożoność (N3) analogicznie - wykonywanie czynności O(n2) n razy.
Złożoności log(n) i n*log(n) pominę bo z tego co widzę jeszcze ich nie macie a są trochę bardziej skomplikowane.

I wreszcie...

for i:=1 to n-1 do
   for j = 1 to i+1 do
       x:= x+1;

To powinieneś wiedzieć, prawie dokładnie takie same przykłady omawiałem :>

for i:=0 to n do
begin
  j:=1;
    while j < n do
      j:=j+1;
end;

Porównaj z poprzednim, jest wbrew pozorom bardzo podobny.

for i:=1 to n do
   if x > 3 then
     for j:=1 to n do
        for k:=5 to n do
           x:=x+1;
   else
       for j:=1 to n do
          x:=x+1;
 

Coś kręcisz, x nie jest nigdzie zadeklarowany. Ale ok, zakładamy że x jest parametrem funkcji.
No więc liczysz zawsze złożoność w najgorszym możliwym przypadku. jeśli x > 3 to złożoność instrukcji warunkowej wynosi (ile, hm?), a jeśli x <= 3 to wynosi tylko (no?).
A jako że instrukcja warunkowa jest wykonywana zawsze n razy, złożoność całego algorytmu wynosi (* no właśnie?*).

Rozpisałem się strasznie, mam nadzieję że chociaż trochę pomogłem i nie namieszałem (czas iść spać). Pozdrawiam...

0
Tezcatlipoca napisał(a)

A coś takiego:

int abc(int *array, int count)
{
   int x = 1;
   for(int i = 0; i < count; i++)
   { x *= array[i]; }

   for(int i = 0; i < count - 1; i++)
   { x += array[i] - array[i+1]; }

   return x / 5;
}

Ta funkcja nie robi nic sensownego. Policzmy jej złożoność - przegląda tablicę wejściową (rozmiaru n) dwa razy - czyli

mamy n*(dodawanie) + n*(dodawanie i odejmowanie) czyli w sumie 3*n operacji. Po poprzednich przykładach powinieneś dość łatwo

wyliczyć T(3n + 3) i O(n).

Jeśli dobrze zrozumiałem, ndodawanie ( pierwsza pętla ma złożoność n) ndodawanie i odejmowanie ( druga pętla ma złożoność 2n ) i do tego przypisanie 1 to O(1), dzielenie x/5 to O(1), zwracanie wartości to też O(1) czyli w sumie mamy 3n+3 i klasa O(n) tak?

int zzz(int *array, int count)
{
    int s = 0;
    for(int i = 0; i < count; i+=10);
    { s += array[i]; }
    return s;
}

Sumujemy co 10 element tablicy złożoność to mniej-więcej T(n/10) - ale złożoność to i tak O(n).

W rzeczywistości każda funkcja która przegląda dane wejściowe stałą ilość razy (raz, dwa razy, sto razy, jedną dziesiątą

raza) ma złożoność O(n).

W tym miejscu już się zgubiłem, pętla ma złożoność n/10 to rozumiem ale co z przypisaniem 0 i zwracaniem wartości ? Nie bierzemy ich pod uwagę czy to nie istotne? Pytam o to bo nasz prowadzący wymaga podania dokładnego wzoru na złożoność, podanie samej klasy O(n) nie wystarczy a biorąc pod uwagę fakt że mamy system binarny jeżeli chodzi o ocenianie ( albo jest źle albo jest dobrze ) to nie podanie wzoru jest równoznaczne z nie zrobieniem zadania. Szczerze mówiąc to wzór jest dla niego najistotniejszy.

To może dalszy przykład:

int foo(int *array, int count)
{
   int x = 0;
   for(int i = 0; i < count; i++)
      for(int j = 0; j < count; j++)
      {
         x += array[i] / array[j];
      }
   return x;
}

Ta funkcja sumuje wszystkie możliwe ilorazy w tablicy.
Jak pisałem, każda funkcja która przegląda dane wejściowe stałą ilość razy ma złożoność O(n) - ale ta funkcja nie przegląda

danych stałą ilość razy - właściwie to przegląda je n razy!
Czyli wykonujemy n razy n operacji - mamy złożoność O(n*n) == O(n^2)!

Tutaj pytanie takie samo jak w poprzednim przykładzie O(n2) czy O(n2 + 2) ?

Albo taki kod (wyjątkowo kod skopiowany z wiki)

void bubblesort(int table[], int size)
{
        int i, j, temp;
        for (i = 0; i<size; i++)
                for (j=i; j<size-1; j++)
                        {
                                if (table[j] > table[j+1])
                                {
                                        temp = table[j+1];
                                        table[j+1] = table[j];
                                        table[j] = temp;
                                }
                        }
}

Jest to procedura sortowania bąbelkowego.
Pierwsza pętla wykonuje się n razy, a zagnieżdżona pętla wykonuje się za każdym razem coraz mniej razy.
Tutaj również jest O(n^2) operacji!
Dlaczego? Dla tablicy 3-elementowej ilość operacji wyniesie 3 (pierwszy raz)+2 (druga pętla, j zaczyna się od 1)+1 (ostatni

obrót).
Dla 4-el wyniesie 4+3+2+1 operacji.
Dla n-el wyniesie n+(n-1)+...+3+2+1 = (n*(n+1))/2 operacji (suma ciągu arytmetycznego). Czyli złożonośc algorytmu to

T(n*(n+1)/2)! Teraz pomijamy nieznaczące wyrazy i otrzymujemy O(n^2).

A co z przypisaniami znajdującymi się wewnątrz ifa?

Ogólnie jeśli wykonujesz jakąś czynność pewną ilość razy zależną od wielkości wejścia złożoność wynosi O(n). A jeśli

wykonujesz czynność o złożoności O(n) n razy, masz zlożoność O(n^2)
Złożoność (N3) analogicznie - wykonywanie czynności O(n2) n razy.
Złożoności log(n) i n*log(n) pominę bo z tego co widzę jeszcze ich nie macie a są trochę bardziej skomplikowane.

Zaczynam to powoli rozumieć, choć w dalszym ciągu pozostają pewne niejasności ale wydaje mi się że bez najmniejszego problemu będziesz w stanie je rozwiać. Co do złożoności log(n) i n*log(n) to pojawiają się one i na wykładach i na ćwiczeniach ale nie wymagał od nas liczenia tego typy złożoności ale mamy wiedzieć że np: wyszukiwanie binarne ma złożoność log2n.

I wreszcie...

for i:=1 to n-1 do
   for j = 1 to i+1 do
       x:= x+1;

To powinieneś wiedzieć, prawie dokładnie takie same przykłady omawiałem :>

Pierwsza pętla wykonuje się n-1 razy a druga wykonuje się dla n = 5, 2+3+...+(n-1)+n, czyli z wzoru na sumę mamy (n*(n+1))/2 = n2 + n / 2, czyli klasa O(n2) ?

for i:=**1** to n do // tutaj miało być 1
begin
  j:=1;
    while j < n do
      j:=j+1;
end;

Porównaj z poprzednim, jest wbrew pozorom bardzo podobny.

Pierwsza pętla wykonuje się n razy, druga wykonuje się n-1 razy. Czyli dla n=5 druga pętla wykona się zawsze 4 razy, z tego wynika że złożoność to n*(n-1)? czyli n2-n, klasa O(n2) ? Do tego mam odpowiedź bo mieliśmy je obliczyć, odpowiedź to n^2, więc się nie zgadza z moimi obliczeniami. Zastanawiam się co zrobić z tym przypisaniem? Gdybym je dodał to miałbym n*(n-1+1) i złożoność wtedy wynosiła

by n^2.

for i:=1 to n do
   if x > 3 then
     for j:=1 to n do
        for k:=5 to n do
           x:=x+1;
   else
       for j:=1 to n do
          x:=x+1;
 

Coś kręcisz, x nie jest nigdzie zadeklarowany. Ale ok, zakładamy że x jest parametrem funkcji.
No więc liczysz zawsze złożoność w najgorszym możliwym przypadku. jeśli x > 3 to złożoność instrukcji warunkowej wynosi

(ile, hm?), a jeśli x <= 3 to wynosi tylko (no?).
A jako że instrukcja warunkowa jest wykonywana zawsze n razy, złożoność całego algorytmu wynosi (* no właśnie?*).

W najgorszym przypadku czyli złożoność pesymistyczna? Jeśli x > 3 to złożoność instrukcji warunkowej wynosi n*(n-4) = (n2) - 4n , klasa O(n2) a jeśli x <= 3 to złożoność wynosi n-1 i jest klasy O(n) ? Czyli złożoność całego algorytmu to O(n3) lub O (n2)? Jako wynik mam podać złożoność obliczeniową dokładną pesymistyczną i optymistyczną ale nie jestem pewien.

Rozpisałem się strasznie, mam nadzieję że chociaż trochę pomogłem i nie namieszałem (czas iść spać). Pozdrawiam...

To fakt rozpisałeś się, aż dziw że Ci się chciało i za to oczywiście wielkie Ci dzięki bo to co napisałeś bardzo mi pomogło, wytłumaczyłeś to o wiele lepiej niż nasz "wspaniały" profesor. Mam jeszcze parę wątpliwości ale zapytałem o nie wyżej. Mam nadzieje że nie napisałem jakiś głupot i nie zmarnowałem Twojego czasu, starałem się korzystać po części z notatek z ćwiczeń. Jeszcze raz wielkie dzięki.

0

W tym miejscu już się zgubiłem, pętla ma złożoność n/10 to rozumiem ale co z przypisaniem 0 i zwracaniem wartości ? Nie bierzemy ich pod uwagę czy to nie istotne? Pytam o to bo nasz prowadzący wymaga podania dokładnego wzoru na złożoność, podanie samej klasy O(n) nie wystarczy a biorąc pod uwagę fakt że mamy system binarny jeżeli chodzi o ocenianie ( albo jest źle albo jest dobrze ) to nie podanie wzoru jest równoznaczne z nie zrobieniem zadania. Szczerze mówiąc to wzór jest dla niego najistotniejszy.

O(n) to rząd wielkości (asymptotyczne tempo wzrostu). T(n) to dokładna ilość działań jakie musi wykonać algorytm (tzw. exact complexity). Dziwne że ktoś go wymaga bo

  1. jest w sumie do niczego w praktyce nie przydatny
  2. często nie istnieje w przypadku ogólnym (dla algorytmów sortowania na przykład)
  3. jest bardzo nieścisły (Czy zwrócenie wartości to operacja? Skoro a = 2 to jedna operacja to czy a += 2 to jedna operacja? A a = a + 2? Pętla for wykonuje sporo działań (inkrementacja zmiennej, sprawdzenie mniejszości, przypisanie na początku) - jest pomijana w obliczeniach)
    3.1) chyba że pojęcie operacji zostanie zdefiniowane - na przykład w algorytmie sumowania jest to ilość dodawań, sortowania - porównań. Wtedy taka notacja zaczyna mieć sens (do porównywania czynników stałych).
  4. dokładna złożoność często zależy od implementacji a nie od algorytmu (można ten sam algorytm zapisać za pomocą większej/mniejszej ilości operacji prymitywnych)

Dla ścisłości algorytm ma złożoność

T(n) = n/10 + 2 dla n będącego wielokrotnością 10 // tak to się poprawnie zapisuje, rozpędziłem się z notacją T(...)
T(n) = floor(n/10) + 3 dla innego n

Można w uproszczeniu napisać że T(n) = n/10 + 2.

Jeśli dobrze zrozumiałem, ndodawanie ( pierwsza pętla ma złożoność n) ndodawanie i odejmowanie ( druga pętla ma złożoność 2n ) i do tego przypisanie 1 to O(1), dzielenie x/5 to O(1), zwracanie wartości to też O(1) czyli w sumie mamy 3n+3 i klasa O(n) tak?

Tak, dokładną złożoność można opisać jako T(n)=3n+3, chociaż patrz punkt 3. powyżej.
Klasa O(n) oczywiście.

Tutaj pytanie takie samo jak w poprzednim przykładzie O(n2) czy O(n2 + 2) ?

O(n2) (a nawet Θ(n2)) - ponieważ funkcja jest rzędu n^2
Ale jeśli wymagany jest dokładniejszy wzór, wtedy możesz podać T(n)=n^2 + 2

A co z przypisaniami znajdującymi się wewnątrz ifa?

Patrz punkt 2. w liście problemów z T(n) - algorytmy sortowania nie mają dokładnej złożoności - dlatego że jeśli dane są na wejściu posortowane od razu, może się wykonać tylko na przykład 2n + 4 operacji, a jeśli są zupełnie pomieszane albo posortowane odwrotnie, wykona się dajmy na to n^2 + log(n) + 3 operacji. I jak to zapisać wzorem?
Można najwyżej policzyć optymistyczną i pesymistyczną złożoność.

Zaczynam to powoli rozumieć, choć w dalszym ciągu pozostają pewne niejasności ale wydaje mi się że bez najmniejszego problemu będziesz w stanie je rozwiać. Co do złożoności log(n) i n*log(n) to pojawiają się one i na wykładach i na ćwiczeniach ale nie wymagał od nas liczenia tego typy złożoności ale mamy wiedzieć że np: wyszukiwanie binarne ma złożoność log2n.

No widzisz, log2(n) a nie jakieś 4log2(n) + 17 :>
Taka intuicja - jeśli dzielisz problem na części to prawie zawsze w złożoności prawdopodobnie pojawi się logarytm.
Na przykład to wyszukiwanie binarne - dzielisz tablicę na 2 części, odrzucasz od razu jedną i rozwiązujesz problem dla drugiej. Czyli z tablicy 1024 elementowej najpierw robi się 512 elementowa, później 256 el, 128, 64, 32, 16, 8, 4, wreszcie 2 i w końcu przypadek końcowy, zostaje Ci 1 element który albo jest rozwiązaniem albo rozwiązania nie ma. Złożoność = n
log2(n)
Albo merge sort - dzielisz tablicę na 2 części, sortujesz podtablice rekurencyjnie i łączysz wyniki (w czasie O(n)). Złożoność = n*log2(n).

Pierwsza pętla wykonuje się n-1 razy a druga wykonuje się dla n = 5, 2+3+...+(n-1)+n, czyli z wzoru na sumę mamy (n*(n+1))/2 = n2 + n / 2, czyli klasa O(n2) ?

Dokładnie.

Pierwsza pętla wykonuje się n razy, druga wykonuje się n-1 razy. Czyli dla n=5 druga pętla wykona się zawsze 4 razy, z tego wynika że złożoność to n*(n-1)? czyli n2-n, klasa O(n2) ? Do tego mam odpowiedź bo mieliśmy je obliczyć, odpowiedź to n2, więc się nie zgadza z moimi obliczeniami. Zastanawiam się co zrobić z tym przypisaniem? Gdybym je dodał to miałbym n*(n-1+1) i złożoność wtedy wynosiłaby n2.

klasa O(n^2) ? Do tego mam odpowiedź bo mieliśmy je obliczyć, odpowiedź to n^2, więc się nie zgadza z moimi obliczeniami. - jak dla mnie się zgadza, n2 == n2 chyba że się pomyliłeś przy pisaniu.
Ale tak, asymptotyczne tempo wzrostu = O(n^2).

W najgorszym przypadku czyli złożoność pesymistyczna? Jeśli x > 3 to złożoność instrukcji warunkowej wynosi n*(n-4) = (n2) - 4n , klasa O(n2) a jeśli x <= 3 to złożoność wynosi n-1 i jest klasy O(n) ? Czyli złożoność całego algorytmu to O(n3) lub O (n2)? Jako wynik mam podać złożoność obliczeniową dokładną pesymistyczną i optymistyczną ale nie jestem pewien.

Cały czas zakładałem że liczysz rząd wielkości, wtedy najważniejsza jest złożoność pesymistyczna (pa przykład QuickSort mimo że praktycznie jest bardzo szybki ma formalnie złożoność O(n^2) ponieważ dla pesymistycznego przypadku będzie się tak właśnie wykonywał).
Resztę dobrze wyliczyłeś, optymistycznie będzie O(n2) a pesymistycznie O(n3).
Jeśli zależy Ci na dokładnym wyniku to optymistycznie n2 a pesymistycznie nn(n-4) = n3 - 4*n^2

Jeszcze jedno, dość ważne - to co piszę jest zgodne z ustaloną obecnie nomenklaturą (oprócz tej wpadki z zapisem T(f(n)) i chyba tyle), ale jeśli wyraźnie różni się od tego co mówi prowadzący, nie ma się co kłócić. Lepiej dostosować się do dziwnych wymagań niż później mieć problemy. Zresztą przed wydaniem Introduction to Algorithms (w 1990 roku :D ) nie było zupełnej zgody co do oznaczeń więc prowadzący może mieć po prostu wiedzę ze starych źródeł.

0
Tezcatlipoca napisał(a)

O(n) to rząd wielkości (asymptotyczne tempo wzrostu). T(n) to dokładna ilość działań jakie musi wykonać algorytm (tzw. exact complexity). Dziwne że ktoś go wymaga bo

  1. jest w sumie do niczego w praktyce nie przydatny
  2. często nie istnieje w przypadku ogólnym (dla algorytmów sortowania na przykład)
  3. jest bardzo nieścisły (Czy zwrócenie wartości to operacja? Skoro a = 2 to jedna operacja to czy a += 2 to jedna operacja? A a = a + 2? Pętla for wykonuje sporo działań (inkrementacja zmiennej, sprawdzenie mniejszości, przypisanie na początku) - jest pomijana w obliczeniach)
    3.1) chyba że pojęcie operacji zostanie zdefiniowane - na przykład w algorytmie sumowania jest to ilość dodawań, sortowania - porównań. Wtedy taka notacja zaczyna mieć sens (do porównywania czynników stałych).
  4. dokładna złożoność często zależy od implementacji a nie od algorytmu (można ten sam algorytm zapisać za pomocą większej/mniejszej ilości operacji prymitywnych)

Dla ścisłości algorytm ma złożoność

T(n) = n/10 + 2 dla n będącego wielokrotnością 10 // tak to się poprawnie zapisuje, rozpędziłem się z notacją T(...)
T(n) = floor(n/10) + 3 dla innego n

Można w uproszczeniu napisać że T(n) = n/10 + 2.

Sam się nad tym zastanawiałem, głównie ze względu na to że sam prowadzący traktuje to dość luźno, a dokładniej raz przypisanie jest brane pod uwagę a innym razem już nie, co oczywiście wprowadza bardzo dużo zamieszania. Niestety nic nie mogę na to poradzić, on wymaga, ja muszę umieć.

Patrz punkt 2. w liście problemów z T(n) - algorytmy sortowania nie mają dokładnej złożoności - dlatego że jeśli dane są na wejściu posortowane od razu, może się wykonać tylko na przykład 2n + 4 operacji, a jeśli są zupełnie pomieszane albo posortowane odwrotnie, wykona się dajmy na to n^2 + log(n) + 3 operacji. I jak to zapisać wzorem?
Można najwyżej policzyć optymistyczną i pesymistyczną złożoność.

No tak teraz rozumiem.

klasa O(n^2) ? Do tego mam odpowiedź bo mieliśmy je obliczyć, odpowiedź to n^2, więc się nie zgadza z moimi obliczeniami. - jak dla mnie się zgadza, n2 == n2 chyba że się pomyliłeś przy pisaniu.
Ale tak, asymptotyczne tempo wzrostu = O(n^2).

Miałem na myśli to że gdy nie uwzględnię przypisania na początku to złożoność będzie inna (n-1)*(n).

Cały czas zakładałem że liczysz rząd wielkości, wtedy najważniejsza jest złożoność pesymistyczna (pa przykład QuickSort mimo że praktycznie jest bardzo szybki ma formalnie złożoność O(n^2) ponieważ dla pesymistycznego przypadku będzie się tak właśnie wykonywał).
Resztę dobrze wyliczyłeś, optymistycznie będzie O(n2) a pesymistycznie O(n3).
Jeśli zależy Ci na dokładnym wyniku to optymistycznie n2 a pesymistycznie nn(n-4) = n3 - 4*n^2

Od razu mi ulżyło, teraz wszystko zaczyna się składać w jedną całość.

</quote>

Jeszcze jedno, dość ważne - to co piszę jest zgodne z ustaloną obecnie nomenklaturą (oprócz tej wpadki z zapisem T(f(n)) i chyba tyle), ale jeśli wyraźnie różni się od tego co mówi prowadzący, nie ma się co kłócić. Lepiej dostosować się do dziwnych wymagań niż później mieć problemy. Zresztą przed wydaniem Introduction to Algorithms (w 1990 roku :D ) nie było zupełnej zgody co do oznaczeń więc prowadzący może mieć po prostu wiedzę ze starych źródeł.</quote>

Tak, zgadza się ale najważniejsze że zrozumiałem a z takimi szczegółami jak sposób zapisu i wymagania prowadzącego sobie jakoś poradzę.
Pozostaje ładnie podziękować i spędzić dobrze resztę jakże pięknego weekendu.
Pozdrawiam.

0

Wie ktoś jak się oblicza w takich przypadkach?badzo proszę o pomoc bo muszę sie tego nauczyc a nie rozumiem;/

0

Ja również proszę o pomoc , przykłady tego typu co są wyżej rozumiem ale mam problem ze zrozumieniem takich :

SweetStuff wcale nie miał łatwiejszych przykładów.

Nie wiem jak określić złożoność gdy jest petla z operatorem dekrementacjii i

Jeśli chodzi o ilość wykonań pętli, to przecież od n do 1 jest dokładnie tyle samo do od 1 do n...

for (i=n; i>=1; i--)
        for (j=i; j<=n; j++)
      {
          ...
      }

Dokładna ilość powtórzeń wynosi tutaj 1 + 2 + 3 + ... + n = (1+n)n/2 (dlaczego? przeanalizuj ile razy operacje wewnątrz pętli wykonają dla n == 1, n == 2, n == 3)
Złożoność rzędu O(n^2).

0
for (i=n; i>1; i--)
       for (j=1; j<n; j++)
          O(1);

(n-1)(n-1) = n2 - 2n + 1, klasa:O(n2)

for (i=n; i>1; i--)
        for (j=i; j<n; j++)
             O(3);

Nie rozumiem jeszcze czym się różni ten Algorytm od wcześniejszego co oznacza O(3)

No popatrz, ja też nie rozumiem... Ale pewnie chodzi o to że O(3) symbolizuje 'złożoność' O(3) czyli 3 operacje (na przykład a++; b++; c++;)

Cóż, niestety, usunąłeś (jakieś 2 minuty temu, ale sobie moment wybrałeś...) swoje posty więc nie wiem na co jeszcze mógłbym odpowiedzieć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1