You are on page 1of 69

Algorytmy i struktury danych

- wykład

1
Organizacja
Terminarz zjazdów –
II semestr 2007/08 Algorytmy i struktury danych

E 60= 15L + 15Cw + 30W

EGZAMIN
  ☺

Wymagania:
Programowanie: C, Pascal ???
2
Plan zajęć

Podstawowe pojęcia algorytmiki.


Metody analizy: poprawności, skończoności, złoŜoności
obliczeniowej, efektywności.
Rekurencja.
Struktury danych – lista(tablica), kolejka, stos, drzewo.
Algorytmy: metody zapisu algorytmów, podstawowe
algorytmy, wyszukiwanie, sortowanie.

3
Literatura
Podstawowa:
Cormem TH., Leiserson CE., Rivest R.L., Wprowadzenie do algorytmów, WNT,
W-wa, 1997;
Wirth N., Algorytmy + struktury danych = program, W-wa, 1989;

Uzupełniająca:
Drozdek A., Simon D.L., Struktury danych w języku C, WNT, W-wa, 1996;
Sedgewick R., Algorytmy w C++, RM, W-wa, 1999;
Banachowski L., Diks K., Rytter W., Algorytmy i struktury danych, WNT, W-wa,
1996
http://www.algorytm.org/index.php
http://programex.risp.pl/?strona=main
http://wazniak.mimuw.edu.pl/
4
http://www.algorytm.org/
Podstawowe zasady analizy
algorytmów*

Analiza algorytmów – dział informatyki, zajmujący się


szukaniem najlepszych algorytmów dla zadań komputerowych.

Czy dany problem moŜe być rozwiązany na komputerze w


dostępnym czasie i pamięci?
Czy istnieje lepszy algorytm od rozwaŜanego?
Jak uzasadnić, Ŝe stosując dany algorytm, rozwiąŜe się
zamierzone zadanie?
5
* Banachowski i inni, Algorytmy i struktury danych, WNT, W-wa, 1996
Algorytm*
Algorytm moŜna rozumieć jako skończony ciąg lub zbiór
reguł, które aplikuje się na zadanej liczbie danych,
pozwalający rozwiązywać zbliŜone do siebie, powtarzające
się klasy problemów.

NWD Euklidesa,
Podział kąta na dwie równe części za pomocą cyrkla i
linijki

6
* Banachowski i inni, Algorytmy i struktury danych, WNT, W-wa, 1996
Algorytm
Nie kaŜda metoda, nie kaŜdy schemat jest algorytmem.
Przyjmuje się, Ŝe algorytm ma wyraźnie określony
początek (start), precyzyjnie określoną kolejność
wykonywania działań, wyróŜniony koniec.

Musi być zrozumiały dla określonego wykonawcy.

7
Schemat przetwarzania danych
C – zbiór wszystkich moŜliwych zestawów danych wejściowych

Dane asercja
wejściowe
początkowa
P(c) –
Funkcja określająca Algorytm – końcowa
warunki, które muszą przetwarzanie
zostać spełnione danych
przez zestaw danych c,
c ∈ C
Q(d)
Dane
wyjściowe
D – zbiór wszystkich moŜliwych zestawów danych wyjściowych 8
Cechy algorytmu
Poprawność  !!!
Określoność  jednoznaczność określeń.
Jednoznaczność  deterministyczny, w kaŜdym przypadku
jego zastosowania, dla tych samych danych uzyskamy ten sam wynik .

Skończoność  skończona liczba kroków.


9
Przykład – algorytm Euklidesa
{Dane: m, n ∈ N, nie równe jednocześnie 0}
{Wyniki: d = nwd(m, n)}
{Zmienne pomocnicze: liczby całkowite a i b}

a := m; b := n
dopóki b ≠ 0, wykonuj C = N × N+
(a, b) = (b, a % b) D= N+
d := a
Funkcja P określa wymóg, aby danymi wejściowymi były dwie liczby
nieujemne, nie równe jednocześnie zeru.
Funkcja Q określa wymóg, aby danymi wyjściowymi była liczba
będąca największym wspólnym dzielnikiem liczb podanych na
wejściu. 10
Zapis algorytmu
Siec działań  Opis algorytmu przy pomocy rysunku.

d:=a

WE/WYJ

B<>0

START/STOP
11
Przykład
START
STAN
POCZĄTKOWY

a=m
b=n
pętla

INSTRUKCJE
T c=a/b
a=b
=0
b!

b=c
WARUNEK
N PĘTLI

d=a STOP
12
Zapis algorytmu
- pseudokod
Opis algorytmu przy pomocy umownych wyraŜeń i
poleceń, zbliŜonych do wyraŜeń i poleceń języków
programowania, operujących jednak na wyŜszym,
niezaleŜnym od składni, bibliotek i platformy docelowej
języka, poziomie.

START: i0
WARUNEK: jeśli (i+1)2>n, to przejdź do KONIEC
ii+1;
przejdź do WARUNEK
KONIEC: qi 13
Zapis algorytmu - program
int nwd(int m, int n)
{
int a, b,c;
a=m; b=n;
Opis algorytmu w while (b!=0)
konkretnym języku {
c = a % b; // mod  pascal
programowania
a = b;
b = c;
}
return a;
}
int main()
{
int d ;
d = nwd (45 ,12); 14
}
Instrukcja iteracyjna - pętla
typu „for”
Instrukcje iteracyjna "dla" stosuje się w celu
wykonania pewnej grupy instrukcji w przypadku, gdy
liczba powtórzeń jest z góry znana.
i=k
for(i=k;i<p;i++)
{ instrukacja2; } i++
instrukcja3;
T
for(i=k;i>p;i--) p instrukcja2
i<
{instrukcja2;}
N
instrukcja3;
instrukcja3 15
Instrukcja iteracyjna – pętla
„while/do while”
instrukcja1 instrukcja1
while (warunek) do
{ inst.1 {
Instrukcja2; Instrukcja2;
} }while (warunek);
Instrukcja3; Instrukcja1;

T
ek

inst.2
un
ar
w

N
inst.3 16
Warunek - C
== a równe b

!= a róŜne b

> a>b

>= a>=b

<= a<=b

< a<b
17
Instrukcje rozgałęzione – „if”
instrukcja1;
If (wyrazenie) Instrukcja1
instrukcja2;
Instrukcja3;
P

nie
Instrukcja2

ze
ra
wy

Instrukcja3
18
Instrukcje rozgałęzione
– „if –else”
instrukcja1;
If (wyrazenie) Instrukcja1
instrukcja2;
else
P

nie
Instrukcja3; F Instrukcja2

ze
Instrukcja3

ra
Instrukcja4;

wy
Instrukcja4
19
Instrukcje rozgałęzione
– „if –else”
instrukcja1;
If (wyrazenie1)
instrukcja2;
else if (wyrazenie2)
Instrukcja3;
else if (wyrazenie3)
Instrukcja4;
else
Instrukcja5; 20
WyraŜenia logiczne
- połączenie warunków

|| - lub  OR
5==5 || 5==9  prawda
&& - i  AND

5 >8 || 5 < 2  fałsz

5==5 && 4==4  prawda

5==3 && 4==4  fałsz


21
Pobieranie danych

int i; //integer;
printf(”podaj element”);
float f;//float
scanf(”%d”,&i);

printf(”%d”,i);  wypisz
scanf(”%d”,&i);  wpisz
printf(”podaj element %d”,i);
scanf(”%f”,&f);
printf(”%f”,f);
scanf(”%f”,&f);
22
Typ tablicowy
int tab[10];
float tab[5];
int tab[]={1,4,6,-9,10};

tab[0]  pierwszy element


tab[1]  drugi element
tab[9]  dziesiętny element

scanf(”%d”,&tab[2]);
23
printf(”%d”, tab[2]);
ZłoŜoność czasowa
Cecha tylko algorytmu jako metody rozwiązywania problemu.
NiezaleŜna od:

komputera, Jednostka złoŜoności


czasowej = wykonanie
języka programowania, jednej operacji
dominującej
sposobu kodowania
OPERACJE DOMINUJĄCE – których liczba jest
proporcjonalna do liczby wykonań wszystkich operacji
jednostkowych w dowolnej realizacji algorytmu 24
ZłoŜoność pesymistyczna
a oczekiwana*
ZłoŜoność obliczeniową algorytmu jest funkcją rozmiaru
danych wejściowych n

ZłoŜoność pesymistyczna  liczba zasobów


komputera przy „najgorszych danych wejściowych”.
ZłoŜoność oczekiwana  liczba zasobów przy
„typowych danych wejściowych”.

25
* Banachowski i inni, Algorytmy i struktury danych, WNT, W-wa, 1996
Pesymistyczna i oczekiwana
złoŜoność czasowa algorytmu*
W(n)= sup {t(c): c ∈ C}
A(n) = ∑ kp
k ≥0
nk

t(c) – liczba operacji dominujących dla zestawu danych c,


C – zbiór wszystkich moŜliwych danych wejściowych,
pnk – rozkład prawdopodobieństwa zmiennej losowej Xn, tzn.
prawdopodobieństwo, Ŝe dal danych rozmiaru n algorytm
wykona k operacji dominujących (k>=0).
26
* Banachowski i inni, Algorytmy i struktury danych, WNT, W-wa, 1996
Przykład
Fragment kodu programu:

START
Rozmiar danych wejściowych: n = N+1
j=1;
Operacja dominująca: L[j] ?? a
L[N+1]=a;
Pesymistyczna złoŜoność czasowa: n+1
while(L[j]!=a)
{
j=j+1;
}
p=j;
END 27
Przykład
Fragment kodu programu:

START
Oczekiwana złoŜoność czasowa:
j=1;
zał.: prawdopodobieństwo znalezienia a na
L[N+1]=a; kaŜdym z n moŜliwych miejsc jest takie
samo i wiadomo, Ŝe a jest w L.
while(L[j]!=a)
1
{ pnk = , dla k = 1,2,..., n
n
n
j=j+1; 1 n
A(n) = ∑ kpnk = ∑ k =
} k =1 n k =1
1 n(n + 1) n + 1
p=j; = =
n 2 2
END 28
Analiza funkcji
F(n)=n2+100*n+log10n+1000
N F(N) N2 100*N log10N 1000
1 1101 0,1 % 9% 0 91 %

10 2101 4,8 % 48 % 0,05 % 48 %

102 21002 48 % 48 % 0,001 % 4,8 %

103 1101003 91 % 9% 0,0003 % 0,09 %

104 … 99 % 1% 0% 0,001 %

105 … 99,99% 0,1 % 0% 0%

29
Notacja „O” – notacja asymptotyczna
f(n) jest O (g(n)), jeśli istnieją liczby dodatnie
c i N takie, Ŝe f(n) < c g(n) dla wszystkich n >= N.

f(n) = n2 + 100*n + log10 n + 1000

f(n) ~ n2 + 100*n + O(log10 n)

f(n) ~ O(n2)

30
Wykres
100,0000%
90,0000%
80,0000%
70,0000%
60,0000% n*n
100*n
50,0000%
log10
40,0000%
1000
30,0000%
20,0000%
10,0000%
0,0000%

0
00
0
00
0
10
1

00
00
10

00
10

00
10

10

10
31
Przykład

3500000

3000000

2500000

2000000 x2+bx+c
1500000 3x2

1000000

500000

0
1 10 100 200 300 500 600 700 800 900 1000

32
Cechy notacji „O”:
Jeśli f(n) jest O(g(n)) i g(n) jest O(h(n)), to
f(n) jest O(h(n)).

Jeśli f(n) jest O(h(n)) i g(n) jest O(h(n)), to


f(n)+g(n) jest O(h(n)).

Funkcja ank jest O(nk).

Funkcja nk jest O(nk+j) dla dowolnego dodatniego j.


33
Z tych wszystkich własności wynika, ze dowolny
O” dla n podniesionego do
wielomian jest typu „O
najwyŜszej w nim potęgi, czyli

f(n) = aknk + ak-1 nk-1 + ..... + a1n +a0 jest O(nk)

(jest teŜ oczywiście O(nk+j) dla dowolnego


dodatniego j).

34
jeśli f(n)=c g(n), to f(n) jest O(g(n)),

funkcja logan jest O(logbn) dla dowolnych a, b >1,

logan jest O(log2n) dla dowolnego dodatniego a.

35
Przykład
mamy dwa algorytmy rozwiązujące pewien problem,
wykonywana przez nie liczba operacji to odpowiednio:
108n i 10n2.
Pierwsza funkcja jest O(n), druga O(n2).

Opierając się na informacji dostarczonej przez notacje „wielkie O”


odrzucilibyśmy drugi algorytm poniewaŜ funkcja kosztu rośnie zbyt
szybko.

ale dla n<107 drugi algorytm wykonuje mniej operacji niŜ pierwszy.
Istotna jest więc tez stała (108), która w tym przypadku jest zbyt duŜa
aby notacja była znacząca.
36
Algorytmy moŜna klasyfikować ze względu na złoŜoność czasową
lub pamięciową. W związku z tym wyróŜniamy wiele klas algorytmów.

Algorytm stały: czas wykonania pozostaje taki sam niezaleŜnie od


ilości przetwarzanych elementów.
Algorytm kwadratowy: czas wykonania wynosi O(n2).
Algorytm logarytmiczny: czas wykonania wynosi O(log n)
itd. itd.

37
Analiza złoŜoności - silnia
• 0! =1;
• n! = n*(n-1)!, n>=1.

• T(0)=tc & T(n)=tc+T(n-1), dla n>=1

38
• T(n)=tc+T(n-1);
• T(n-1)=tc+T(n-2);
• … T(n)=(n+1)tc

• T(1)=tc+T(0);
• T(0)=tc

39
Przykład zerowanie
elementów tablicy
ta - przypisanie
i=0;
while(i<n)
1 tc - porównanie

{
j=0;
while(j<=i)
{
A tab[i][j]=0;
j=j+1;
0 1 }
i=i+1;
}
40
N i
T (n) = tc + t a + ∑ (2t a + tc + t c + ∑ (tc + 2t a ))
i =1 j =1

Pętla wewnętrzna A

Pętla zewnętrzna

N
T (n) = tc + t a + ∑ (2t a + 2tc + i (tc + 2t a ))
i =1

41
N
T (n) = t c + t a + ∑ (2t a + 2t c + i (tc + 2t a ))
i =1

N ( N + 1)
1 + 2 + 3 + ... + N =
2

N
T (n) = tc + t a + ∑ (2t a + 2tc + i (tc + 2t a ))
i =1

2
N
T (n) = t a (1 + 3N + N 2 ) + tc (1 + 2.5tc + )
2 42
Wyznaczanie złoŜoności dla
najgorszego przypadku
Instrukcja:
Przypisanie  O(1),
Wejście do funkcji/procedury  O(1),
Wyjście z funkcji/procedury  O(1),
Pętla  suma czasów wykonania kaŜdej pętli O(Σ)

43
Analiza procedury sumowania

int i =0;
int suma=0;
for (i=0; i<n; i++) sum+=a[i];

pętla powtarza się n razy,

podczas kaŜdego jej przebiegu realizuje 2 przypisania:


aktualizujące zmienną „sum” i zmianę wartości zmiennej „i”.

Mamy zatem 2n przypisań podczas całego wykonania pętli;

asymptotyczna złoŜoność wynosi O(n). 44


for (i=0; i<n; i++)
for (j=1, sum=a[0]; j<=i; j++)
sum+=a[j];
Pętla zewnętrzna powtarza się n razy:
-wewnętrzna pętla,
-instrukcja przypisania wartości zmiennym „i”, „ j”, „ sum”.

Pętla wewnętrzna wykonuje się j razy {1,...,n-1}, a na kaŜdą


iteracje przypadają dwa przypisania:
-dla „sum”,
-dla „j”.
1+3*n+2*(1+2+…+n-1)=1+3n+2*(n(n-1)/2)n2 45
najdłuŜsza podtablice zawierająca
liczby uporządkowane rosnąco

for (i=0; len=1; i<n-1; i++)


{
for (ii=iii=k=i; k<n-1 && a[k]<a[k+1]; k++,iii++);
if(len < iii-ii+1) len=iii-ii+1;
}
Jeśli liczby w tablicy są uporządkowane malejąco, to pętla zewnętrzna
wykonuje się n-1 razy, a w kaŜdym jej przebiegu pętla wewnętrzna
wykona się tylko raz. ZłoŜoność algorytmu jest więc O(n).

Jeśli liczby w tablicy są uporządkowane rosnąco, to pętla zewnętrzna


wykonuje się n-1 razy, a w kaŜdym jej przebiegu pętla wewnętrzna
wykona się i razy dla i e {1,...,n-1}. ZłoŜoność algorytmu jest więc O(n2). 46
Poprawność algorytmu
– metody sprawdzania
W celu wykazania, ze program jest zgodny ze
specyfikacja, rozwaŜa się poszczególne kroki programu.
Krokiem moŜe być dowolna jednostka w programie: blok,
pętla, funkcja, ale takŜe cały program.

Instrukcje elementarne  a=b: //a>=0;a=a+1;a>=1;

Sekwencje instrukcji elementarnych

Funkcje

47
ZłoŜoność obliczeniowa
algorytmu
czas działania,
ilość potrzebnej pamięci.
Rozmiar  liczba pojedynczych danych wejściowych.
Sortowanie: liczba elementów w ciągu wejściowym

ZłoŜoność pamięciowa: słowo pamięci maszyny.


ZłoŜoność czasowa: ???

48
SORTOWANIE
DANE WEJŚCIOWE: tab[n]

i=0, min=tab[0]
i++

T T
n min>tab[i]
i< min=tab[i]

49
SORTOWANIE
- sortowanie przez wstawianie
DANE WEJŚCIOWE: tab[n]
tab[j] – bieŜący element,
tab[j+1…n] – karta ze stołu
tab[1…j-1] – karta w ręce

50
Pseudokod
for j  2 to length(tab)
do k  tab[j]
ij-1
while i>0 and tab[i] > k
do tab[i+1] tab[i]
i i-1 tab[1…j-1]  karty w ręce

tab[i+1]k tab[j+1…n]  karty na stole

Indeks j przesuwamy od lewej do prawej 

51
Analiza sortowania przez
wstawianie
Czas działania sortowania przez wstawienie zaleŜy od:
 danych wejściowych  n;
 stopień posortowania danych wejściowych;

Czas działania algorytmu jest wyraŜony poprzez liczbę


wykonania prostych operacji.

ZałoŜenie:
- elementarna operacja jest maszynowo niezaleŜna
- wykonanie jednego wiersza programu wymaga stałego
czasu
52
Etapy metody „dziel i zwycięŜaj”

DZIEL: dzielimy problemu na mniejsze.


ZWYCIĘśAJ: rozwiązujemy podproblemy rekurencyjnie
POŁĄCZ: łączymy rozwiązania podproblemów, aby otrzymać

53
Algorytm sortowanie przez scalanie

 Dziel  Dzielimy n-elementów ciąg na dwa


podciągi po n/2 elementów kaŜdy.
 ZwycięŜaj  Sortujemy otrzymane
podciągi, uŜywając rekurencyjnie
sortowania przez scalanie
 Połącz  Łączymy posortowane podciągi
w jeden ciąg.

54
Operacja sortowania przez scalanie

55
Sortowanie: Podziel + scalaj

tab  tablica o długości n


Sort(tab,1,length(tab))

Zał: n jest potęgą 2

56
Rekurencja
Ustalanie warunku początkowego

Zastosowanie kroku indukcyjnego,

Funkcji silnia -> n!


n! = 1, jeśli n=0,
= n* (n-1)! jeśli n > 0.

57
Stos
początek I poziom
stosu II poziom
III poziom

 Wywołanie kolejnej funkcji wiąŜe


się z „odkładaniem” danych na stos

 Wynik działania kolejnych funkcji


wiąŜe się z „zdejmowanie” ze stosu

koniec n poziom
stosu
58
Rekurencja a iteracja

silnia(11) 10!*11 3268800*11

silnia(3) 2!*3 2*3


silnia(2) 2*1! 1*2
silnia(1) 1 1

59
Implementacja obliczania silni
int silnia(int n)
{
if (n =< 1)
START (silnia(5))
return 1; //warunek początkowy 120
else
silnia(4) return n*silnia(n-1) // 24
}
silnia(3) 6
silnia(2) 2
silnia(1) 1

60
Co lepsze??? – liczby
Fibonacciego
LICZBY FIBONACCIEGO
F(n) = n, jeśli n <2
F(n) = F(n-2)+F(n-1), jeśli n > 2

JEŚLI N<2 TO F=1


Iteracyjnie???
JEŚLI N>2 TO
F(N)=F(N-2)+F(N-1)

liczba wywołań funkcji F jest równa


2*F (n+1)-1
dla wyznaczenia wartości F(n). 61
Drzewo rekurencji dla obliczeń
liczby Fibonacciego
F(6)

F(4) F(5)
F(4)

F(2) F(3)
F(3) F(3)
F(2)

F(0) F(1) F(1) F(2) F(1) F(2)


F(1) F(2)

F(1) F(0) F(1)


F(0) F(0) F(1)
F(0)
F(1) 62
Porównanie - wywoływanie
n Metoda Metoda rekurencyjna
iteracyjna
6 15 25
10 27 177
15 42 1973
20 57 21891
25 72 242785
30 87 2692537

ZłoŜoność czasowa algorytmu rekurencyjnego ~ O(2n),


ZłoŜoność czasowa algorytmu iteracyjnego ~ O(n). 63
Pseudokod
for j  2 to length(tab)
do k  tab[j]
ij-1
while i>0 and tab[i] > k
do tab[i+1] tab[i]
i i-1 tab[1…j-1]  karty w ręce

tab[i+1]k tab[j+1…n]  karty na stole

Indeks j przesuwamy od lewej do prawej 

64
Dziel i zwycięŜaj
• (1) Dzielimy zadanie posortowania całego
ciągu na dwa podzadania: posortowania
jego lewej i prawej połowy.

• (2) Gdy obie części tworzą juŜ ciągi


uporządkowane, wtedy scalamy je
otrzymując rozwiązanie.

65
Rekurencyjne dzielenie i scalanie

Dzielenie:
74289721

72971 4872

791 47 82
27

71 9 2 7
4 7 8 2

7 1
66
Rekurencyjne dzielenie i scalanie

Scalanie: 122477789

12779 2478

179 47 28
27

17 9 2 7 8 2
4 7

7 1 O(n+m)

67
WNIOSKI

sortowanie przez wybieranie jest „łatwym”, ale „wolnym”


sposobem sortowania;
sortowanie przez scalanie jest „szybszym”, ale tez bardziej
„skomplikowanym” algorytmem.

algorytm sortowania przez wybieranie ~ O(n2),


algorytm sortowania przez scalanie ~ O(n log n).

68
• http://www.cs.ubc.ca/spider/harrison/Java/
sorting-demo.html

69

You might also like