You are on page 1of 158

Wykad ze Wstpu

do Informatyki
Rok 2004-2005

Marek Zawadowski
Wydzia Matematyki, Informatyki i Mechaniki
Uniwersytet Warszawski
3 stycznia 2005

Spis treci

1 Wstp (1/2)

2 Wprowadzenie (2 1/2)

1.1 Literatura . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Zaliczenie i egzamin . . . . . . . . . . . . . . . . . . . . . . .
1.3 Historia Informatyki . . . . . . . . . . . . . . . . . . . . . . .
2.1
2.2
2.3
2.4
2.5
2.6
2.7
2.8

Algorytm Euklidesa . . . . . . . . . . . . . . . .
Problem algorytmiczny . . . . . . . . . . . . . . .
Sortowanie liczb . . . . . . . . . . . . . . . . . . .
Analiza zoonoci algorytmu . . . . . . . . . . .
Wiee Hanoi . . . . . . . . . . . . . . . . . . . . .
Wyszukiwanie sowa w sowniku . . . . . . . . . .
Tablice rzeczywistego czasu dziaania algorytmw
Komputer od rodka . . . . . . . . . . . . . . . .

3 Jzyk Pascal (4)


3.1
3.2
3.3
3.4
3.5
3.6

Jzyki programowania wysokiego poziomu


Diagramy skadniowe . . . . . . . . . . . .
Formalna denicja jzyka imperatywnego
Zmienne . . . . . . . . . . . . . . . . . . .
Typy proste . . . . . . . . . . . . . . . . .
Typy strukturalne . . . . . . . . . . . . .
1

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.
.
.

4
4
4

. 5
. 6
. 6
. 7
. 8
. 10
. 10
. 12
.
.
.
.
.
.

14

14
14
16
17
18
20

3.7
3.8
3.9
3.10

Przegld instrukcji jzyka Pascal


Procedury . . . . . . . . . . . . .
Procedury rekurencyjne . . . . .
Poprawno programw . . . . .

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

Metoda powrotw (prb i bdw) . . . . . . . . .


Metoda 'dziel i rzd' . . . . . . . . . . . . . . . .
Sortowanie przy pomocy porwna . . . . . . . . .
Programowanie dynamiczne . . . . . . . . . . . . .
Algorytmy zachanne . . . . . . . . . . . . . . . . .
Algorytm sortowania przez kopcowanie (heapsort) .
Podsumowanie . . . . . . . . . . . . . . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

Systemy liczbowe o rnych podstawach . . . . . . .


Reprezentacja staopozycyjna liczb cakowitych . . .
Operacje arytmetyczne staopozycyjne . . . . . . . .
Reprezentacja zmiennopozycyjna liczb rzeczywistych
Arytmetyka zmiennopozycyjna . . . . . . . . . . . .
Wybrane problemy numeryczne . . . . . . . . . . . .

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

.
.
.
.
.
.

4 Podstawowe metody programowania (5)


4.1
4.2
4.3
4.4
4.5
4.6
4.7

5 Reprezentacja liczb na komputerze (2)


5.1
5.2
5.3
5.4
5.5
5.6

6 Dynamiczne struktury danych (4)


6.1
6.2
6.3
6.4
6.5

Podstawowe dynamiczne struktury danych . . . . .


Typy wskanikowe . . . . . . . . . . . . . . . . . .
Implementacja list . . . . . . . . . . . . . . . . . .
Drzewa binarnych poszukiwa (BST) . . . . . . . .
Struktury danych dla rodziny zbiorw rozcznych

7 Algorytmy grafowe (5)


7.1
7.2
7.3
7.4
7.5
7.6
7.7

Grafy i reprezentacje grafw . . . . . . . .


Skadowe spjne grafu niezorientowanego
Przeszukiwanie grafu wszerz (BFS) . . . .
Przeszukiwanie grafu w gb (DFS) . . . .
Sortowanie topologiczne . . . . . . . . . .
Silnie spjne skadowe grafu . . . . . . . .
Minimalne drzewo rozpinajce . . . . . . .

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

.
.
.
.
.
.
.
.
.
.
.
.

21
29
34
40

43

43
48
52
54
59
63
67

69

69
71
73
74
76
79

82

82
86
91
95
101

105

105
108
110
117
122
123
129

8 Zoono algorytmw (3)


8.1
8.2
8.3
8.4
8.5

Problemy decyzyjne . . . . . . . . . . . . .
Algorytmy werykujce . . . . . . . . . . .
Redukowalno problemw i problem P=NP
Problemy nieobliczalne . . . . . . . . . . . .
Metody przyblione . . . . . . . . . . . . . .

9 Rozwizywanie ukadw rwna liniowych

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

.
.
.
.
.

9.1 Mnoenie macierzy . . . . . . . . . . . . . . . . . . . . . . . .


9.2 Rozwizywanie ukadw rwna liniowych niejednorodnych
metod rozkadu LUP . . . . . . . . . . . . . . . . . . . . . .
9.3 Obliczanie rozkadu LUP . . . . . . . . . . . . . . . . . . . .
9.4 Macierze odwrotne . . . . . . . . . . . . . . . . . . . . . . . .
9.5 Wyznacznik macierzy kwadratowej . . . . . . . . . . . . . . .

133

133
134
136
138
139

146

146
146
150
154
154

Wstp (1/2)

1.1 Literatura
1. Oglne wprowadzenie: D. Harel, Rzecz o istocie informatyki
2. Algorytmy:
T.H. Cormen, C.E. Leiserson, R.L. Rivest, Introduction to Algo-

rithms (Wprowadzenie do Algorytmw)


L. Banachowski, K. Diks, W. Rytter, Algorytmy i struktury
danych
A.V. Aho, J.E. Hopcroft, J.D. Ulman, Projektowanie i analiza
algorytmow komputerowych
3. Jzyk Pascal:
M.Iglewski, J.Madey, S.Matwin, Pascal
R.K. Kott, Programowanie w jzyku Pascal

1.2 Zaliczenie i egzamin


Zaliczenie: program i kolokwium. Egzamin: pisemny, po obu semestrach.

1.3 Historia Informatyki


IV w. p.n.e. Euklides: algorytm Euklidesa (pierwszy niebanalny algorytm).

IX w n.e. Algorismus (Muhammad ibn Musa al-Kwarizmi =Muhammad

syn Musy z Kworyzmu), algorytmy dodawania odejmowania, mnoenia, i dzielenia liczb dziesitnych.

XIX w. n.e. Joseph Jaquard, maszyna tkacka sterowana algorytmem.

Charls Babbage, maszyna rnicowa do obliczania wzorw matematycznych i projekt maszyny analitycznej, mechanicznego prototypu
komputera.

1920-30 r. Alan Turing, Emil Post, John von Neuman, Kurt Gdel, Alnzo
Church, Stephen Kleene: badania pojcia funkcji obliczalnej.

1945 r. J. von Neuman, pierwszy komputer (U Pensylvenia) (?)


196- r. Informatyka staje sie now dziedzin wiedzy.
4

Wprowadzenie (2 1/2)

2.1 Algorytm Euklidesa


Dane wejciowe: dwie liczby naturalne m, n > 0.
Wynik: N W D(m, n).

Opis algorytmu. Odejmuj liczb wiksz od mniejszej a do wyrwnania


liczb.
Zapis algorytmu.
a:=m; b:=n;
dopki a<> b wykonuj {NWD(a,b)=NWD(m,n), a,b>=1}
jeli a<b to b:=b-a
w przeciwnym przypadku a:=a-b
wypisz(a)

W algorytmie uylimy nastpujcych operacji elementarnych:


1. cztery instrukcje przypisania;
2. iteracja nieograniczona (ptla while);
3. instrukcja warunkowa;
4. instrukcja wejcia wyjcia.
W nawiasach { } zapisalimy niezmiennik ptli, tzn. takie zdanie ktre
jeli jest prawdziwe przy wejciu do ptli to pozostaje prawdziwe po kadym
penym wykonaniu ptli.
Czy program robi to co chcemy? Tak:
1. Po kadym wykonaniu ptli prawdziwy jest niezmiennik ptli
N W D(a, b) = N W D(m, n), a, b 1.
2. Po wyjciu z ptli a = b. Zatem a = N W D(a, b).
3. Ptla wykonuje si co najwyej m + n 2 razy (w szczeglnoci nie
moe dziaa w nieskoczono).
Ad 1. Wystarczy pokaza, e jeli a > b to N W D(a, b) = N W D(ab, b).
W tym celu wystarczy pokaza, e liczba k dzieli a i b wiw gdy dzieli (a b)
i b.
Ad 2. Oczywiste.
Ad 3. Kade wykonanie instrukcji warunkowej zmniejsza sum a + b o
co najmniej 1. Z drugiej strony mamy a 1, b 1. Zatem instrukcja
warunkowa moe by wykonana co najwyej m + n 2 razy.
5

2.2 Problem algorytmiczny


Problem (zadanie) algorytmiczny polega na
scharakteryzowaniu wszystkich poprawnych danych wejciowych;
scharakteryzowaniu oczekiwanych wynikw jako funkcji danych wej-

ciowych.

Rozwizanie algorytmiczne polega na podaniu algorytmu tzn. takiego


opisu dziaa przy pomocy operacji elementarnych ktry zastosowany do
poprawnych danych wejciowych daje oczekiwane wyniki.

Rozrniamy wykonywanie algorytmw od dziaania twrczego.

Problemy dotyczce algorytmw:


1. Jzyk: zbir instrukcji elementarnych;
2. Rozstrzygalno: czy istnieje algorytm rozwizujcy dany problem?
3. Analiza poprawnoci: czy algorytm dziaa poprawnie, tzn. robi to co
ma robi?
4. Analiza zoonoci: czy algorytm dziaa szybko?
5. Analiza numeryczna: czy algorytm dziaa dokadnie?

2.3 Sortowanie liczb


Dane wejciowe: liczba naturalna n i cig liczb a1 , a2 , . . . , an .
Wynik: permutacja a01 , a02 , . . . , a0n cigu a1 , a2 , . . . , an taka, e a01
a02 . . . a0n .

Przykad. Dane: 2, 7, 4, 5, 1. Wynik: 1, 2, 4, 5, 7.


Jak do tego problemu podej systematycznie? Na przykad tak jak
sortujemy rozdane karty w brydu.
Zapis algorytmu (sortowanie przez wkadanie). (A[j] - j -ty element).
dla j:=2 do n wykonuj
k:=A[j];
i:=j-1;
dopki i>0 oraz A[i]>k wykonuj
A[i+1]:=A[i];

i:=i-1;
A[i+1]:=k;

Przykad.
Dane :

2
2
2
W ynik : 1

7
4
4
2

4
7
5
4

5
5
7
5

1
1
1
7

2.4 Analiza zoonoci algorytmu


Analiza zoonoci algorytmu jest to przewidywanie ile zasobw potrzeba do
wykonania algorytmu.
Zasoby:
1. pami;
2. poczenia komunikacyjne;
3. czas dziaania (dla nas najwaniejszy).
eby analizowa zoono algorytmu musimy co wiedzie o tym jak on
bdzie wykonywany przez maszyn.
My bdziemy zakada, e programy s wykonywane na maszynie o
dostpie swobodnym (RAM): tzn. instrukcje s wykonywane jedna po drugiej
(nigdy dwie na raz) i program nie moe si modykowa w trakcie dziaania.
Czas dziaania zaley od rozmiaru danych wejciowych. 5 liczb nasz algorytm sortuje szybciej ni 1000. Take dla dwch cigw rwnej dugoci
algorytm moe wykonywa rn liczb instrukcji w zalenoci od tego jak
bardzo rni si one od cigu posortowanego. Na og, czas dziaania algorytmu wyraany jest jako funkcja rozmiaru danych wyjciowych.
1. Rozmiar danych wejciowych jest to funkcja przyporzdkowujca
poprawnym danym wejciowym algorytmu liczb naturaln.
2. Czas dziaania algorytmu jest to funkcja przyporzdkowujca danym
wejciowym liczb podstawowych operacji wykonywanych przez algorytm na tych danych.
3. (Pesymistyczna, czasowa) zoono algorytmu jest to funkcja z N w
N przyporzdkowujca liczbie naturalnej n najduszy czas dziaania
algorytmu na danych o rozmiarze n.
7

Dla problemu sortowania rozmiar danych to dugo cigu.


nr
1 dla j:=2 do n wykonuj
2 k:=A[j];
3 i:=j-1;
4 dopki i>0 oraz A[i]>k wykonuj
5
A[i+1]:=A[i];
6
i:=i-1;
7 A[i+1]:=k;

czas
| n
| n-1
| n-1
| t_2+...+t_n
| (t_2-1)+...+(t_n-1)
| (t_2-1)+...+(t_n-1)
| n-1

tj - liczba wykona linii 4 przy ustalonym j .


tj - jest najwikszy gdy macierz jest uporzdkowana w porzdku malejcym, wtedy tj = j .
T (n) - zoono algorytmu.
T (n) = 3(n 1) + n + 2

n
X
j=2

(j 1) +

n
X

j1=

j=2

n(n 1) n(n + 1)
3
7
+
1 = n2 + n 4
2
2
2
2
7
To jest cigle 'za dokadnie', skadniki 2 n i 4 oraz staa 32 nie maj
wikszego znaczenia, przy duych n. To co jest wane to n2 . Mwimy, e al= 3(n 1) + n + 2

gorytm sortowania przez wkadanie ma zoono (pesymistyczn, czasow)


O(n2 ).

Notacja O(f (n)). Niech f : N N funkcja. Mwimy, e funkcja g :


N N jest (klasy) O(f (n)) (piszemy g O(f (n)) lub wrcz g = O(f (n)))
jeli istniej stae a, b R takie, e dla n > b g(n) a f (n) ('g przyjmuje
wartoci nie wiksze ni f z dokadnoci do staej').

2.5 Wiee Hanoi

B
8

Problem wie Hanoi. Przenie pojedynczo n krkw z wiey A


na wiee B uywajc wiey C tak by nigdy krek wikszy nie lea na
mniejszym.
Opis algorytmu. Aby przenie n krkw z A na B przez C
1. przenie n 1 krkw z A na C uywajc B;
2. przenie krek z A na B;
3. przenie n 1 krkw z C na B uywajc A.
Zapis algorytmu.
procedura przenies(m,X,Y,Z); {przenosi kraki z X na Y uywajc Z}
jeli m=1 to przestaw(X,Y)
w przeciwnym przypadku
przenie(m-1,X,Z,Y);
przestaw(X,Y)
przenie(m-1,Z,Y,X);
przenies(n,A,B,C) {wywoanie poczatkowe}

Przykad. n = 3. ...

Ile przestawie wykona algorytm by przestawi n krkw?


an - liczba przestawie n krkw.

Rwnanie rekurencyjne:
(

a1 = 1
an+1 = an + 1 + an = 2an + 1

Rozwizanie: an = 2n 1.
Dowd indukcyjny. Dla n = 1, 21 1 = 1 = a1 . Zamy, e an = 2n 1.
Wtedy
an+1 = 2an + 1 = 2(2n 1) + 1 = 2n+1 2 + 1 = 2n+1 1

Liczba przestawie jest proporcjonalna do iloci wszystkich operacji


wykonywanych przez algorytm. Zatem cay algorytm dziaa w czasie O(2n ).

2.6 Wyszukiwanie sowa w sowniku


Problem wyszukiwania sowa w sowniku.

Dane wejciowe: liczba naturalna n i cig sw w1 , . . . , wn uporzdkowany w porzdku leksykogracznym (alfabetycznym) oraz sowo w.
Wynik: TAK, gdy dla pewnego 1 i n, w = wi ; NIE, w przeciwnym

przypadku.

Przykad. Dane: w
~ =0 a0 ,0 ala0 ,0 b0 ,0 bela0 ,0 hela0 , w =0 bela0 . Wynik: TAK.

Ponisza procedura mem sprawdza czy sowo wystpuje w sowniku


pomidzy sowami wm1 i wm2 .
procedura mem(m1,m2);
jeli m1=m2 to
jeli w=w_m1 to wypisz('TAK')
w przeciwnym przypadku wypisz('NIE')
w przeciwnym przypadku
m3:= (m1+m2) div 2;
jeli w>w_m3 to mem(m3+1,m2)
w przeciwnym przypadku mem(m1,m3)
mem(1,n) (wywoanie pocztkowe)

Rozmiar danych: dugo cigu.


pn -liczba porwna sw dla sownika dugoci n.
Rwnanie rekurencyjne:
(

p1 = 1
p2n = pn + 1

Rozwizanie: pn log n.
Liczba porwna jest rzdu log n. Algorytm dziaa w czasie O(log n).

2.7 Tablice rzeczywistego czasu dziaania algorytmw


W poniszej tabeli przedstawiony jest rozmiar zada jakie mona rozwiza
w cigu jednej sekundy, minuty, godziny.
Zakadamy, e do wykonania operacji podstawowej potrzebna jest jedna
milisekunda (= 103 s).
10

nr

Algorytm

Zoono

A1

szukanie sowa
O(log n)
w sowniku
A2
znajdowanie
O(n)
maksimum
w tablicy
A3
sortowanie
O(n log n)
przez 'scalanie',
'kopcowanie'
A4
sortowanie
O(n2 )
przez 'wkadanie',
A5
n3
A6
Wiee Hanoi
O(2n )

Maksymalny rozmiar zadania


1 sekunda 1 minuta 1 godzina
21000
1000

6 104

3.6 106

140

4893

2 105

31

244

1897

10
9

39
15

153
21

A teraz przypumy, e zwikszymy szybko komputera 10 razy.


Ponisza tablica pokazuje o ile zwikszy si maksymalny rozmiar zadania
ktry mona rozwiza po przyspieszeniu.
nr

Algorytm

Zoono

A1

szukanie sowa
O(log n)
w sowniku
A2
znajdowanie
O(n)
maksimum
w tablicy
A3
sortowanie
O(n log n)
przez 'scalanie',
'kopcowanie'
A4
sortowanie
O(n2 )
przez 'wkadanie',
A5
n3
A6
Wiee Hanoi
O(2n )

11

Maksymalny
Maksymalny
rozmiar
rozmiar
zadania przed
zadania po
przyspieszeniem. przyspieszeniu.
s1

s10
1

s2

10 s2

s3

okoo 10 s3
dla duych n

s4

3.16 s4

s5
s7 6

2.15 s5
s6 + 3.3

2.8 Komputer od rodka


Schemat logiczny komputera
Procesor:

Pami
wewntrzna:

Arytmometr
Jednostka
sterujca

staa (ROM)
operacyjna
(RAM)

Rejestry

Magistrale komunikacyjne
Monitor
Dyski

Drukarka
Klawiatura

Sie

Procesor przetwarza informacje i steruje pozostaymi elementami sys-

temu.

Pami suy do przechowywania informacji.


Ukady wejcia-wyjcia (Dyski, Monitor, Klawiatura, Drukarka, Sie)

umoliwiaj komunikacj komputera ze wiatem zewntrznym.

Magistrale komunikacyjne cz moduy komputera.

Komputer dziaa powtarzajc cykle rozkazowe. Na jeden cykl rozkazowy


skada si wiele operacji. W pewnym przyblieniu mona je przedstawi
nastpujco:
1. pobranie kolejnego rozkazu z komrki pamici wskazywanej przez
licznik rozkazw;
2. sprawdzenie czy rozkaz wymaga pobrania danych, jeli tak, to wyznaczenie miejsc w pamici z ktrych naley pobra dane i umieszczenie
danych w rejestrach komputera;
3. wykonanie rozkazu (arytmometr);
12

4. wysanie wyniku pod waciwy adres w pamici;


5. zmiana zawartoci licznika rozkazw, tak by wskazywa kolejny rozkaz
dla procesora;
6. obsuga przerwa (o ile takie maj miejsce);
7. przejcie do kroku 1. w celu wykonania nastpnego cyklu rozkazw.
Od pomysu algorytmu do wykonania programu przez maszynie jest szereg krokw do wykonania. Pierwsze kroki s wykonywane czowieka a
nastpne przez maszyn. Mona wyszczeglni nastpujce etapy tego procesu:
1. Pomys algorytmu (czowiek);
2. Algorytm (czowiek);
3. Program w jzyku wysokiego poziomu (programista);
4. Program w jzyku adresw symbolicznych, asemblerze, (kompilacja,
maszyna);
5. Kod maszynowy (dalsza kompilacja, maszyna);
6. Wykonanie kodu na komputerze (maszyna).

13

Jzyk Pascal (4)

3.1 Jzyki programowania wysokiego poziomu


Jzyki programowania wysokiego poziomu s to sformalizowane jzyki suce
do zapisu algorytmw.
Typy jzykw programowania wysokiego poziomu:

1. imperatywne: Pascal, C, Basic, Fortran, Cobol, APL, Algol, Forth, ...


2. funkcyjne: ML, Miranda, Haskel, ...
3. programowanie w logice: Prolog.
4. programowanie zorientowane obiektowo: SmallTalk, C ++ ...
5. programowanie rwnolege: Occam, Concurrent Pascal, ...
Na opis jzyka programowania skada si:
1. Precyzyjna skadnia tzn. dokadne okrelenie co jest dopuszczalnym
programem w tym jzyku.
2. Jednoznaczna semantyka tzn. jednoznaczny opis kadego wyraenia
dozwolonego skadniowo.
(a) Semantyka operacyjna: opis stanu komputera przed i po wykonaniu instrukcji.
(b) Semantyka denotacyjna: opis funkcji przeksztacajcej dane wejciowe w dane wyjciowe.

3.2 Diagramy skadniowe


Skadni jzyka programowania mona opisywa gracznie przy pomocy diagramw skadniowych lub tekstowo przy pomocy notacji BNF. My opiszemy
skadnie jzyka Pascal gracznie.
W diagramie skadniowym obiekt deniowany wystpuje jako podpis do
rysunku deniujcego. Symbole:
1. Blok owalny


14

obejmuje symbole oznaczajce same siebie.


2. Blok prostoktny

obejmuje pojcie zdeniowane gdzie indziej.


3. Strzaka
-

wskazuje kolejno symboli w napisie zoonym.


4. Rozgazienie
PP P
q
P

oznacza alternatyw denicyjn - mona wybra dowoln ze strzaek.


Przykady
cyfra dziesitna
@
@
@
@
R 
@
R 
@





@
@
@
@
@
R
@

...

@
@
@
@
@
R 
R 
@





@
@
@
@
R
@
R
@

liczba bez znaku


6

liczba

cyfra dziesitna



@
 
R

@

R

liczba bez znaku



15

identykator

litera

litera
*



H
6 H
j
H

cyfra dziesitna

? 




3.3 Formalna denicja jzyka imperatywnego


Na tekst programu skadaj si
1. opis struktur danych, tzn. opis obiektw na ktrych dziaa algorytm;
w programie: denicje i deklaracje.
2. opis procesu obliczeniowego; w programie: instrukcje.
Czasem zawiera si to w nastpujcej 'rwnoci':
program = algorytm + struktury danych

Formaln denicja (fragmentu) jzyka Pascal mona przedstawi tak:


program




- program - identykator - ; - blok




16


- .


blok

 
- type
 6


identykator

 
- var
66
 

identykator

; 



- =

typ


- : 


- ;


typ


- ;



6

deklaracja funkcji lub procedury


- ;




- begin



6


instrukcja

; 


 
- end
 

W powyszym diagramie wystpuj kolejno sekcja denicji typw, sekcja


deklaracji zmiennych, sekcja deklaracji funkcji i procedur oraz program
gwny.
typ

identykator typu
*


HH
j
H

H
H
H




opis typu

Jednak dalszy opis jzyka Pascal przedstawimy mniej formalnie.

3.4 Zmienne
1. Zmienna i jej nazwa: zmienn moemy utosamia z obszarem pamici,
w ktrym przechowywana jest pewna warto (warto tej zmiennej w postaci kodu dwjkowego). Nazwa zmiennej (identykator) to
mnemotechniczny adres tego obszaru pamici.
NB. Dla rnych zmiennych obszar pamici moe by rny.
17

2. Typ zmiennej wyznacza wielko obszaru pamici przeznaczonego na


dan zmienn. Aby poprawnie skompilowa program musimy poinformowa kompilator o zamiarze wykorzystania kadej zmiennej (wyjtki
od tej reguy poznamy pniej). Taka informacja to deklaracja zmiennej (lub staej).
Deklaracje zmiennych w jzyku Pascal maj nastpujca posta:
var nazwa1, nazwa2 : typ1;
nazwa3 : typ3;
....

Sowo 'var' jest sowem kluczowym rozpoczynajcym sekcj deklaracji


zmiennych. Deklaracja zmiennych wprowadza identykatory zmiennych
wymienione po lewej stronie deklaracji, i zapowiada, e bd one uywane
dla oznaczania wartoci typu podanego po prawej stronie deklaracji.
Denicje staych w jzyku Pascal maj nastpujc posta:
const stala1='opis stalej';
....

Sowo 'const' jest sowem kluczowym rozpoczynajcym sekcj denicji


staych. Stae, podobnie jak zmienne, przechowuj wartoci rnych typw
ale nie mog by modykowane podczas realizacji programu.
Przykad
const zakres=100;
pi=3.14;
liczba=17;
znak='a';
ciag_znakow='ala';

3.5 Typy proste


Podstawowymi typami jzyka Pascal s typy proste. Przy ich pomocy deniuje si bardziej zoone typy strukturalne.

Typy standardowe

18

typ

identykator przykadowe
funkcje
typu
elementy typu
i relacje
logiczny
boolean
true, false
and, or, not
cakowity
integer
-2, 1, 1000
+,-,*, div, mod,< !
znakowy
char
'a','1','+'
rzeczywisty
real
10,1.7,1,2E4
+,-,*,/
acuchowy
string
'ala'
+,<
Typy logiczny, cakowity i znakowy s typami porzdkowymi. Na elementach typu porzdkowego T s okrelone funkcje ord przeksztacajc typ T
w typ integer oraz funkcje poprzednika i nastpnika
succ, pred : T T

(succ nie jest zdeniowany dla ostatniego elementu typu T , a pred nie jest
zdeniowany dla pierwszego elementu typu T ).
Przykad deklaracji zmiennych:
var x,y,z : real;
p,q : boolean;
litera : char;
s1,s2 : string;
m,n : integer;

Uywajc funkcji i relacji tworzymy ze zmiennych i staych wyraenia.


Przykady wyrae:

1. (x + y)/z - wyraenie typu real;


2. (x + y) < z - wyraenie typu boolean;
3. s1+s2 - wyraenie typu string;
4. s1+litera - wyraenie typu string;
5. (p and ((s1 + litera) < z)) or not q - wyraenie typu boolean;
6. n mod m - wyraenie typu integer.

Typy wyliczeniowe

Typy wyliczeniowe s deniowane przez wyliczenie identykatorw elementw typu.


Przykad
19

type dzien_tygodnia = (pon,wt,sr,czw,pt,sob,niedz);


kolor=(czerwony,zielony,niebieski);

Typy okrojone

Typy okrojone s deniowane przez ograniczenie typu porzdkowego.


Przykad
type dzien_roboczy = (pon..pt);
mala_liczba=(1..30);

Typy wyliczeniowe i okrojone te s typami porzdkowymi.

3.6 Typy strukturalne


Typy strukturalne s deniowane z wczeniej zdeniowanych typw przy
pomocy tzw. konstruktorw typw (operacji na typach).

Tablice

Deklaracja tablicy:
type tablica=array[T1,...,Tn] of T;

gdzie T 1, . . . T n s typami porzdkowymi a T dowolnym typem. Teoriomonogociowo tablicom typu tablica odpowiadaj funkcje z produktu
kartezjaskiego T1 . . . Tn w T.
Przykad denicji typw tablicowych:
type tablica1 = array[1..10] of char;
tablica2 = array[dzien_roboczy,mala_liczba] of real;
tablica3 = array['a'..'z'] of integer;

Wtedy tablica1[7] jest znakiem, tablica2[wt,3] jest liczb rzeczywist, a tablica3['c'] jest liczb cakowit.

Rekordy

Deklaracja rekordu:
type rekord1=record p1:T1;
p2:T2;
...
pn:Tn
end;

20

gdzie rekord1 jest identykatorem deniowanego typu rekordowego T1 ... Tn


s identykatorami typw a p1 s identykatorami pl. Wszystkie identykatory pl musz by rne. Jeli natomiast identykatory typw s rwne,
moemy pola odpowiednich typw umieci na tej samej licie. Na przykad
jeli T1 i T2 s rwne to powyszy rekord moemy zdeniowa te tak:
type rekord2=record p1,p2:T1;
p3:T3;
...
pn:Tn
end;

Teoriomnogociowo rekordy typu rekord1 to n-tki uporzdkowane, elementy


produktu kartezjaskiego T1 . . . Tn.
Przykad
type student = record
nazwisko,imie:string;
rok,nr:integer;
srednia:real
end;
var s1,s2:student;

Wtedy s1.nazwisko jest acuchem, s1.rok liczb cakowit, a


s1.srednia liczb rzeczywist.

Zbory, Pliki, na wiczeniach.


Typy wskanikowe Typy wskanikowe su do konstrukcji dynam-

icznych struktur danych. Bd one omawiane w drugim semestrze.


Z typami zwizane s
1. operacje na elementach danego typu;

2. sposb dostpu do informacji przechowywanych w zmiennych i staych


danego typu;
3. konstrukcje programotwrcze suce do przeszukiwania elementw
typw strukturalnych.

3.7 Przegld instrukcji jzyka Pascal


Poniej opiszemy kolejno podstawowe instrukcje jzyka Pascal i ich
znaczenia.
21

Instrukcja przypisania
Instrukcja ma posta
a:=w

gdzie a jest zmienn a w jest wyraeniem tego samego typu co zmienna a.


Przykad. Przy deklaracji zmiennych
var a,x:real;
p:boolean;
n,m:integer;

moemy na przykad dokona takich podstawia


a:=(x+n)/2;
n:=n*m;
n:=n+2;
p:=(a<x) or (n=0);

Opis logiczny instrukcji. Znaczenie tej instrukcji opisuje aksjomat


P (a\w){ a := w }P

(1)

gdzie P jest dowoln formu, a P (a\w) jest formu powsta z P przez zastpienie wszystkich1 wystpie zmiennej a wyraeniem w. Caa formula (1)
oznacza, e jeli przed wykonaniem instrukcji a:=w speniony jest warunek
P [a\w] to po wykonaniu instrukcji a:=w speniony jest warunek P .
Przykady zastosowania aksjomatu (1):
(b = (x + n) + 1){a := x + n}(b = a + 1)

czyli, jeli przed wykonaniem instrukcji a := x + n zachodzi (b = (x + n) + 1)


to po jej wykonaniu zachodzi (b = a + 1).
(n + 1 < k n + 1 > 0){n := n + 1}(n < k n > 0)

czyli, jeli przed wykonaniem instrukcji n := n+1 zachodzi (n+1 < kn+1 >
0) to po jej wykonaniu zachodzi (n < k n > 0).
1
S tu pewne ograniczenia ktre nas w praktyce nie bd dotyczy. Gdy formua P
ma kwantykatory to wyraenie w wstawiamy na tak zwane wolne wystpienia zmiennej
a. Ponadto, takie podstawienie nie moe wiza adnej ze zmiennych wystpujcych w
wyraeniu w.

22

Innymi sowy instrukcja podstawiania jest wykonywana w ten sposb, e


najpierw wyliczamy warto wyraenia po prawej stronie a potem wstawiamy
wyliczon warto na zmienn po lewej stronie.
Do opisu znaczenia instrukcji przypisania uylimy zapisu logicznego.
Oglnie zapis logiczny ma posta
P { I }Q

gdzie P i Q s formuami a I instrukcj, i oznacza, e jeli przed wykonaniem


instrukcji I prawdziwa jest formua P to po jej wykonaniu (o ile wykonywanie
instrukcji si zakoczy) prawdziwa jest formua Q. P nazywamy warunkiem
pocztkowym a Q warunkiem kocowym.
Prawdziwa jest nastpujca regua wnioskowania
P { I }Q, Q{ J }R
P { I; J }R

(2)

Ta regua, jak i inne reguy wnioskowania, pozwala wywnioskowa formu


pod kresk o ile ustalimy prawdziwo formu nad kresk. W tym przypadku
regua (3) wyraa to, e ; czy dwie instrukcje nic w nich nie zmieniajc.
Czsto uyteczna jest regua ktra nieznacznie uoglnia regu (2)
P P 0,

P 0 { I }Q, Q Q0 , Q0 { J }R,
P { I; J }S

R R0

(3)

Przykad. Zamian warto zmiennych x i y dowolnego typy T mona


wykona uywajc dodatkowej zmiennej z typu T w nastpujcy sposb:
z:=x;
x:=y;
y:=z

Mona to wykaza uywajc opisu znaczenia instrukcji podstawiania (1) oraz


reguy (2) w nastpujcy sposb:
(x = a y = b) {z := x} (z = a y = b)
(z = a y = b) {x := y} (z = a x = b)
(z = a x = b) {y := z} (y = a x = b)

W praktyce takie rozumowania jest lepiej prowadzi od koca.


23

Zatem, uywajc dwukrotnie reguy (2), otrzymujemy


(x = a y = b) {z := x; x := y; y := z} (y = a x = b)

Gdy T jest typem cakowitym lub rzeczywistym to moemy zamieni


wartoci zmiennych x i y nie uywajc dodatkowej zmiennej, w nastpujcy
sposb:
x:=x+y;
x:=x-y;
y:=x-y

By pokaza, e powysze trzy instrukcje rzeczywicie wymieniaj wartoci


zmiennych x i y znowu uyjemy aksjomatu (1) zaczynajc od koca (gdzie
wstawiamy formu ktr chcemy udowodni (y = a x = b)):
((x+y)((x+y)y)) = b(x+y)y = a {x := x+y} x(xy) = bxy = a
x (x y) = b x y = a {y := x y} (x y) = b y = a)
(x y) = b y = a) {x := x y} x = b y = a)

Formua pierwsza ((x+y)((x+y)y)) = b(x+y)y = a (otrzymana


na kocu) nie jest t o ktr nam chodzi. Ale zauwamy, e prawdziwa jest
formua
(x = a y = b) ((x + y) ((x + y) y)) = b (x + y) y = a

A teraz uywajc reguy (3) otrzymujemy dany wynik:


(x = a y = b) {x := x + y; y := x y; y := x y} (x = b y = a)

Instrukcja pusta
Instrukcja pusta to pusty cig znakw i znaczy 'nic nie rb'. Jej znaczenie
opisuje si aksjomatem
P { }P

dla dowolnej formuy P . Jeli napiszemy cig instrukcji I1 ; ; I2 to jest to


zoenie trzech instrukcji przy czym drug instrukcj jest instrukcja pusta.

24

Instrukcja zoona
Instrukcja zoona czy cig instrukcji w jedn instrukcj i ma posta
begin I1; ... ; In end gdzie I1, ... , In s instrukcjami. Znaczenie tej
instrukcji opisuje regua
Pi { Ii } Pi+1 i = 1, . . . , n
P1 { begin I1 ; . . . ; In end } Pn+1

(4)

Przykad. Fragment programu


begin
x:=x+2;
y:=2*x;
end;

jest zoeniem trzech instrukcji, z ktrych ostatnia jest instrukcj pust.

Instrukcje warunkowe
Mamy dwie instrukcje warunkowe. Pierwsza ma posta
if w then I

gdzie w jest wyraeniem typu boolowskiego a I jest instrukcj. Znaczenie tej


instrukcji opisuje regua
P w { I } Q P w Q
P {if w then I} Q

(5)

tzn. instrukcja oznacza 'jeli w to wykonaj I'. Druga instrukcja warunkowa


jest rozszerzeniem pierwszej i ma posta
if w then I1 else I2

gdzie w jest wyraeniem typu boolowskiego a I1 i I2 s instrukcjami. Znaczenie tej instrukcji opisuje regua
P w { I1 } Q P w { I2 } Q
P {if w then I1else I2} Q

(6)

tzn. instrukcja oznacza 'jeli w to wykonaj I1 w przeciwnym wypadku


wykonaj I2'.
Przykad. Jeli x jest typu cakowitego to mamy
T { if x < 0 then abs := x else abs := x } abs = |x|

25

(7)

gdzie T oznacza formu zawsze prawdziw. Z (1) i (3) mamy


(T x < 0) (x = x x < 0),

(abs = x x < 0) (abs = |x|)

((x = x x < 0) { abs := x } (abs = x x < 0)


(T x < 0) { abs := x } (abs = |x|)

i podobnie mona pokaza, e


(T (x < 0)) { abs := x } (abs := |x|).

Zatem (7) wynika z powyszych dwch formu na mocy reguy (6).

Iteracja warunkowa (ptla while)


Instrukcja iteracji warunkowej ma posta
while w do I

gdzie w jest wyraeniem typu boolowskiego a I jest instrukcj.


Przykad.
while x<y do begin
x:=x+2;
y:=y+1
end

Znaczenie tej instrukcji opisuje regua


P w {I }P
P { while w do I } P w

(8)

Formu P speniajc przesanki tej reguy nazywamy niezmiennikiem ptli.


Instrukcja ta powoduje, e instrukcja I jest wykonywana dopki warunek w
jest speniony. Zauwamy, e w regule (8) warunek P wystpuje zarwno
w warunku pocztkowym jak i kocowym (std jego nazwa niezmiennik).
Umiejtny wybr takiego niezmiennika jest zazwyczaj najistotniejszym problemem przy dowodzeniu czciowej poprawnoci programw.
Przykad. Pokaemy, e po wykonaniu poniszego fragmentu programu
zmienna iloczyn ma warto mn. Wszystkie zmienne s typu cakowitego.
if n<0 then a:=-n
else a:=n;
k:=0;

26

x:=0;
while k<a do begin
x:=m+x;
k:=k+1
end;
if n<0 then iloczyn:=-x
else iloczyn:=x

Mamy
T { if n<0 then a:=-n else a:=n } (a = |n|)

oraz
(a = |n|) { k:=0; x:=0 } (k = 0 x = 0 (a = |n|)).

Prawdziwa jest nastpujca formua


(k = 0 x = 0 (a = |n|)) (k a x = k m)

Ponadto dla formuy Q = (k a x = k m) mamy


Q (k < a) { x:=m+x;k:=k+1 } Q

Zatem Q jest niezmiennikiem ptli i na mocy reguy (8) mamy


Q { while k<a do begin x:=m+x;k:=k+1 end } ((k < a) Q).

Uywajc reguy (3) otrzymujemy


Q { while k<a do begin x:=m+x;k:=k+1 end } (k = a Q).

Ponadto mamy te
(x = a m a = |n|) { if n<0 then iloczyn:=-x else iloczyn:=x }
(iloczyn = n m).

czc powysze formuy przy pomocy reguy (3) otrzymujemy tez.

Iteracja ograniczona (ptla for)


Instrukcja iteracji ograniczonej ma posta
for x:=t1 to t2 do I

27

gdzie x jest zmienn typu porzdkowego, t1 i t2 s wyraeniami tego samego


typu co zmienna x a I jest instrukcj.
Przykad.
for i:=1 to 10 do begin
x:=x*i;
y:=y+i
end;

Znaczenie tej instrukcji opisuje regua (zakadamy, e instrukcja I nie


zmienia wartoci zmiennej i oraz t1 succ(t2))
P (t1), P (i) { I } P (succ(i)) i = t1, . . . , t2
P (t1) { for i := t1 to t2 do I } P (succ(t2))

(9)

Podobnie jak w przypadku ptli while formu P speniajc przesanki


tej reguy nazywamy niezmiennikiem ptli. Instrukcja ta powoduje, e instrukcja I jest wykonywana kolejno dla wszystkich wartoci x of t1 do t2.

Instrukcje wejcia-wyjcia
Instrukcje wejcia-wyjcia
zewntrznym'. Instrukcja

su

do

komunikacji

ze

'wiatem

write(w)

wypisuje na ekran warto wyraenia w typu standardowego. Instrukcja


read(x)

wczytuje warto z klawiatury na zmienn x typu standardowego.


Przykady. Podajemy poniej dwa proste przykady programw. Pierwszy nwd oblicza najwikszy wsplny dzielnik a drugi srednia redni arytmetyczn n liczb.
Program nwd;
var n,m:integer;
begin
read(n);
read(m);
while n<>m do
if n>m then n:=n-m
else m:=m-n;
write(n)
end.

28

Program srednia;
var n,i:integer;
x,s:real;
begin
read(n);
s:=0;
for i:=1 to n do begin
read(x);
s:=s+x;
end;
write(s/n)
end.

3.8 Procedury
Programy nawet w jzyku wysokiego poziomu, jeli nie s podzielone na
mniejsze moduy szybko staj si nieczytelne. By temu zapobiec moe je
dzieli na mniejsze moduy ktre wykonuj poszczeglne fragmenty zadania
i maj bardziej przejrzyst form. Do modularyzacji wikszych programw
su procedury. Rozwamy nastpujce zadanie.
Zadanie.
Dane: tablica A liczb cakowitych.
Wynik: Liczba wystpie liczby 1 po liczbie 0.

Dla tablicy A = [1, 0, 0, 7, 1, 1, 0, 6, 7, 1, 1] wynik powinien by 2. Mona


to zadanie rozwiza tak:
const m=100;
var A : array[1..m] of integer;
s,n,i : integer;
begin
for i:=1 to m do
read(A[i]);
s:=0; n:=1;
while n<m do begin
while (n<m) and (A[n]<>0) do
n:=n+1;
if A[n]=0 then begin
while (n<m) and (A[n]<>1) do

29

{wczytanie wartoci A}
{inicjalizacja zmiennych}
{ptla gwna}
{szukanie kolejnego 0 w A}
{jeli znalazl 0 to...}
{szukanie kolejnego 1 w A}

n:=n+1;
if A[n]=1 then s:=s+1; {jeli znalazl 1 to zwikszamy s}
end;
end;
write(s);
{wypisanie wynikw}
end.

W nawiasach klamrowych zapisane s komentarze wyjaniajce co robi


poszczeglne fragmenty programu. Mona jednak ten program zapisa, uywajc procedur, tak:
const m=100;
var A : array[1..m] of integer;
s,n : integer;
procedure dane;{wczytanie wartoci A}
var i:integer;
begin
for i:=1 to m do
read(A[i]);
end;
procedure szukaj(var j:integer;x:integer);
{szukanie w tablicy A wartosci x od miejsca j}
begin
while (j<m) and (A[j]<>x) do
j:=j+1;
end;
begin{prgram glowny}
dane; {wywolanie procedury wczytujacej dane}
s:=0; n:=1;
{inicjalizacja zmiennych}
while n<m do begin
{ptla gwna}
szukaj(n,0); {wywolanie procedury szukaj z parametrami
aktualnymi n oraz 0}
if A[n]=0 then begin
{jeli znalazl 0 to...}
szukaj(n,1); {wywolanie procedury szukaj z parametrami
aktualnymi n oraz 1}
if A[n]=1 then s:=s+1; {jeli znalazl 1 to zwikszamy s}
end;
end;

30

write(s);
end.

{wypisanie wynikw}

Majc taki program mona go teraz atwo poprawi by szuka rnych kombinacji liczb na przykad 0, 1 i 2, 3.
const m=100;
var A : array[1..m] of integer;
s,n : integer;
procedure dane;{wczytanie wartoci A}
var i:integer;
begin
for i:=1 to m do
read(A[i]);
end;
procedure szukaj(var j:integer;x:integer);
{szukanie w tablicy A wartosci x od miejsca j}
begin
while (j<m) and (A[j]<>x) do
j:=j+1;
end;
function kombinacja(k,l:integer):integer;
{liczy ile razy k wystepuje przed l w tablicy A}
var s,n:integer;
begin
s:=0; n:=1;
{inicjalizacja zmiennych}
while n<m do begin
{ptla gwna}
szukaj(n,k); {wywolanie procedury szukaj z parametrami
aktualnymi n oraz k}
if A[n]=k then begin
{jeli znalazl k to...}
szukaj(n,l); {wywolanie procedury szukaj z parametrami
aktualnymi n oraz l}
if A[n]=l then s:=s+1; {jeli znalazl l to zwikszamy s}
end;
end;
kombinacja:=s;
end;

31

begin {program glowny}


dane; {wywolanie procedury wczytujacej dane}
write(kombinacja(0,1));
{wypisanie wynikw}
write(kombinacja(2,3))
end.

W ten sposb pierwszy program zosta podzielony na mniejsze moduy, ktre


wykonuj jasno okrelone podzadania. A sam program gwny zosta zredukowany do 'spisu treci'.

Parametry i zmienne zwizane z procedurami


Poniewa procedury mog zalee od parametrw rnego rodzaju i
mona w nich deklarowa dodatkowe zmienne ktre istniej tylko w czasie
wykonywania tej procedury, w poniszych tabelach zestawiamy i opisujemy
te nowo napotkane 'twory'.

Zmienne w procedurach
Globalne

Lokalne

(zmienne uywane
(zmienne zadeklarowane
w procedurze ale
w procedurze i istniejce
nie zadeklarowane w tej
tylko podczas dziaania
procedurze i nie bdce
tej procedury)
parametrami formalnymi)

Zmienne:
Zmienne globalne s zadeklarowane w nagwku programu i istniej w

czasie caego dziaania programu.

Zmienne lokalne s deklarowane po nagwku procedury (i sowie var)

i istniej tylko w czasie dziaania tej procedury.

W ciele procedury dostpne s zarwno zmienne lokalne zadeklarowane

w tej procedurze jaki i zmienne globalne. Wyjtek od tej reguy stanowi


sytuacja, w ktrej zmienna globalna ma ten sam identykator co zmienna lokalna. Wtedy zmienna globalna nie jest dostpna w tej procedurze2 .

Takie zjawisko nazywa si zasanianiem zmiennych

32

Parametry procedur
Formalne

Aktualne

(wyliczone w nagwku
procedury i uywane
w ciele procedury)

(wyliczone przy kadym


woaniu procedury)

woane przez warto

wyraenia typw
odpowiadajcych parametrom
formalnym

woane przez zmienn

zmienne typw
odpowiadajcych parametrom
formalnym

Parametry:
Parametry formalne procedury to zmienne zadeklarowane w nagwku

procedury ( w nawiasie, po identykatorze procedury).

Parametry aktualne procedury to zmienne lub wyraenia, ktre s

parametrami przy woaniach procedury.

Parametry formalne woane przez warto zachowuj si w ciele pro-

cedury jak zmienne lokalne z ta rnic, e s inicjalizowane przed


rozpoczciem wykonywania procedury przez wartoci parametrw aktualnych.

Parametry formalne woane przez zmienn (w nagwku procedury ich


deklaracj poprzedza sowo var) zachowuj si w procedurze podobnie

do zmiennych globalnych. Dokadniej, parametr aktualny odpowiadajcy parametrowi formalnemu woanemu przez zmienn musi by zmienn i wszystkie operacje dotyczce tego parametru formalnego w czasie wykonywania procedury s wykonywane na odpowiadajcym mu
parametrze aktualnym.

Uwaga. Z powyszego opisu wynika, e warto parametru aktualnego


woanemu przez zmienn moe by aktualizowana w czasie dziaania procedury. Moemy zatem, przy pomocy zmiennych woanych przez warto

33

przekazywa szereg wartoci dowolnych typw obliczone w czasie dziaania


procedury.
Przykad.
var t:array[1..100] of integer;
a,b:integer;
procedure cos (var x:integer;y:integer);
var b,t:integer;
begin
x:=x+1; y:=y+1; a:=a+1; b:=y+1; t:=a+1;
end;
begin
a:=20; b:=10;
cos(a,b)
writeln(a); writeln(b);
end.

W procedurze cos, x jest parametrem formalnym woanym przez zmienn,


y jest parametrem formalnym woanym przez warto, b i t s zmiennymi
lokalnymi a zmienna a jest globalna. Zmienne globalne: tablicowa t i
cakowita b s niedostpne w procedurze cos, poniewa s zasonite przez
zmienne lokalne o tym samym identykatorze i typie cakowitym. W instrukcji woania procedury cos(a,b), a i b s parametrami aktualnymi. W
wyniku wykonania programu na ekranie zostan wypisane liczby:
22
10

3.9 Procedury rekurencyjne


Procedury rekurencyjne to takie, ktre woaj same siebie.
Jedn z najprostszych funkcji, ktr wygodnie jest deniowa rekurencyjnie jest funkcja silnia. Mona j zdeniowa tak:
(

n! =

1
n (n 1)!

gdy n = 0
gdy n > 0

T matematyczn denicje mona atwo przetumaczy na funkcj w jzyku


Pascal:

34

function silnia(n:integer):integer;
begin
if n=0 then silnia:=1
else silnia:=n*silnia(n-1)
end;

Do administrowania obliczeniami programu uywajcego procedur uywamy


stosu odwoa. Stos3 jest jedn z najprostszych dynamicznych struktury
danych. Na stosie mona dokonywa trzech operacji:
1. woy element na wierzch stosu;
2. zdj element z wierzchu stosu;
3. sprawdzi czy stos jest pusty.
Stos liter mona sobie wyobraa tak:
C
A
B
A
Wane jest, e liczba elementw na stosie jest w zasadzie nieograniczona, jego
wielko moe si zmienia dynamicznie w trakcie wykonywania programu w
zalenoci od biecych potrzeb.
Sprbujmy teraz przeanalizowa jak jest wykonywana instrukcja
silnia(5) umieszczona w pewnym miejscu programu gwnego, ktre oznaczymy przez . By obliczy warto silnia(5) musimy przerwa wykonywanie kolejnych instrukcji programu, wykona procedur silnia z parametrem
o wartoci 5 a nastpnie powrci do wykonywania programu w miejscu w
ktrym je przerwalimy. By umoliwi taki powrt wkadamy na stos adres
miejsca powrotu i aktualne wartoci zmiennych. Teraz stos wyglda tak:
1
,

wart. zm.

Stos na przykad ksiek ma to do siebie, e mona wkada ksiki na wierzch i z


wierzchu je zdejmowa, nie mona natomiast wyjmowa ich ze rodka, bez naruszania
caej konstrukcji.
3

35

Rozpoczynajc wykonywanie ciaa funkcji silnia zmienna n ma warto 5.


Zatem n 6= 0 i pozostaje do wykonania instrukcja silnia:=n*silnia(n-1)
przy wartoci zmiennej n rwnej 5. W tym celu naley obliczy warto
wyraenia n*silnia(n-1). Warto n znamy ale by obliczy warto
silnia(n-1) musimy ponownie wywoa procedur silnia tym razem od
parametru aktualnego n 1 = 5 1 = 4. Przed wywoaniem silnia(n-1)
trzeba zapamita gdzie mamy wrci z tego woania i jakie wartoci maj
mie wtedy zmienne. Oznaczmy miejsce silnia(n-1) w ciele procedury
silnia jako . Zatem w tym przypadku musimy zapamita adres miejsca
powrotu i warto zmiennej n rwn 5. Te dane wkadamy na stos, ktry
wyglda teraz tak:

, n = 5
, wart. zm.

Majc tak zabezpieczony powrt rozpoczynamy obliczanie procedury silnia


z wartoci pocztkow parametru n rwn 4. Poniewa 4 6= 0, znowu
musimy wywoa procedur silnia, ale tym razem od parametru aktualnego
n = 4 1 = 3. Przed wywoaniem silnia(n-1) znw trzeba zapamita
gdzie mamy wrci z tego woania i jakie wartoci maj mie wtedy zmienne.
Zatem wkadamy na stos adres miejsca powrotu i warto zmiennej n. Teraz
stos wyglda tak:

, n = 4
, n = 5
, wart. zm.

... i rozpoczynamy obliczanie silnia(3). W ten sposb dojdziemy w kocu


do sytuacji w ktrej stos wyglda tak:

36

, n = 1
, n = 2
, n = 3
, n = 4
, n = 5
, wart. zm.

... i rozpoczynamy obliczanie silnia(0). W tym przypadku warto funkcji


silnia jest obliczana bezporednio w ciele procedury bez potrzeby dalszych
odwoa. Po skoczeniu obliczenia silnia(0), na wierzchu stosu znajduje
si informacja 'co dalej'. Zdejmujemy zatem z wierzchu stosu dane i n = 1,
tak, e stos wyglda teraz tak:
, n = 2
, n = 3
, n = 4
, n = 5
, wart. zm.

i kontynuujemy obliczenie w miejscu z wartoci n = 1, tzn. kontynuujemy obliczanie wartoci funkcji silnia z wartoci n = 1 i obliczan wanie
wartoci silnia(0) rwn 1. Teraz wyliczamy, e silnia(1) ma warto
1 i koczymy wykonywanie tego woania funkcji silnia i ponownie wracamy
do obliczania w miejscu i z wartoci zmiennych, ktre s zapamitane teraz
na wierzchu stosu. Zdejmujemy zatem z wierzchu stosu dane i n = 2
i kontynuujemy obliczenie funkcji silnia a do momentu gdy zakoczymy
obliczanie wartoci silnia(5) rwnej 120. W tym momencie stos wyglda
tak:
,

wart. zm.

Oprniamy teraz stos, wracamy do miejsca i wartoci zmiennych z przed


woania silnia(5) oraz wartoci silnia(5) rwn 120 i kontynuujemy
wykonywanie programu.
Moemy drzewo odwoa dla woania silnia(5) przedstawia tak:
37

silnia(5)
silnia(4)
silnia(3)
silnia(2)
silnia(1)
silnia(0)

tzn. silnia(5) woa silnia(4) a do silnia(0), a ta ostatnia jest wyliczania bez adnych dodatkowych woa.

Za rekurencja. Rekurencyjne procedury s zwykle bardziej czytelne


i atwiejsze do zaprogramowania jednak, poniewa ich implementacja uywa
stosu, zwykle uywaj wikszej pamici i s nieco wolniejsze od procedur
nierekurencyjnych, o ile takie istniej. Na przykad funkcj silnia mona
obliczy iteracyjnie:
function silnia1(n:integer):integer;
var s,i:integer;
begin
s:=1;
for i:= 1 to n do
s:=s*i;
silnia1:=s
end;

Tak zapisana funkcja jest nieco mniej czytelna ale obliczania przy jej uyciu bdzie nieco efektywniejsze. Natomiast w przypadku obliczania cigu
Fibbonacciego zdeniowanego nastpujco:
fn =

f
n2 + fn1

gdy n = 0
gdy n = 1
gdy n > 1

rnica szybko robi si o wiele istotniejsza. Jeli zapiszemy t funkcj


rekurencyjnie:
procedure Fibb(n:integer);
begin
if n=0 then Fibb:=0

38

else if n=1 then Fibb:=1


else Fibb:=Fibb(n-2)+Fibb(n-1)

end;

to wyglda ona elegancko ale jest bardzo nieefektywna, gdy wiele wartoci
bdzie wyliczaa wielokrotnie. Drzewo odwoa dla woania Fibb(5) bdzie
wygldao tak:
Fibb(5)





Fibb(3)
Fibb(1)

@
@

Fibb(2)

Fibb(0)

@
@

Fibb(1)

XX
XXX
X

Fibb(4)

Fibb(2)
Fibb(0)

@
@

Fibb(1)

@
@

Fibb(3)

Fibb(1)

@
@

Fibb(2)
C
C

Fibb(0) Fibb(1)

A zatem Fibb(3) bdzie wywoany dwa razy Fibb(2) i Fibb(0) bdzie


wywoany trzy razy, a Fibb(1) bdzie wywoany pi razy! Taka procedura nie tylko pochania wicej pamici ale i wielokrotnie wicej czasu od
procedury iteracyjnej:
procedure Fibb1(n:integer):integer;
var x,y,i:integer;
begin
if n<2 then Fibb1:=n
else begin x:=1; y:=0
for i:=1 to n-1 do begin
x:=x+y;
y:=x-y
end
Fibb1:=x
end;
end;

Zauwamy, e niezmiennikiem ptli for w procedurze Fibb1 jest formua


x = fi+1 y = fi . A std atwo zauway, e funkcja Fibb1 te oblicza

wartoci cigu Fibbonacciego.


Zatem jeli jest proste rozwizanie iteracyjne to lepiej unika rekurencji.
39

3.10 Poprawno programw


Jak si przekona, e napisany przez nas program jest poprawny, tzn. dla
poprawnych danych wejciowych daje poprawne wyniki? Testowanie jest
pewn wskazwk ale trudno przetestowa program dla wszystkich danych
wejciowych. Potrzebny jest dowd poprawnoci.
Mwimy, e program jest poprawny jeli daje poprawne wyniki dla wszystkich moliwych danych wejciowych. Dowody poprawnoci zwykle skadaj
si z dwch czci: dowodu czciowej poprawnoci i wasnoci stopu.
Warunek pocztkowy okrela wasnoci jakie musz spenia poprawne

dane wejciowe.

Warunek kocowy okrela wasnoci jakie musz spenia poprawne

dane wyjciowe, wyniki.

Program, lub fragment programu S jest czciowo poprawny ze wzgldu


na warunek pocztkowy p i warunek kocowy q jeli o ile dane wejciowe
speniaj warunek p i program si zatrzyma to dane wyjciowe speniaj warunek q . Notacja: p{S}q .
Program, lub fragment programu S jest poprawny ze wzgldu na
warunek pocztkowy p i warunek kocowy q jeli o ile dane wejciowe
speniaj warunek p to program si zatrzyma i dane wyjciowe speniaj warunek q .

Przykad 1.
Pokaemy, e fragment programu S1
silnia:=1;
k:=1;
while k<n do begin
k:=k+1;
silnia:=silnia*k
end;

jest poprawny ze wzgldu na warunek pocztkowy p = (n > 0) i warunek


kocowy q = (silnia = n!).
Zauwamy, e jeli p jest speniony przed rozpoczciem wykonywania S1
to r = (silnia = k!)(k n) jest speniony po wykonaniu pierwszych dwch
instrukcji z S1.
Pokaemy, e formua r jest niezmiennikiem ptli while. Oznaczmy przez
S par instrukcji k:=k+1;silnia:=silnia*k.
40

Zamy, e warunki r i (k < n) s speniane. Oznaczmy przez silnia0


oraz k0 wartoci zmiennych silnia i k przed wykonaniem S a przez silnia1 i
k1 wartoci tych zmiennych po wykonaniu S . Pierwsza instrukcja zwiksza
warto k o jeden, a std k1 = k0 + 1. Poniewa k0 < n to k1 = k0 + 1 n.
Druga instrukcja mnoy warto zmiennej silnia przez (now) warto k.
Zatem
silnia1 = silnia0 k1 = k0 ! (k0 + 1) = (k0 + 1)! = k1 !

Czyli pokazalimy, e
r (k < n){S}r

i z reguy (8) otrzymujemy, e


r{while k < n do S}(k n) r

Zatem po wyjciu z ptli while (o ile to nastpi) mamy, e k = nsilnia = k!.


Std q . Pokazalimy, e p{S1}q , tzn. e S1 jest czciowo poprawny ze
wzgldu na warunek pocztkowy p i warunek kocowy q .
Ponadto ptla while zatrzyma si po n 1 przejciach z wartoci k = n,
gdy przed wejciem do ptli k = 1 oraz kade wykonanie ptli zwiksza
warto zmiennej k o jeden. Zatem S1 jest poprawny ze wzgldu na warunek
pocztkowy p i warunek kocowy q .
Przykad 2. Pokaemy, e fragment programu S2
z:=x; y:=1; m:=n;
while m>0 do begin
if (m mod 2) = 1 then y:=z*y;
m:=m div 2;
z:=z*z
end

jest poprawny ze wzgldu na warunek pocztkowy p = (n > 0) i warunek


kocowy q = (y = xn ).
Niezmiennikiem ptli jest formua Q = (xn = y z m m 0). Jeli
oznaczymy przez z1 , y1 , m1 , wartoci zmiennych z , y , m przed wykonaniem
jednego obrotu ptli a przez z2 , y2 , m2 , wartoci tych zmiennych po wykonaniu jednego obrotu ptli to mamy:
jeli m1 = 2 k to y2 = y1 oraz
xn = y1 z1 m1 = y1 (z1 z1 )k = y2 z2 m2 ;

41

jeli m1 = 2 k + 1 to y2 = y1 z1 oraz
xn = y1 z1 m1 = (y1 z1 ) (z1 z1 )k = y2 z2 m2 .

Oczywicie, przed wejciem do ptli niezmiennik jest speniony. Po wyjciu


z ptli m = 0 i wtedy xn = y z m = y 1 = y . Std p{S2}q .
Poniewa kady obrt ptli zmniejsza warto dodatni m o co najmniej
1, ptla bdzie wykonana co najwyej n razy. Zatem S2 si zatrzyma dla
dowolnego n > 0.

42

Podstawowe metody programowania (5)

4.1 Metoda powrotw (prb i bdw)


Problem ustawienia n hetmanw.

Dane: liczba naturalna n.


Wynik: ustawienie n hetmanw na szachownicy n n tak by adne

dwa hetmany si nie szachoway.

Zastanwmy si jak taki problem mona rozwiza w miar efektywnie


dla n = 8.
Pomys 1 Przejrze wszystkie ustawienia hetmanw na szachownicy i
sprawdza czy s poprawnie
ustawione.
!

Ustawie jest

64
8

4 109 . To jest za duo!

Pomys 2 Pomys pierwszy mona atwo poprawi ograniczajc nieco


przestrze ktr mamy przeszukiwa. W kadym wierszu moe sta tylko
jeden hetman. Wektor (i1 , . . . , i8 ) dla 1 i1 , . . . , i8 8 reprezentuje ustawienie hetmanw na polach o wsprzdnych ((1, i1 ), . . . , (8, i8 )). Takich wektorw jest 88 107 . Duo!
program1
for i1:=1 to 8 do
for i2:=1 to 8 do
......
for i8:=1 to 8 do
sprawdz czy (i1,...,i8) reprezentuje poprawne ustawienie

Pomys 3 Nietrudno zauway, e moemy i t przestrze ograniczy. W


kadym wierszu i kadej kolumnie moe sta tylko jeden hetman. Wystarczy
zatem przejrze wektory (i1 , . . . , i8 ) bdce permutacjami zbioru {1, . . . , 8}.
Permutacji jest 8! = 104 . Sporo!
program2
proba:=pierwsza permutacja;
while proba nie jest ostatni permutacj
oraz nie jest rozwizaniem do
proba:=nastpna_permutacja(proba);

43

Pomys 4 (Metoda powrotw) Rozszerzamy czciowe poprawne


rozwizanie a do uzyskania penego poprawnego rozwizania. Jeli si nie
da rozszerzy czciowego rozwizania to wracamy i poprawiamy czciowe
rozwizanie w pierwszym moliwym miejscu.
Przykad n = 8.

H
H

H
H

Na tej szachownicy hetmany zostay ustawione w kolejnych wierszach w


pierwsze pole od lewej strony ktre nie jest szachowane przez poprzednio
ustawione hetmany. W szstym wierszu wszystkie pola s szachowane, zatem musimy pitym wierszu przestawi hetmana na nastpne nieszachowane
pole w tym wierszu (sme zaznaczone ) i prbowa dalej...
Szkic procedury realizujcej taki algorytm. (Konkretne algorytmy z
powrotami, w tym ten rozwizujcy nasz problem, s 'ukonkretnieniem' tego
schematy.)
procedure probuj;
begin
zapocztkuj wybieranie kandydatw;
repeat
wybierz nastpnego kandydata;
if kandydat jest dopuszczalny then begin
dopisz kandydata do czciowego rozwizania;
if rozwiazanie niepene then begin
probuj wykona nastepny krok (rekursja);
if proba nieudana then
usun kandydata z czciowego rozwiazania
end;
end;
until (prba udana) lub (nie ma wicej kandydatw)
end;

44

eby napisa szczegowo procedur musimy najpierw zastanowi si nad


reprezentacj danych odpowiedni do naszych potrzeb. Powinnimy mie
tablic het n liczb cakowitych reprezentujc obecnie rozwaane czciowe
rozwizanie, tzn
het[i] = 0 gdy w i-tym wierszu nie ma hetmana,
het[i] = j > 0 gdy i-tym wierszu na j -tym miejscu stoi hetman.

Ponadto musimy pamita, ktre kolumny i lewe . i prawe & 'skosy',


na ktrych ju stoi hetman. Bdziemy te informacje pamita w tablicach
boolowskich kol, lewy, prawy, tak, e
(

kol[i] =
(

lewy[i] =

prawy[i] =

i-ta kolumna jest wolna


w i-tej kolumnie stoi hetman

gdy skos o sumie wsprzednych i jest wolny


gdy na skosie o sumie wsprzednych i stoi hetman

true
f alse

true
f alse

true
f alse

gdy skos o rnicy wsprzednych i jest wolny


gdy na skosie o rnicy wsprzednych i stoi hetman

Oprcz tablic potrzebujemy jeszcze zmiennej OK ktra bdzie pamitaa czy


ju znalelimy rozwizanie czy nie, tzn.
(

OK =

true
f alse

gdy znalelimy ju rozwiazanie


w przeciwnym przypadku.

Zatem deklaracja istotnych zmiennych powinna wyglda tak:


const n=8;
var het :
kol :
lewy :
prawy :
OK
:

array[1..n] of integer;
array[1..n] of boolean;
array[2..2*n] of boolean;
array[1-n..n-1 of boolean;
boolean;

procedury tak:
procedure probuj(i:integer; var q : boolean);
var k:integer;
begin
k:=0; {k - kolejna prbowana pozycja}

45

repeat
k:=k+1;
if kol[k] and lewy[k+i] and prawy[k-i] then begin
het[i]:=k; kol[k]:=false;
lewy[k+i]:=false; prawy[k-i]:=false;
if i<n then begin
probuj(i+1,q);
if not q then begin
het[i]:=0; kol[k]:=true;
lewy[k+i]:=true; prawy[k-i]:=true;
end;
end
else q:=true;
end;
until q or (k=n)
end;

a program gwny tak:


begin
for i:=1 to n do het[i]:=0;
for i:=1 to n do Kol[i]:=true;
for i:=2 to 2*n do lewy[i]:=true;
for i:=1-n to n-1 do prawy[i]:=true;
OK:=false;
probuj(1,OK);
if OK then wypisz(het)
else write('Nie ma rozwiza.')
end.

Procedura wypisz powinna wypisywa rozwizanie, na ekran lub do pliku,


liczbowo lub gracznie.
Jeli bymy chcieli wypisa nie jedno a wszystkie rozwizania to mona
to zrobi jeszcze prociej modykujc procedur probuj tak:
procedure probuj1(i:integer);
var k:integer;
begin
for k:=1 to n do
if kol[k] and lewy[k+i] and prawy[k-i] then begin
het[i]:=k; kol[k]:=false;

46

lewy[k+i]:=false; prawy[k-i]:=false;
if i<n then probuj1(i+1)
else wypisz(het);
het[i]:=0; kol[k]:=true;
lewy[k+i]:=true; prawy[k-i]:=true;
end;
end;

47

4.2 Metoda 'dziel i rzd'


Metoda 'dziel i rzd' polega na rozwizaniu wikszego problemu poprzez
podzielenie go na mniejsze podprogowy dla ktrych znajdujemy rozwizanie
a nastpnie za ich pomoc znajdujemy rozwizanie caego problemu. Metod
t zilustrujemy prezentujc algorytm sortowania przez scalanie.
Problem sortowania.

Dane wejciowe: liczba naturalna n i cig liczb a1 , a2 , . . . , an .


Wynik: permutacja a01 , a02 , . . . , a0n cigu a1 , a2 , . . . , an taka, e a01
a02 . . . a0n .

Zanim zaprezentujemy algorytm sortowania przez scalanie najpierw


rozwamy problem scalania dwch cigw:
Problem scalania.

Dane wejciowe: dwa cig liczb a1 , a2 , . . . , an , b1 , b2 , . . . , bm .


Wynik: permutacja c1 , c2 , . . . , cn+m cigu a1 , a2 , . . . , an , b1 , b2 , . . . , bm
taka, e c1 c2 . . . cn+m .

Procedur scalania mona opisa tak.


1. porwnujemy najmniejsze elementy dwch cigw, mniejszy z nich
wpisujemy do cigu wynikowego i usuwamy z cigu scalanego,
2. powtarzamy 1. a jeden z cigw scalanych bdzie pusty,
3. dopisujemy pozostae elementy na koniec cigu wynikowego.
Na przykad dla cigw scalanych
a1 , a2 , . . . , an ,

b1 , b 2 , . . . , bm

jeli mamy
a1 b1

a2 6 b1

a2 6 b2

a2 b3 . . .

to wynikowy cig scalony wyglda tak:


a1 , b1 , b2 , a2 . . .

Zauwamy, e scalanie wymaga co najwyej n + m 1 porwna.


Teraz, przy denicji typu tablica=array[1..n] of integer, moemy
tak napisa procedur sortujc przez scalanie.
48

procedure sortowanie(var A:tablica;min,max:integer);


var m:integer;
begin
if min<max then begin
m:=(min+max) div 2;
sortowanie(A,min,m);
sortowanie(A,m+1,max);
scalanie(A,min,m,max);
end;
end;

By

posortowa

sortowanie(T,1,n).

tak:

tablic T typu tablica naley wywoa


Natomiast sama procedura scalajca wyglda

procedure scalanie(var A:tablica;min,m,max:integer);


var i,j,k,l,p:integer; B:tablica;
begin
i:=min; j:=m+1; k:=min;
while (i<= m) and (j<= max) do begin
if A[i]<= A[j] then begin B[k]:=A[i]; i:=i+1 end
else begin B[k]:=A[j]; j:=j+1 end;
k:=k+1;
end;
if i<=m then begin l:=i; p:=m end
else begin l:=j; p:=max end;
for i:=0 to (p-l) do B[k+i]:=A[l+i];
for i:=min to max do A[i]:=B[i];
end;

Majc powyszy przykad przed oczami podsumujmy zasadnicze kroki


metody 'dziel i rzd':
1. dziel problem na mniejsze podproblemy;
2. rozwi podproblemy rekurencyjnie; jeli s one dostatecznie mae to
rozwi je bezporednio;
3. pocz rozwizania podproblemw w rozwizanie caego problemu.
Policzymy teraz zoono algorytmu sortowania przez scalanie. Niech
T (n) oznacza maksymaln liczb porwna elementw tablicy A przy
49

wykonywaniu procedury sortowanie dla tablicy o rozmiarze n. (Dla uproszczenia zakadamy, e n = 2k .)


(

T (n) =

0
2 T (n/2) + (n 1)

gdy n = 1
gdy n > 1

Notacja O(f (n)), (f (n)) i (f (n)) . Niech f : N N funkcja. Przypomnijmy, e funkcja g : N N jest (klasy) O(f (n)) jeli istniej stale
a, b R takie, e dla n > a, g(n) b f (n). Jeli funkcja 'g(n) O(f (n))'
mwimy czsto, e g(n) jest O(f (n)) i piszemy: g(n) = O(f (n)).
Mwimy, e funkcja g : N N jest (klasy) (f (n)) jeli istniej stale
a, b R takie, e dla n > a, b f (n) g(n). Podobnie jeli funkcja 'g(n)
(f (n))' mwimy czsto, e g(n) jest (f (n)) i piszemy: g(n) = (f (n)).
Mwimy, e funkcja g : N N jest (klasy) (f (n)) jeli g jest klasy
O(f (n)) i (f (n)).

Mamy

Fakt 4.1 Niech a, b, c bd liczbami rzeczywistymi dodatnimi. Rozwizaniem


rwnania rekurencyjnego
(

T (n) =

b
a T (n/c) + b n

gdy n = 1
gdy n > 1

dla n postaci ck , (gdzie k N ) jest funkcja


T (n) =

O(n)

O(n ln n)

O(nlogc a )

gdy a < c
gdy a = c
gdy a > c

Zauwamy, e jeli zinterpretujemy liczby a, b, c jako


1.

1
c

- rozmiar jednego podproblemu;

2. a - liczba podproblemw;
3. b n - czas budowania rozwizania problemu rozmiaru n z rozwiza
podproblemw;
to powyszy Fakt mona uy do obliczania zoonoci wielu algorytmw
zbudowanych metod 'dziel i rzd', take algorytmu sortowania przez
scalanie. W tym przypadku a = b = c = 2 a zatem T (n) = O(n ln(n)).
Pniej pokaemy te, e T (n) = (n ln(n)).
50

Dowd Faktu 4.1:


Niech r = ac , n = cm . Wtedy
T (n) = n b

m
X

ri

gdzie (m = logc n).

(10)

i=0

Rwno (10) udowodnimy przez indukcj po m.


Dla m = 0, mamy n = c0 = 1 oraz
T (n) = T (1) = b = n b

0
X

ri .

i=0

Czyli (10) zachodzi dla m = 0.


Zamy teraz, e (10) zachodzi dla n = cm . Wtedy uywajc denicji
rekurencyjnej T i zaoenia indukcyjnego mamy
T (cm+1 )

def T

a T (cm ) + b cm+1

=anb

m
X

ind.

ri + b cm+1 =

i=0

m
X
a m+1
c
b
ri + b cm+1 =
c
i=0
m
a X
= b cm+1 (
ri + 1) =
c i=0
m+1
X

= b cm+1 (

ri + r0 ) =

i=1

= b cm+1

m+1
X

ri

i=0

Zamy, e a < c. Wtedy szereg


1
rwna 1r
. Zatem
T (n) = n b

m
X
i=0

ri

i=0 r

1
1

a
c

jest zbieny i jego suma jest

b n = O(n).

Jeeli a = c to ri = 1 dla dowolnego i N . Wtedy dla n = cm , mamy


i
r=0 r = logc n oraz

Pm

T (n) = b n logc n = O(n ln n).

51

Niech a > c. Mamy m = logc n oraz


logc n

T (n) = n b

ri = b n

i=0

r1+logc n 1
=
r1

b
a
(n ( )1+logc n n) =
r1
c

b
a1+logc n
(n (
) n) =
r1
cn
ab
cn
=
(alogc n
)=
c (r 1)
a
cn
= const (nlogc a
) = O(nlogc a )
a
=

gdzie const jest sta a przedostatnia rwno wynika z rwnoci alogc n =


nlogc a . Poniewa a > c to logc a > 1.
Q.E.D.

4.3 Sortowanie przy pomocy porwna


W poprzednim podrozdziale pokazalimy, e mona skonstruowa algorytm,
ktry sortuje tablic n liczb w czasie O(n ln n), poprzez wskazanie konkretnego algorytmu ktry ma te wasno ('sortowanie przez scalanie'). Czy
mona zrobi to szybciej? Odpowied moe zalee od rnych szczegw.
Na przykad, jeeli zaoymy, e w tablicy sortowanej jest stosunkowo
niewiele rnych wartoci np. co najwyej 2 lub 3 lub 4 to mona posortowa taka tablic w czasie O(n). Z drugiej strony jeli chcemy pokaza, e
nie ma adnego algorytmy, ktry sortuje w czasie mniejszym ni O(n ln n),
to musimy dowie wicej (ni tylko wskaza algorytm i pokaza, e ma dane wasnoci), musimy pokaza e 'kady algorytm robi 'co innego' (albo
nie sortuje albo nie tak szybko jak bymy chcieli). By pokaza, e nie ma
programu sortujcego szybciej ni O(n ln n) zaoymy, e sortowanie odbywa
si metod porwna, tzn. porwnujemy elementy tablicy midzy sob i w
zalenoci od wyniku porwnania co przestawiamy lub nie.
Do abstrakcyjnej analizy algorytmw sortujcych przy pomocy porwna uyjemy drzewa decyzyjnego. Wierzchoki wewntrzne drzewa s etykietowane decyzjami do podjcia. Podczas obliczenia, w zalenoci od ich
wyniku przesuwamy si w lewo lub prawo. Licie drzewa s etykietowane
poprawnymi rozwizaniami. Drzewo decyzyjne dla sortowania trzech elementw a1 , a2 , a3 moe wyglda tak:
52

a1 < a2

a2 < a3

T
a1 < a2 < a3



T 


XXXN
XX
X

@ N
@

a1 < a3

T
a1 < a3 < a2

a3 < a2

a3 < a2 < a1

@ N
@

@ N
@

a1 < a3

a3 < a1 < a2

a2 < a1 < a3

@ N
@

a2 < a1 < a3

Jedno obliczenie w takim drzewie odpowiada jednej gazi drzewa. W liciach drzewa znajduj si wszystkie moliwe odpowiedzi, tzn. permutacje
zbioru {a1 , a2 , a3 } (kada co najmniej raz). Zatem wysoko drzewa - to
pesymistyczna zoono algorytmu. Mamy

Lemat 4.2 Drzewo decyzyjne dla dowolnego algorytmu sortujcego

mentw przy pomocy porwna ma wysoko (n ln n).

n ele-

Dowd: Niech H(n) bdzie wysokoci drzewa decyzyjnego dla pewnego


algorytmu sortujcego przy pomocy porwna. Takie drzewo ma co najmniej
n! lici. Poniewa pene drzewo binarne o wysokoci h ma 2h lici to dowolne
drzewo o wysokoci h ma co najwyej 2h lici. Std
n! 2H(n)

i
log2 (n!) H(n).

Poniewa n! ( n3 )n to
n
H(n) log2 (n!) log2 ( )n = n log2 n n log 3 = (n ln n).
3

Q.E.D.

Wniosek 4.3 Kady algorytm sortujcy tablic n elementw przy pomocy


porwna ma pesymistyczn zoono czasow (n ln n).

53

4.4 Programowanie dynamiczne


Programowanie dynamiczne (Pd) stosuje si do problemw optymalizacyjnych, w ktrych musimy dokonywa serii wyborw w celu znalezienia optymalnego rozwizania. Dokonujc wyborw, czsto musimy si wielokrotnie
odwoywa do rozwizania tego samego podproblemu. Jeli wszystkich podproblemw nie jest 'zbyt duo' to Pd jest metod efektywn. Algorytm Pd
rozwizuje problem tylko raz i zapamituje do ponownego wykorzystania.
Konstrukcja algorytmu:
1. Charakteryzacja struktury optymalnego rozwizania.
2. Rekurencyjna denicja optymalnego rozwizania.
3. Obliczenie kosztu i sposobu konstrukcji optymalnego rozwizania
metod 'od dou do gry' (bottom-up).
4. Konstrukcja optymalnego rozwizania przy uyciu informacji obliczonej w punkcie 3.
Niech ~x =< x1 , . . . , xm >, ~y =< y1 , . . . , yn > i ~z =< z1 , . . . , zk > bd
cigami. Wtedy
1. ~z jest podcigiem cigu ~x, jeeli istnieje rosncy cig liczb naturalnych
< i1 , . . . , ik > taki, e zj = xij dla j = 1, . . . , k .
2. ~z jest wsplnym podcigiem cigw ~x i ~y jeli jest podcigiem ~x i ~y.
3. N W P (~x, ~y) oznacza zbir najduszych wsplnych podcigw cigw
~x i ~y .
Przykad.
~x =< A, B, C, B, D, A, B >,

~y =< B, B, D, C, B, A, A >

~z =< B, D, A >,

z~0 =< D, C > .

Wtedy ~z jest podcigiem ~x i ~y a z~0 jest podcigiem ~x ale nie ~y.


Problem znajdowania najduszego wsplnego podcigu.

Dane wejciowe: dwa cigi ~x i ~y .


Wynik: ~z N W P (~x, ~y ).

54

Charakteryzacja najduszego wsplnego podcigu.

Cig dugoci n ma 2n podcigw. Zatem sprawdzenie wszystkich podcigw jest kosztowne. Ale problem N W P ma wasno optymalnej podstruktury.
Niech ~x =< x1 , . . . , xm > bdzie cigiem, i n. i-tym preksem cigu
~x nazywamy cig ~xi =< x1 , . . . , xi >.
Przykad.
~x =< A, B, C, B, D, A, B >, ~x4 =< A, B, C, B >, ~x0 =

Mamy

Fakt 4.4 Niech ~x =< x1 , . . . , xm > i ~y =< y1 , . . . , yn > bd cigami oraz


~z =< z1 , . . . , zk > N W P (~x, ~y ) . Wtedy
1. Jeeli xm = yn to zk = xm = yn oraz ~zk1 N W P (~xm1 , ~yn1 ).
2. Jeeli xm 6= yn oraz zk 6= xm to ~z N W P (~xm1 , ~y ).
3. Jeeli xm 6= yn oraz zk 6= yn to ~z N W P (~x, ~yn1 ).
Dowd:
Ad 1. Zamy, e xm = yn . Jeeli zk 6= xm to cig <
z1 , . . . , zk , xm jest wsplnym podcigiem ~x i ~y . Zatem ~z 6 N W P (~x, ~y ) a to
jest sprzeczne z zaoeniem. Std zk = xm . Podobnie mona pokaza, e
zk = y n .
Pokaemy, e ~zk1 N W P (~xm1 , ~yn1 ). Oczywicie ~zk1 jest podcigiem ~xm1 i ~yn1 . Przypumy, e istnieje duszy wsplny podcig
w
~ =< w1 , . . . , wk > cigw ~xm1 i ~yn1 . Wtedy cig < w1 , . . . , wk , xm >
jest wsplnym podcigiem ~x i ~y duszym od ~z. I znowu mamy sprzeczno.

Ad 2. Jeli zk 6= xm to ~z jest podcigiem ~xm1 . Jeli by istnia duszy


podcig ~xm1 i ~y to byby on te podcigiem ~x i ~y. A to jest sprzeczne z
zaoeniem.
Ad 3. Ten przypadek jest podobny do 2.
Q.E.D.

Wniosek 4.5 Najduszy wsplny podcig dwch cigw zawiera najdusze


wsplne podcigi preksw tych cigw.

Rekurencyjna denicja rozwizania.

Z podanego faktu wynika, e znalezienie ~z N W P (~x, ~y) sprowadza si


do znalezienia
z~0 N W P (~xm1 , ~yn1 ) gdy xm = yn

55

oraz dwch podproblemw znalezienia


z~1 N W P (~xm1 , ~y ),

z~2 N W P (~x, ~yn1 ) gdy xm 6= yn

Ten ktry jest duszy naley do N W P (~x, ~y).


Niech c(i, j) =dugo najduszego wsplnego podcigu cigw ~xi i ~yj .
Wtedy
c(i, j) =

c(i 1, j 1) + 1

max(c(i 1, j), c(i, j 1))

gdy i = 0 lub j = 0,
gdy xi = yj ,
gdy xi 6= yj .

T denicje mona atwo przetumaczy na funkcj rekurencyjnie obliczajc


c ale zoono jej bdzie wykadnicza.

Obliczanie kosztu i sposobu konstrukcji optymalnego rozwizania.


Moemy napisa funkcj, ktra oblicza koszt rozwizania optymalnego
'od dou do gry'. To znaczy liczy dugo najduszego wsplnego podcigu
preksw cigw ~x i ~y od najkrtszych a do caych cigw ~x i ~y. By po takim
obliczeniu mc odtworzy najduszy wsplny podcig, przy okazji liczenia
c(i, j) dla i, j > 0 musimy zapamita z ktrej klauzuli denicji funkcji c
korzystalimy i jeeli z trzeciej to ktra z wartoci c(i 1, j), c(i, j 1) bya
wiksza.
Innymi sowy funkcja ta rozwizuje nastpujcy problem:
Dane wejciowe: dwa cigi ~x i ~y .
Wynik: dwie tablice; c jak wyej i b tak, e b(i, j) ='wskazwka' jak
oblicza optymalne rozwizanie dla ~xi i ~yj .

Tablice b i c (zwaszcza b) bd nam pomocne do znalezienia rozwizania.


procedure dlugosc_NWP(x,y);
begin
m:=dlugosc(x);
n:=dlugosc(y);
for i:=1 to m do c[i,0]:=0;
for i:=1 to n do c[0,i]:=0;
for i:=1 to m do
for j:=1 to n do
if x[i]=y[j] then begin

56

end;

c[i,j]:=c[i-1,j-1]+1; {skracamy oba ciagi}


b[i,j]:='xy'
end else
if c[i-1,j]>=c[i,j-1] then begin
c[i,j]:=c[i-1,j]; {skracamy x}
b[i,j]:='x'
end else begin
c[i,j]:=c[i,j-1]; {skracamy y}
b[i,j]:='y'
end;
end;

Przykad. Ponisza tablica opisuje wartoci tablic b i c obliczone dla cigw


~x =< A, B, C, B, D, A, B > i ~y =< B, D, C, A, B, A > (m = 7, n = 6).
j
i
0
1
2
3
4
5
6
7

~x
A
B
C
B
D
A
B

0
1
2
3
4
5
6
~y
B
D
C
A
B
A
0
0
0
0
0
0
0
0
x, 0 x, 0 x, 0 xy, 1 y, 1 xy, 1
0
xy, 1 y, 1 y, 1 x, 1 xy, 2 y, 2
0
x, 1 x, 1 xy, 2 y, 2 x, 2 x, 2
0
xy, 1 x, 1 y, 2 y, 2 xy, 3 y, 3
0
x, 1 xy, 2 x, 2 x, 2 x, 3 x, 3
0
x, 1 x, 2 x, 2 xy, 3 x, 3 xy, 4
0
xy, 1 x, 2 x, 2 x, 3 xy, 4 x, 4

W prawym dolnym rogu mamy c[7, 6] = 4. Zatem najduszy wsplny


podcig ~x i ~y ma dugo 4. Z tego rogu podrujc w gr gdy b[i, j] =0 x0 , w
lewo gdy b[i, j] =0 y 0 , oraz po skosie b[i, j] =0 xy 0 , zbieramy kolejne elementy
najduszego wsplnego podcigu ~x i ~y. W ten sposb znajdujemy, e <
B, C, B, A > N W P (~x, ~y ).

Konstrukcja optymalnego rozwizania.

Majc tablic b moemy teraz wypisa cig ~z N W P (~x, ~y).


procedure drukuj_NWP(i,j);
begin
if (i<>0) and (j<>0) then begin
if b[i,j]='xy' then begin
drukuj_NWP(i-1,j-1);

57

write(x[i])
end else
if b[i,j]='x' then drukuj_NWP(i-1,j)
else drukuj_NWP(i,j-1);
end;
end;

Teraz instrukcja drukuj_NWP(dlugosc(x),dlugosc(y)) drukuje ~z


N W P (~x, ~y ).

58

4.5 Algorytmy zachanne


Typowe algorytmy optymalizacyjne dokonuj szeregu wyborw w celu
znalezienia optymalnego rozwizania. S jednak liczne problemy przy
rozwizywaniu ktrych nie trzeba stosowa metody programowania dynamicznego a wystarcz prostsze i bardziej efektywne algorytmy. Algorytmy
zachanne wybieraj to co w danym momencie wyglda najlepiej w nadziei,
e doprowadzi to do optymalnego globalnego rozwizania. Metod t zilustrujemy rozwizujc nastpujcy problem.
Problem wyboru zaj

Mamy sal wykadow i zbir propozycji na jej wykorzystanie do


prowadzenia rnych zaj w okrelonych godzinach. Chcemy wybra maksymaln liczb zaj nie kolidujacych ze sob. Formalnie problem ten wyglda
tak:
Dane wejciowe: zbir n przedziaw P = {[si , fi ) : 1 i n}, taki,
e si , fi R si < fi dla i = 1, . . . , n.
Wynik: podzbir A {1, . . . , n} o maksymalnej liczbie elementw
taki, e dla i, j A, i 6= j mamy [si , fi ) [sj , fj ) = .

Opis algorytmu.

1. Porzdkujemy przedziay wzgldem ich prawych kocw, tak by fi


fj dla 1 i < j n.
2. Wybieramy po kolei takie zajcia, ktre nie koliduj z ju wybranymi
i si najwczeniej kocz:
function wybor_zajec;
begin
A:={1};
j:=1; {j - ostatnio wybrany element}
for i:=2 to n do
if s[i]>=f[j] then begin
A:=A+{i};
j:=i;
end;
zwroc(A);
end;

59

Fakt 4.6 Powyszy algorytm znajduje optymalne rozwizanie problemu


zgodnego wyboru zaj.

Dowd. Niech B {1, . . . , n} bdzie optymalnym rozwizaniem, |B| =


k , oraz niech A {1, . . . , n} bdzie zbiorem skonstruowanym przez algorytm.
Niech Al bdzie zbiorem pierwszych l elementw z A, B l zbiorem powstaym
z B po usuniciu pierwszych l elementw.
Zauwamy, e sposb konstrukcji zbioru A gwarantuje, e rne przedziay o indeksach z A s rozczne.
Pokaemy przez indukcj po l = 1, . . . , k, e
Al jest okrelone i Al B l jest optymalnym rozwizaniem.

(11)

Wtedy dla k = l mamy B k = i Ak B k A jest optymalnym rozwizaniem,


czyli Ak = A.
Pozostaje pokaza (11). Dla l = 1 mamy pokaza, e A1 B 1 =
{1} B {min(B)} jest optymalnym rozwizaniem. Poniewa f1 fmin(B)
(fi s uporzdkowane niemalejco) to przedzia [s1 , f1 ) jest rozczny z
przedziaami [si , fi ) dla i B {min(B)}. Zatem zbir A1 B 1 = {1} B 1
ma k elementw i jest optymalnym rozwizaniem.
Zamy, e 1 l < k i Al B l jest optymalnym rozwizaniem. Poniewa
l < k to
=
6 B l {j : sj fmax(Al ) } =
6 .

Niech i = min{j : sj fmax(Al ) }. Wtedy Al+1 = Al {i}. Z denicji i,


si fmax(Al ) , a to oznacza, e przedzia [si , fi ) jest rozczny z przedziaami
w Al . Ponadto z minimalici i, fi fmin(B l ) . Zatem [si , fi ) jest rozczny z
przedziaami w B l+1 = B l {min(B l )}. A to oznacza, e Al+1 B l+1 jest
optymalnym rozwizaniem.
Q.E.D.
By mona byo stosowa algorytmy zachanne, podane jest by problem
mia dwie cech:
1. Wasno zachannego wyboru: globalne optymalne rozwizanie moe
by otrzymane przez lokalne optymalne (zachanne) wybory.
2. Optymalna podstruktury: (jak w Pd) optymalne rozwizanie problemu
zawiera optymalne rozwizanie podproblemw.
Uwaga. Nie kada moliwa strategia wyboru zachannego dla problemu wyboru zaj daje optymalne rozwizanie. Na przykad wybr zaj
niekolidujcych z ju wybranymi, ktre:

60

1. trwaj najkrcej,
2. koliduj z najmniejsz liczb pozostaych zaj
nie daje optymalnego rozwizania. Ponisze przykady wyjaniaj dlaczego.
W tym przypadku

wybierajc najkrtsze zajcia wybierzemy tylko dwa, gdy mona by wybra


trzy, a w tym

wybierajc zajcia kolidujce z najmniejsz liczb pozostaych zaj, zaczniemy od zaj oznaczonych i w efekcie wybierzemy trzy, gdy mona by
wybra cztery.
Problemy plecakowe.

Problemy plecakowe dotycz pakowania do plecaka przedmiotw ktre


maj w sumie najwiksz warto nie przekraczajc jednak dopuszczalnego
obcienia plecaka. W jednej wersji musimy pakowa cae przedmioty a w
drugiej moemy pakowa take tylko czci przedmiotw. Mimo, e problemy wygldaj podobnie jeden moe by atwo rozwizany przy pomocy
algorytmu zachannego a drugi nie ma efektywnego rozwizania. Formalnie
problemy te mona sformuowa tak.

Problem plecakowy 0-1.


Dane wejciowe: n przedmiotw, i-ty przedmiot jest wart vi zotych i
way wi kilogramw, w jest dopuszczalnym ciarem plecaka.
Wynik: podzbir A {1, . . . , n} taki, e
P
iA vi jest maksymalna.

iA wi

w oraz warto

Problem plecakowy uamkowy.


Dane wejciowe: n przedmiotw, i-ty przedmiot jest wart vi zotych i
way wi kilogramw, w jest dopuszczalnym ciarem plecaka.
Wynik: podzbir A {1, . . . , n} oraz liczby ri R dla i A takie, e
P
P
iA ri wi w oraz warto
iA ri vi jest maksymalna.

61

Dla problemu 01 nie jest znane istotnie lepsze rozwizanie ni przegldanie wszystkich moliwych podzbiorw przedmiotw. Natomiast problem
uamkowy mona rozwiza 'zachannie' w nastpujcy sposb:
1. Porzdkujemy przedmioty wzgldem malejcej wartoci
2. WybieramPpierwsze k przedmiotw tak, e
oraz w ki=1 wi z k + 1-go przedmiotu.

62

Pk

i=1 wi

vi
wi .

w <

Pk+1
i=1

wi

4.6 Algorytm sortowania przez kopcowanie (heapsort)


Algorytm sortowania przez kopcowanie podobnie do algorytmu sortowania
przez scalanie dziaa w czasie O(n ln(n)) ale ma t wasno, e sortuje 'w
miejscu' tzn. nie uywa dodatkowej tablicy. Algorytm ten uywa struktury
kopca.
Kopiec jest to drzewo binarne etykietowane liczbami rzeczywistymi (lub
innymi obiektami na ktrych jest zdeniowany liniowy porzdek), takie, e
etykieta kadego wierzchoka jest niemniejsza od etykiety synw tego wierzchoka.
Przykad. Kopiec moe wyglda na przykad tak:
17




11
10

@
@

XX
XXX
X

15
@
@

14
@
@

@
@

13

@
@

7
C
C

W szczeglnoci wierzchoki na kadej ciece s uporzdkowane w porzdku


nierosncym i etykieta korzenia ma maksymaln warto.
Opis algorytmu sortowania przez kopcowanie.

1. Tworzymy kopiec etykietowany elementami sortowanego cigu.


2. Najwiksz etykiet w drzewie (znajdujc si w korzeniu) usuwamy a
na jej miejsce wstawiamy etykiet z jednego z lici. Li ten usuwamy
i poprawimy drzewo tak by znowu tworzyo kopiec.
3. Krok 2. powtarzamy dopki drzewo jest niepuste.
4. Elementy usuwane z kopca tworz cig posortowany.
Kopiec o n wierzchokach mona wygodnie reprezentowa w nelementowej tablicy A:

63

korze

2i 2i + 1

lewy syn

wierzchoek

prawy syn

Wtedy:
1. A[1] jest etykiet korzenia;
2. synowie i-tego wierzchoka maj numery 2i oraz 2i + 1;
3. i jest liciem gdy n < 2i;
4. warunek kopca wyraa nierwno: A[i] A[bi/2c] dla i = 1, . . . , n.
Program bdzie uywa dwch procedur: kopcuj oraz buduj_kopiec.
Procedura buduj_kopiec buduje kopiec.
Wywoanie procedury
kopcuj(i,j) odtwarza struktur kopca we fragmencie tablicy od itego do j -tego miejsca zakadajc, e w elementy tablicy od i + 1-ego do
j -tego miejsca speniaj wasno kopca.
procedure kopcuj(i,j);
begin
l:=2*i; r:=2*i+1; {l, r -synowie i}
if (l<=j) and (A[l]>A[i]) then w:=l
else w:=i;
if (r<=j) and (A[r]>A[w]) then w:=r;
{po tych zamianach A[w] ma najwieksza wartosc z A[l], A[r], A[i]}
if w<>i then begin
zamien(A[i],A[w]);
kopcuj(w,j)
end;
end;

Procedura kopcuj(i,j) bez odwoa rekurencyjnych wykonuje sta


liczb porwna. Jeli procedura kopcuj(i,j) woa kopcuj(w,j) to j
w 2i. Zatem procedura kopcuj(i,j) woa siebie O(ln(n)) i dziaa w
czasie O(ln(n)).
procedure buduj_kopiec; {tworzenie kopca}
begin
for i:=n div 2 downto 1 do
kopcuj(i,n)
end;

64

Program gwny, uywajc powyszych procedur, realizuje algorytm sortowania przez kopcowanie:
begin{program gwny}
buduj_kopiec;
for i:=n downto 2 do begin
zamien(A[i],A[1]);
kopcuj(1,i-1)
end;
end.

Lemat 4.7 Zamy, e elementy tablicy A[i+1], . . . , A[j] speniaj warunek

kopca, 1 < i < j . Wtedy

1. Po wykonaniu procedury kopcuj(i,j) elementy A[i], . . . , A[j] speniaj


warunek kopca.
2. Procedura kopcuj(i,j) wraz z odwoaniami rekurencyjnymi wykonuje
co najwyej tyle porwna co wysoko i-teg wierzchoka w drzewie o j
wierzchokach.
Dowd: wiczenie.

Lemat 4.8 Procedura buduj_kopiec dziaa w czasie O(n).


Dowd: Procedura kopcuj(i,n) jest wywoywana raz dla kadego wierzchoka 1 i n. Dla i-tego wierzchoka kopcuj(i,n) wykonuje (wraz z
odwoaniami rekurencyjnymi) co najwyej tyle porwna co wysoko i-tego
wierzchoka. Zatem w procedurze buduj_kopiec liczba porwna jest co
najwyej taka jak suma wysokoci wszystkich wierzchokw drzewa.
Niech W (n) bdzie sum wysokoci wierzchokw drzewa binarnego o n
wierzchokach.
Pene drzewo binarne o wysokoci m ma 2m+1 1 wierzchokw i 2m
lici.
Niech hn (i) bdzie liczb wierzchokw o wysokoci i w drzewie o n wierzchokach. Mamy
hn (i) hn0 (i) dla n n0 .

Niech 2m n n0 = 2m+1 1. Wtedy


hn0 (i) = 2mi .

65

Std
W (n) =

m
X

i hn (i)

i=1

= 2m

m
X

i hn0 (i) =

i=1
m
X
i=1

m
X

i 2mi =

i=1

i
c n = O(n)
2i

Q.E.D.

Twierdzenie 4.9 Algorytm sortowania przez kopcowanie dziaa w czasie


O(n ln(n)).

Dowd: Procedura buduj_kopiec Wykonuje O(n) porwna. Nastpnie


algorytm wykonuje n-krotnie procedur kopcuj(1,i) dla i = 1, . . . , n. Procedura kopcuj(1,i) wykonuje co najwyej O(ln(i)) porwna. Zatem cay
algorytm dziaa w czasie O(n ln(n)).
Q.E.D.

66

4.7 Podsumowanie
Mamy cztery metody konstrukcji rozwiza problemw optymalizacyjnych:
1. Metoda powrotw: rozszerzamy czciowe poprawne rozwizanie a
do uzyskania penego poprawnego rozwizania. Jeli si nie da rozszerzy czciowego rozwizania to wracamy i poprawiamy czciowe
rozwizanie w pierwszym moliwym miejscu.
Przykady.
(a) Ustawienia Hetmanw
(b) Konik szachowy
(c) Kwadrat magiczny
2. Metoda 'dziel i rzd' : problem dzielimy na mniejsze podproblemy,
ktre rozwizujemy rekurencyjnie, i z tych rozwiza podproblemw
budujemy rozwizanie caego problemu. By taka metoda bya efektywna problemy powinny by w 'sensowny sposb' rozczne. Przykady.
(a) Sortowanie przez scalanie
(b) Wypenienie tablicy 2n 2n ksztatem L tak by dokadnie jedno
ustalone pole zostao nie pokryte.
3. Programowanie dynamiczne: Jeli przy rozwizaniu problemu musimy
si odwoywa wielokrotnie do rozwizania tych samych podproblemw
to metoda 'dziel i rzd' moe nie by efektywna. Jeli podproblemw
jest 'stosunkowo niewiele' (wielomianowo wiele) w stosunku do rozmiaru problemu to mona je wszystkie 'rozwiza' (lub jako zapamita
sposb ich rozwizania) od dou go gry w sposb efektywny.
Konstrukcja algorytmu:
(a) Charakteryzacja struktury optymalnego rozwizania.
(b) Rekurencyjna denicja optymalnego rozwizania.
(c) Obliczenie kosztu i sposobu konstrukcji optymalnego rozwizania
metod 'od dou do gry' (bottom-up).
(d) Konstrukcja optymalnego rozwizania przy uyciu informacji
obliczonej w punkcie 3.
By taka metoda bya skuteczna liczba podproblemw nie moe by
zbyt du. Przykady.
67

(a)
(b)
(c)
(d)

Wybr najduszego wsplnego podcigu,


Wybr rozmieszczenia nawiasw przy mnoeniu macierzy,
Triangulacja wielokta,
Obliczanie dwumianu Newtona.

4. Algorytmy zachanne: wybieraj to co w danym momencie wyglda


najlepiej w nadziei, e doprowadzi to do optymalnego globalnego
rozwizania. S bardzo efektywne.
Przykady.
(a) Zgodny wybr zaj,
(b) Uamkowy problem plecakowy,
(c) Algorytmy grafowe.

68

Reprezentacja liczb na komputerze (2)

5.1 Systemy liczbowe o rnych podstawach


System dziesitny

Cyfry: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Liczba 764.5 oznacza 7 102 + 6 101 + 4 100 + 5 101 .
System ten jest wygodny dla czowieka a dla maszyny mniej. Reprezentacja cyfry dziesitnej zajmuje cztery bity pamici komputera:
cyf ra reprezentacja
0
0000
1
0001
2
0010
3
0011
4
0100
5
0101
6
0110
7
0111
8
1000
9
1001

W ten sposb marnujemy cz pamici poniewa s kombinacje (np. 1101),


ktre nie oznaczaj adnej cyfry dziesitnej.

System dwjkowy

Cyfry: 0, 1
Liczba (1010.1.5)2 oznacza 1 23 + 0 22 + 1 21 + 0 20 + 1 21 .
System dwjkowy dobrze pasuje do maszyny gdy reprezentacja jednej
cyfry zajmuje dokadnie jeden bit. n-cyfrowa liczba (bez znaku) pamitana
jest w sowie n-bitowym. Natomiast dla czowieka jest on zbyt rozwleky.
Przypomnijmy, e istnieje prosty sposb konwersji zapisu dziesitnego
liczby na dwjkowy:

1. cz cakowit dzielimy przez 2 i bierzemy reszty,


2. cz uamkow mnoymy przez 2 i bierzemy czci cakowite (a do
uzyskania danej precyzji).
Przykad. Dla liczby x = (43.625)10 liczymy

69

43
21
10
5
2
1
0

1
1
0
1
0
1

625
1 250
0 500
1 000

i otrzymujemy
x = (101011.101)2

W przypadku niektrych liczb reprezentowanych w systemie


dziesitkowym moemy uzyska tylko przyblione reprezentacje dwjkowe.
Na przykad dla liczby y = (69.76)10 powysza procedura si nie zakoczy
69
34
17
8
4
2
1
0

1
1
0
0
0
0
1
...

1
0
1
0
0
0
1

76
52
04
08
16
32
64
28
...

i otrzymujemy wynik przybliony


y (1000101.1100001)2 .

System szesnastkowy

Cyfry: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
Liczba E9B.F oznacza 14 162 + 9 161 + 11 160 + 15 161 .
System ten w zasadzie czy dobre cechy systemu dwjkowego i dziesitnego. Jest bardziej zwizy od dwjkowego i lepiej wykorzystuje pami ni
system dziesitkowy. Reprezentacja cyfry szesnastkowej zajmuje cztery bity

70

pamici komputera:
cyf ra reprezentacja
0
0000
1
0001
2
0010
3
0011
4
0100
5
0101
6
0110
7
0111

cyf ra reprezentacja
8
1000
9
1001
A
1010
B
1011
C
1100
D
1101
E
1110
F
1111

i kada kombinacja 4-bitowa odpowiada pewnej cyfrze szesnastkowej. Dlatego czsto system szesnastkowy jest stosowany do zapisu liczb liczb
dwjkowych. Na przykad kody ASCII znakw s czsto podawane przy uyciu dwucyfrowych liczb szesnastkowych. Natomiast ludzkie przyzwyczajenie
do operowania w systemie dziesitkowym jest tak ugruntowane, e aden
inny system pozycyjny nie moe mie szerszego znaczenia w komunikacji
midzy ludmi.

5.2 Reprezentacja staopozycyjna liczb cakowitych


Liczby cakowite ze znakiem s pamitane w sowach n-bitowych. Ustalmy

n = 8.

bit znaku
reprezentacja moduu liczby
@
@
0 = '+' @
@
@
R

R
@
1 = '-'
0 1 0 0 1 1 0 1

Nieujemna liczba cakowita jest pamitana jako znak i modu liczby zapisany
w systemie dwjkowym. Powysze sowo reprezentuje liczb 77. Natomiast
jeli liczba jest ujemna to istnieje kilka sposobw jej reprezentacji:
1. znak-modu: wygodny dla czowieka, ale przy operacjach arytmetycznych trzeba porwnywa znaki i 0 ma dwie reprezentacje4 ('dodatni'
i 'ujemn').
2. znak-uzupenienie do 1: ta reprezentacja jest mniej wygodna dla
czowieka i w niej te 0 ma dwie reprezentacje.
To, e 0 ma dwie reprezentacje nie jest tylko spraw estetyki. Gdy jeden obiekt
ma rne reprezentacje, sprawdzenie rwnoci dwch obiektw staje si niepotrzebnie
skomplikowana procedur.
4

71

3. znak-uzupenienie do 2: ta reprezentacja jest jeszcze mniej wygodna


dla czowieka ale w niej 0 (i kada inna reprezentowana liczba) ma tylko
jedn reprezentacj, ponadto operacje arytmetyczne s wykonywane w
prosty sposb.
Ze wzgldu na przytoczone powyej zalety zajmiemy si bliej sposobem
reprezentacji liczb jako znak-uzupenienie do 2. Ten jaki jest w praktyce
uywany do reprezentacji liczb cakowitych na komputerach.
Dla

Uzupenienie do 1 liczb cakowitych otrzymujemy negujc wszystkie bity.


x = 10011000

uzupenienie do 1 liczby x jest rwne


01100111

Uzupenienie do 2 liczb cakowitych otrzymujemy negujc wszystkie bity i


dodajc 1. Dla x jak wyej uzupenienie do 2 liczby x jest rwne
+

01100111
1
01101000

tzn. by otrzyma uzupenienie do 2 liczby cakowitej zostawiamy z prawej


strony wszystkie zera i pierwsz jedynk a reszt bitw negujemy:
01101000

Reprezentacja liczb cakowitych w systemie znak-uzupenienie

do 2 (n = 8):

1. dla 0 x 127
bit znaku

moduu liczby x
zapisanej w systemie dwjkowym

@
@
R
@

@
@
R
@

2. dla 128 x 1
bit znaku

uzupenienie do 2 moduu liczby x


zapisanej w systemie dwjkowym

@
@
R
@

@
@
R
@

72

Przykad. Sowo
0 1 0 1 0 0 0 0

reprezentuje liczb dodatni 80 natomiast sowo


1 1 0 1 0 0 0 0

reprezentuje liczb ujemn (0110000)2 = 48.

5.3 Operacje arytmetyczne staopozycyjne


Reprezentujc liczby w systemie znak-uzupenienie do 2, przy dodawaniu
nie trzeba zwraca uwagi na znak liczby. Wyniki otrzymujemy poprawne
i dokadne o ile argumenty i wartoci maj swoje reprezentacje jako sowa
n-bitowe w systemie znak-uzupenienie do 2.
1. Zmiana znaku Uzupeniamy do 2 liczb (cznie z bitem znaku):
x = 26

0 0 0 1 1 0 1 0

x = 26 1 1 1 0 0 1 1 0

2. Dodawanie Dodajemy dwie liczby cznie z bitem znaku i ewentualne


przeniesienie pomijamy. Wynik reprezentuje sum w systemie znakuzupenienie do 2:
x = 24

0 0 0 1 1 0 0 0

y = 40 1 1 0 1 1 0 0 0

x + y = 16 1 1 1 1 0 0 0 0

3. Odejmowanie Dodajemy odjemn do liczby przeciwnej do odjemnika.

73

4. Mnoenie i dzielenie Nie tak prosto. Najlepiej mnoy i dzieli moduy


a potem ustala znak. Jeli mnonik jest dodatni to mona mnoy
jak zwykle.
Uwaga. Zakres liczb cakowitych reprezentowanych w komputerze jest
zwykle do may a operacje s wykonywane dokadnie. Dla liczb rzeczywistych jest odwrotnie, zakres jest duy a operacje s wykonywane w sposb
przybliony.

5.4 Reprezentacja zmiennopozycyjna liczb rzeczywistych


Opiszemy teraz reprezentacj zmiennopozycyjn liczb rzeczywistych tcyfrow, dziesitn.
Dowoln liczb rzeczywist x 6= 0 mona przedstawi w postaci znormalizowanej:
x = m 10c

gdzie 0.1 |m| < 1, c - liczba cakowita. Liczb m nazywamy cech a liczb
c - mantys liczby x.
Dla x rwnego 0 przyjmuje si m = 0 i c = 0.
Przykad. Dla
x = 0.00354

po znormalizowaniu otrzymujemy
x = 0.354 102

Mantysa i cecha s pamitane w komputerze w postaci staopozycyjnej


dziesitnej. W arytmetyce t-cyfrowej mantysa ma t-cyfr i jest na og
wielkoci zaokrglon. Zakres cech decyduje o zakresie liczb rzeczywistych
reprezentowanych w komputerze. Liczba cyfr mantysy decyduje o precyzji
liczb pamitanych na komputerze.
Przykad. Przyjmijmy, e w naszej reprezentacji mantysa jest 4-cyfrowa
a cecha 1-cyfrowa.
liczba
x
a1 = 16 = 0.166(6)
a2 = 42.5368
a3 = 6 042 875
a4 = 7.67443

przyblienie
x
a1 = 0.1667 100
a2 = 0.4254 102
a3 = 0.6043 104
a4 = 0.7674 101

74

Bd bezwzgldny przyblienia jest to modu rnicy midzy wartoci


rzeczywist a wartoci przyblion:
a = |a a|

Mamy nastpujce oszacowanie bdu zaokrglenia mantysy:


|m m| 0.5 10t

A std, dla liczby dla a = m 10c , bd bezwzgldny wartoci przyblionej


a mona oszacowa tak:
a = |a a| = |m 10c m 10c | 0.5 10t 10c

Bd wzgldny przyblienia jest to bd bezwzgldny podzielony przez


modu dokadnej wartoci liczby:
a = |

a
aa
|=
|a|
a

Dla a = m 10c , mamy nastpujce oszacowanie bdu wzgldnego:


a = |

aa
0.5 10t 10c
0.5 10t 10c
|

= 5 10t
a
m 10c
0.1 10c

Wielko u = 5 10t jest wzgldn dokadnoci komputera.


Poniewa
|

aa
|u
a

to dla pewnego mamy


a = a(1 + )

gdzie || u.
Uwaga. Zwykle bd wzgldny jest lepsz miara przyblienia.

O liczb rzeczywistych na komputerze prezentuje si mniej wicej tak


(cecha 2-cyfrowa, mantysa 4-cyfrowa):
nadmiar
K

niedomiar
k 0 k = 0.1 1099

75

nadmiar
K = 0.9999 1099

Przedzia [K, K] stanowi zakres licz reprezentowanych na komputerze.


Poza tym przedziaem wystpuje nadmiar. Liczby o module wikszym od
K nie maj reprezentacji. Przedzia [k, k] jest nazywany niedomiarem.
Liczby z tego zakresu s reprezentowane przez 0, k, lub k z duym bdem
wzgldnym.

5.5 Arytmetyka zmiennopozycyjna


Nie tylko wartoci liczb zmiennopozycyjnych s przyblione ale operacje arytmetyczne wykonywane na przyblieniach liczb te nie musz mie dokadnej
reprezentacji. Zatem przy wykonywaniu dziaa arytmetycznych w arytmetyce zmiennopozycyjnej bdy przyblie si kumuluj. Opiszemy teraz
te operacje i oszacujemy bdy jakie przy nich powstaj.
1. Mnoenie wykonujemy w nastpujcy sposb
(a) mnoymy mantysy,
(b) dodajemy cechy,
(c) normalizujemy.
Przykad. Obliczymy reprezentacj zmiennopozycyjn iloczynu a =

0.375 102 i b = 0.225 103 . Obliczamy iloczyn mantys


0.375
0.225
1875
750
750
0.084375

i po normalizacji otrzymujemy a b = 0.8438 104 . Zatem


a b = a b(1 + ),

dla || u.
2. Dzielenie wykonujemy podobnie
(a) dzielimy mantysy,
(b) odejmujemy cechy,
(c) normalizujemy.
76

3. Dodawanie jest nieco bardziej skomplikowane i wykonujemy je w


nastpujcy sposb
(a) wyrwnujemy cechy zwikszajc mniejsz i przesuwajc mantys
mniejszej w prawo,
(b) dodajemy mantysy,
(c) normalizujemy.
Przykad. Obliczymy reprezentacj zmiennopozycyjn sumy a =
0.357 103 i b = 0.268 104 . Obliczamy sum 'wyrwnanych' man-

tys

0.036
0.268
0.304

i otrzymujemy a + b = 0.304 104 . Mona pokaza, e istniej 1 , 2


takie, e
a + b = a(1 + 1 ) + b(1 + 2 )

oraz |1 |, |2 | u.
4. Odejmowanie jest wykonywane podobnie do dodawania.
Oszacujemy teraz bd wzgldny mnoenia i dodawania.
Dla mnoenia mamy


a b a b a b a b(1 + )


= || u

=



ab
ab

Zatem bd wzgldny mnoenia nie przekracza wzgldnej dokadnoci komputera. Jeli ju liczby mnoone s przyblione to bdy si kumuluj.


(a(1 + 1 ) b(1 + 2 ))(1 + ) a b

=


ab


a b((1 + 1 + 2 + 1 2 ))(1 + ) a b
=

ab

= |(1 + 2 + 1 2 )(1 + )| 2 u

Czyli bd wyniku mnoenia jest rzdu 2 u, o ile bd reprezentacji argumentw nie przekracza wzgldnej dokadnoci komputera.
77

Dla dodawania mamy




(a(1 + 1 ) + b(1 + 2 )) (a + b)




a+b

|a| |1 | + |b| |2 |
|a| + |b|

u
|a + b|
|a + b|

Jeli liczby a i b s maj przeciwne znaki i nieznacznie rnice si moduy to


|a|+|b| moe by due podczas gdy |a+b| bdzie bardzo mae i w konsekwencji
|a|+|b|
|a+b| moe by bardzo due. W takim przypadku moemy po jednej operacji
dodawania znacznie utraci dokadno obliczenia. Taka sytuacj obrazuje
nastpujcy przykad.
Przykad. Obliczymy rnic liczb a = 10.0726 i b = 10.0789 w arytmetyce 5-cyfrowej . Mamy przyblienia
a = 0.10073 102

b = 0.10079 102

Bd wzgldny przyblie a i b



a a 4 106 102
=
a =
< 4 105 u(= 5 105 )
a 10.0726


b b
106 102


b =
< 105 u
=
b
10.0789

nie przekracza wzgldnej dokadnoci komputera. Natomiast bd rnicy





(b a) b a 6.3 103 6 103




=
=



(b a)
6.3 103

4
0.3
> 4 102 = 103 u
6.3
5

W szczeglnoci zmiennopozycyjne dziaania mnoenia i dodawania s


przemienne ale nie s czne!

78

5.6 Wybrane problemy numeryczne


W tej sekcji pokaemy kilka typowych problemw zwizanych obliczeniami
zmiennopozycyjnymi.

Obliczanie pierwiastkw rwnania kwadratowego


Rwnanie kwadratowe
x2 + px + q = 0

ma pierwiastki
x1 =

p2 4q
2

x1 =

p +

p2 4q
2

o ile wyrnik = p2 4q jest nieujemny. Obliczymy te pierwiastki w


arytmetyce 4-cyfrowej dla
p = 6.433

q = 0.009474.

Obliczenie x1 :
1. = (6.433)2 = 41.38,
2. = 4q = 0.03790,
3. = = 41.34,

4. = = 6.430,
5. 1 = p = 6.433 6.430 = 0.003,
6. x1 =

1
2

= 1.5 103 .

Poniewa przybliona warto pierwiastka x1 w arytmetyce 5-cyfrowej


wynosi
x1 1.4731 103

to widzimy, e nasze obliczenie x1 dao nam tylko jedn dokadn cyfr


znaczc i bd wzgldny wynosi
x1 101 .

Korzystajc z poprzednich oblicze moemy obliczy x2 :


1. 2 = p + = 6.433 + 6.430 = 12.86,
79

2. x2 =

2
2

= 6.43.

Poniewa przybliona warto pierwiastka x2 w arytmetyce 5-cyfrowej


wynosi
x2 6.4313

to widzimy, e nasze obliczenie x2 dao nam dokadne trzy cyfry znaczce.


Przyczyna utraty dokadnoci w obliczeniu x1 tkwi w obliczeniu 1 w
kroku 5. Obliczamy rnic liczb o bardzo bliskich wartociach. Natomiast
problem ten nie istnieje przy obliczaniu 2 w kroku 2. obliczenia x2 . Tam
liczymy sum tych liczb nie tracc istotnie na dokadnoci.
Majc dobre przyblienie x2 , moemy te obliczy x1 ze wzoru Viete'a
x1 x2 = q :


x1 =

0.009474
6.430

= 0.001473 = 1.473 103

i wtedy mamy cztery cyfry dokadne oraz bd wzgldny


x1 104 .

Mora z tych rozwaa jest taki, e jeeli p > 0 to x1 jest liczone dokadniej a jeeli p < 0 to x2 jest liczone dokadniej.

Schemat Hornera obliczania wielomianu


Normalna procedura obliczenia wartoci wielomianu n-tego stopnia
Wn (x) = an xn + an1 xn1 + . . . + a1 x + a0 ,

sugerowana przez sposb zapisu wielomianu, polega na obliczeniu


1. x2 , x3 , . . . , xn - n 1 mnoe,
2. a1 x, a2 x2 , . . . , an xn - n mnoe,
3. a0 + a1 x + . . . + an1 xn1 + an xn n -dodawa.
Zatem takie obliczenie wymaga 2n 1 mnoe i n dodawa.
Natomiast istnieje inny sposb obliczania tej samej wartoci, zaproponowany przez Hornera. Liczymy:
1. Pn (x) = an x + an1 - 1 mnoenie i 1 dodawanie,
2. Pn1 (x) = (an x + an1 )x + an2 - 1 mnoenie i 1 dodawanie,
80

3. . . .
4. P1 = P2 x + a0 - 1 mnoenie i 1 dodawanie.
Zatem takie obliczenie wymaga tylko n mnoe i n dodawa. Oprcz tego,
e ta metoda obliczania wartoci wielomianu jest szybsza to jest te dokadniejsza.

81

Dynamiczne struktury danych (4)

'Zbiory matematyczne' nie zmieniaj si, natomiast 'zbiory informatyczne'


mog si zwiksza, zmniejsza lub zmienia w inny sposb. S to 'zbiory
dynamiczne'.
Sposb w jaki reprezentujemy 'zbiory dynamiczne' zaley od tego jakie
operacje chcemy na nich wykonywa. Mamy dwa rodzaje operacji: modykacje i pytania.

Modykacje (przykady):
1. dodaj(S,x) - dodaj element (wskazywany przez) x do zbioru S ;
2. usun(S,x) - usu element (wskazywany przez) x ze zbioru S .

Pytania (przykady):
1. szukaj(S,k) - sprawd czy element x naley do zbioru S ; jeli tak to
wska ten element, jeli nie to wska Nil;
2. minimum(S) - (pytanie na zbiorze liniowo uporzdkowanym) zwraca
element najmniejszy zbioru S ;
3. maksimum(S) - (pytanie na zbiorze liniowo uporzdkowanym) zwraca
element najwikszy zbioru S ;
4. nastepny(S,x) - (pytanie na zbiorze liniowo uporzdkowanym) zwraca
element nastpny po x w zbioru S ;
5. poprzedni(S,x) - (pytanie na zbiorze liniowo uporzdkowanym)
zwraca element poprzedni przed x w zbioru S .
Zwykle potrzeba tylko czci spord tych operacji. Wane jest by operacje wykonywane byy szybko, tzn. w czasie staym lub co najwyej logarytmicznym w stosunku do rozmiaru zbioru S .

6.1 Podstawowe dynamiczne struktury danych


Stos

Stos jest najprostsz struktur dynamiczn (LIFO - last in rst out).


Mona wkada elementy tylko na wierzch stosu i zdejmowa elementy tylko
z wierzchu stosu. Poza tym mona testowa czy stos jest pusty. Wszystkie
operacje s wykonywane w czasie staym. Stos mona sobie wyobraa tak:

82

D
C
B
A
Operacje na stosie:

1. dodaj (na wierzch) Push(S,x);


2. zdejmij (z wierzchu) Pop(S);
3. test pustoci stosu
(

empty(S) =

gdy S jest pusty


w przeciwnym przypadku.

true
false

Jak ju wczeniej pokazalimy, przy pomocy stosw mona implementowa procedury rekurencyjne. Stos S , jeli ma ograniczon wysoko,
mona implementowa w tablicy:
S : array[1..n] of typ;
topS : integer;
function empty :boolean;
begin
empty:=(topS=0)
end;
procedure push(x:typ);
begin
topS:=topS+1;
S[topS]:=x;
end;
procedure pop(var x:typ);
begin
x:=S[topS];
topS:=topS-1;
end;

83

Kolejka

Kolejka jest struktur podobn do kolejki w sklepie (FIFO - rst in rst


out). Mona wkada elementy tylko na koniec kolejki i zdejmowa elementy
tylko z pocztku kolejki. Poza tym mona testowa czy kolejka jest pusta.
Wszystkie operacje s wykonywane w czasie staym. Kolejk mona sobie
wyobraa tak:
tail(ogon)

head(glowa)
?

Operacje na kolejce:

1. dodaj (na koniec) dodaj(Q,x);


2. zdejmij (z pocztku) usun(Q);
3. test pustoci kolejki
(

empty(Q) =

gdy S jest pusty


w przeciwnym przypadku.

true
false

Kolejk Q, jeli ma ograniczon dugo, mona implementowa w tablicy, ale w bardziej skomplikowany sposb ni stos.
Q : array[0..n] of typ;
headQ,tailQ : integer;
tailQ

Q:

headQ
?

function empty :boolean;


begin
empty:=(headQ=tailQ)
end;
procedure wstaw(x:typ);
begin
Q[tailQ]:=x;
if tailQ=n then tailQ:=0

84

else tailQ:=tailQ+1;

end;

procedure usun(var x:typ);


begin
x:=Q[headQ];
if headQ=n then headQ:=0
else headQ:=headQ+1
end;

Listy.

Lista to zbir elementw, z ktrych kady (z wyjtkiem ostatniego)


wskazuje na nastpny i na kady element (z wyjtkiem pierwszego) wskazuje
jaki element. List jednokierunkow mona sobie wyobraa tak:
head
H

x1
HH
H
j

x2
-

x3
-

xn
-

...

- N IL

Lista zajmuje proporcjonalnie wiele miejsca do liczby elementw na licie.


List dwukierunkow mona sobie wyobraa tak:
head

x1

HH
H

H
j

x2
-

N IL 

x3


Drzewa binarne

xn


...

- N IL


Drzewo binarne (o ile jest niepuste) ma korze i kady wierzchoek drzewa


ma co najwyej dwa nastpniki, lewy i prawy. Ponadto z korzenia do kadego
wierzchoka istnieje dokadnie jedna droga. Drzewo binarne mona sobie
wyobraa tak:

85

rootP

PP
P
q
P

x1







HH
H
j

x2




x3
H





x4
N IL

N IL

N IL

H
HH
H
j

H
HH
H
j

x5
N IL

N IL

x6
N IL

N IL

6.2 Typy wskanikowe


Zmienne typw dotychczas poznanych istniej w istniej przez cay czas
wykonywania tej czci programu (program gwny lub procedura), w ktrej
s zadeklarowane. Maj one na stae przydzielon pami, do ktrej odwoujemy si za pomoc identykatora zmiennej. S to zmienne statyczne. Takie
zmienne nie nadaj si do reprezentowania 'struktur dynamicznych', na
przykad tych, ktre zostay opisane powyej, (o ile nie naoymy z gry
ogranicze dotyczcych rozmiaru tych struktur). Do reprezentowania takich struktur su typy wskanikowe i wskazywane przez zmienne tych
typw zmienne dynamiczne. Zmienne dynamiczne mona tworzy i usuwa
w dowolnym miejscy programu a odwoujemy si do nich nie przez identykator zmiennej lecz przez zmienn wskanikow wskazujc t zmienn.
Przykad deklaracji typu wskanikowego.
type Tab=array[1..10] of integer; {typ tablicowy, przykladowy typ}
Wskaznik=^Tab; {typ wskaznikow do elementow typu Tab}
var A:Tab; {deklaracja zmiennej typu Tab}
u,v,w:Wskaznik; {deklaracja zmiennych typu
Wskaznik wskazujcego typ Tab}

Zmienne typu wskaniki mog mie warto nieokrelon (np. zaraz


po ich deklaracji) mog zawiera adres zmiennej dynamicznej typu Tab
lub mog by rwne staej Nil, nie wskazujcej adnej zmiennej. Po takich deklaracjach w pamici komputera mamy zarezerwowane takie obszary
pamici (wartoci we wszystkich tablicach s losowe):
86

A
3

71

u
?
v
?

Po wykonaniu kolejno instrukcji


new(u);
{1}
v:=u;
{2}
new(v);
{3}
w:=u; u:=v; v:=w; {4}
u^:=A
{5}
dispose(v); v:=Nil {6}
new(u);
{7}

pami komputera bdzie wygldaa jak nastpuje. Po wykonaniu instrukcji


1:
A
3
u

71

u
-

10

v
?

Po wykonaniu instrukcji 2:
A
3
u

71
u

10

87

Po wykonaniu instrukcji 3:
A
3
u

71

u
10

1
v

Po wykonaniu linii 4:
A
3
u

71
v

10

@
@
@
R
@

u
8

Po wykonaniu instrukcji 5:
A
3
u

71
v

10

@
@
R
@

u
3

71

Po wykonaniu linii 6:

88

A
3

71

10

@
@
R
@

u
3

71

Po wykonaniu instrukcji 7:
A
3
u

71
u

v
?

?
3

71

A teraz dokadnie opiszemy procedury new, tworzc zmienn dynamiczn i


dispose usuwajc zmienn dynamiczn.
Zakadamy nastpujc deklaracj:
var u,v : ^Typ

Procedura new(v):

1. tworzy now zmienn (dynamiczn) typu Typ cakowicie nieokrelon


(rezerwuje miejsce w pamici komputera na zmienn typy Typ);
2. tworzy nowy wskanik typu ^Typ i przypisuje go zmiennej v (adres
nowo utworzonej zmiennej dynamicznej zostaje przypisany zmiennej
v);
3. Do utworzonej zmiennej mona si odwoa przez v^.
Procedura dispose(v):

1. usuwa zmienn (dynamiczn) typu Typ wskazywan przez v (zwalnia


miejsce w pamici komputera zajmowane przez t zmienn); jeli v nie
wskazuje zmiennej wystpi bd;
89

2. wszystkie zmienne wskazujce na v^ maj warto nieokrelon.


Operacje na zmiennych i wartociach typw wskanikowych:

1. do kadego typu wskanikowego naley staa Nil nie wskazujca na


adn zmienn dynamiczn;
2. instrukcje przypisania: v:=u oraz v:=Nil;
3. relacje: v=u oraz v<>u;
4. funkcje mog mie wartoci typw wskanikowych;
5. parametry formalne
wskanikowego.

aktualne

procedur

mog

by

typu

W nastpnym paragrae poka jak mona implementowa listy uywajc typw wskanikowych. Ale typy wskanikowe mog si te przyda do
innych celw, na przykad do deklaracji duych zmiennych. Deklaracja
type Wektor = array[1..10000] of real;
var A,B,C:Wektor;

nie zostanie zaakceptowana przez kompilator Turbo Pascala poniewa ma on


ograniczenie na czny rozmiar zmiennych deklarowanych w sekcji deklaracji
zmiennych var a zmienne typu Wektor zajmuj duo pamici. Natomiast
deklaracja
type Wektor = array[1..10000] of real;
Wsk=^Wektor
var u,v,w:Wsk;

zostanie zaakceptowana przez kompilator Turbo Pascala poniewa zmienne


typu Wsk pamitaj tylko adresy i zajmuj mao pamici. Teraz na pocztku
programu po instrukcjach
new(u); new(v); new(w);

mamy dostp do trzech zmiennych dynamicznych typu Wektor: u^, v^, w^.

90

6.3 Implementacja list


Elementami listy s rekordy zawierajce warto (lub wartoci) i wskanik
do nastpnego elementu na licie.

Lista jednokierunkowa

type lista=^element;
element=record
nazwisko : string;
wiek : integer;
next :lista
end;

Pokaemy jak wykona nastpujce operacje na licie:


1. tworzenie pustej listy; (inicjalizacja)
2. tworzenie nowej zmiennej typu element;
3. wstawienie zmiennej wskazywanej przez zmienn wskanikow do listy;
4. znajdowanie wskanika do elementu o szukanym polu;
5. drukowanie wszystkich elementw listy;
6. usuwanie wskazanego elementu z listy (tylko dla list dwukierunkowych).
procedure ini;
begin head:=Nil end;
function nowy: lista;
var v:lista;
begin
new(v); v^.next:=Nil;
read(v^.nazwisko);
read(v^.wiek);
nowy:=v
end;
procedure dodaj(v:lista);
begin
v^.next:=head;

91

head:=v
end;
function szukaj(s:string):lista;
var v:lista;
begin
v:=head; szukaj:=Nil;
while (v<>Nil) do
if v^.nazwisko=s then begin
szukaj:=v; v:=Nil
end
else v:=v^.next
end;
procedure druk;
var v:lista;
begin v:=head;
while v<>Nil do begin
writeln(v^.Nazwisko,' ',v^.wiek);
v:=v^.next
end;
end;

Teraz fragment programu:


ini;
for i:=1 to 10 do dodaj(nowa);
druk;

tworzy list 10-elementow i j drukuje.

Lista dwukierunkowa
type lista2=^element2;
element2=record
nazwisko : string;
wiek : integer;
next,prev :lista
end;

92

Procedury ini, druk, szukaj dla listy dwukierunkowej s takie same


jak dla listy jednokierunkowej. Natomiast procedury nowy, dodaj naley
odpowiednio zmodykowa:
function nowy2 : lista2;
var v:lista2;
begin
new(v); v^.next:=Nil; v^.prev:=Nil;
read(v^.nazwisko);
read(v^.wiek);
nowy2:=v
end;
procedure dodaj2(v:lista2);
begin
if head<>Nil then head^.prev:=v;
v^.next:=head;
head:=v;
v^.prev:=Nil;
end;

Ponadto na licie dwukierunkowej moemy atwo usuwa wskazany element.


procedure usun2(x:lista2);
begin
if x^.prev<>Nil then x^.prev^.next:=x^.next
else head:=x^.next;
if x^.next<>Nil then x^.next^.prev:=x^.prev
end;

Lista dwukierunkowa z wartownikiem Procedury dodaj2 i usun2

s nieco skomplikowane, gdy musimy sprawdza czy lista jest pusta przy
dodawaniu oraz czy s przed i za usuwanym elementem s inne elementy
przy usuwaniu. Mona te procedury uproci dodajc do listy wartownika
'sztuczny element', ktry powoduje, e lista nigdy nie jest pusta. W efekcie,
na licie z wartownikiem, dodawanie i usuwanie odbywa si bez sprawdzania
adnych warunkw.
procedure ini3;

93

begin new(head); head^.next:=head; head^.prev:=head


end;
procedure dodaj3(v:lista2);
begin
v^.next:=head^.next;
v^.prev:=head;
v^.next^.prev:=v;
head^.next:=v;
end;
procedure usun3(x:lista2);
begin
x^.prev^.next:=x^.next;
x^.next^.prev:=x^.prev
end;
function szukaj3(s:string):lista2;
var v:lista2;
begin
v:=head^.next;
while (v<>head) and (v^.nazwa<>s) do
v:=v^.next;
if v<>head then szukaj3:=v
else szukaj3:=Nil;
end;
procedure druk3;
var v:lista2;
begin v:=head^.next;
while v<>head do begin
writeln(v^.Nazwisko,' 'v^.wiek);
v:=v^.next
end;
end;

Teraz, ponisza procedura czyci list:


procedure empty;

94

var v:lista2;
begin
while head<>head^.next do begin
v:=head^.next;
usun3(v);
dispose(v)
end;
end;

Majc takie listy mona atwo implementowa stosy i kolejki.

6.4 Drzewa binarnych poszukiwa (BST)


Drzewo binarne jest to drzewo, w ktrym kady wierzchoek ma co najwyej
dwa nastpniki, lewy i prawy. Ponadto, o ile jest niepuste, posiada korze - jedyny wierzchoek, ktry nie jest nastpnikiem adnego wierzchoka.
Bdziemy uywali poj: ojciec, lewy i prawy syn, lewe i prawe poddrzewo,
potomek, przodek.
Drzewo binarnych poszukiwa jest to drzewo binarne etykietowane, w
ktrym kady wierzchoek ma etykiet wyrnion zwan kluczem. Klucze
wierzchokw s typu, na ktrym okrelony jest porzdek liniowy. Ponadto dla kadego wierzchoka v klucze w lewym poddrzewie s niewiksze
od klucza wierzchoka v , a klucze w prawym poddrzewie s niemniejsze od
klucza wierzchoka v .
W Pascalu drzewa binarnych poszukiwa implementuje si uywajc
typw wskanikowych.
type wsk=^wierzcholek;
wierzcholek=record
klucz:integer;
lewy,prawy,ojciec:wsk;

Pokaemy procedury na drzewach:


1. znajdowanie wierzchoka o danym kluczu;
2. drukowanie rekordw wedug wzrastajcej wartoci kluczy;
3. znajdowanie wierzchoka o kluczu minimalnym;
4. znajdowanie wskanika do nastpnego wierzchoka;
5. dodawanie nowego wierzchoka;
95

6. usuwanie wierzchoka z drzewa;


7. inne przykadowe procedury rekurencyjne na drzewach.
1. Znajdowanie wierzchoka o danym kluczu. Procedura rekurencyjna szukaj zwraca wskanik do wierzchoka o kluczu s w drzewie o
korzeniu w lub Nil jeli nie ma takiego klucza. Procedura porusza si
po drzewie, w lewo lub w prawo, z zalenoci od tego czy napotkane
klucze na ciece s mniejsze czy wiksze od poszukiwanego. Jeli dojdzie do koca cieki nie znajdujc po drodze szukanego wierzchoka
to znaczy, e takiego wierzchoka w ogle nie ma w drzewie.
function szukaj(w:wsk;s:integer):wsk;
begin
if w=Nil then szukaj:=Nil else
if w^.klucz=s then szukaj:=w else
if w^.klucz<s then szukaj:=szukaj(w^.prawy,s)
else szukaj:=szukaj(w^.lewy,s)
end;

2. Drukowanie rekordw wedug wzrastajcej wartoci kluczy.


Procedura rekurencyjna drukuj odwiedza wszystkie wierzchoki
drzewa w porzdku niemalejcym kluczy, tzn. dla danego wierzchoka zawsze odwiedza najpierw wierzchoki jego lewego poddrzewa,
potem ten wierzchoek a na kocu wierzchoki jego prawego poddrzewa.
Odwiedziwszy wierzchoek drukuje go.
procedure drukuj(w:wsk);
begin
if w<>Nil then begin
drukuj(w^.lewy);
write(w^.klucz);
drukuj(w^.prawy);
end;
end;

3. Znajdowanie wierzchoka o kluczu minimalnym. Procedura


minimum zwraca wskanik do wierzchoka o kluczu minimalnym drzewie
o korzeniu w lub Nil jeli drzewo jest puste. Procedura przechodzi po
wierzchokach w lewo tak dugo a nie tra na wierzchoek, ktry nie
ma lewego syna.
96

function minimum(w:wsk):wsk;
begin
if w<>Nil then
while w^.lewy<>Nil then w:=w^.lewy;
minimum:=w
end;

4. Znajdowanie wskanika do nastpnego wierzchoka. Procedura


next zwraca wskanik do wierzchoka o kluczu nastpnym po kluczu
wierzchoka wskazywanego przez w lub Nil jeli nie ma takiego klucza.
Procedura dziaa w ten sposb, e zwraca minimum poddrzewa o korzeniu w^.prawy o ile jest ono niepuste, a jeli jest puste to wraca do
gry po kolejnych przodkach a do momentu gdy znajdzie wierzchoek,
dla ktrego poprzedni wierzchoek jest lewym synem.
function next(w:wsk):wsk;
var y:wsk;
begin
if w^.prawy<>Nil then next:=minimum(w^.prawy)
else begin
y:=w^.ojciec; next:=Nil;
while y<>Nil do
if w<>y^.lewy then begin
w:=y; y:=y^.ojciec;
end
else begin
next:=y; y:=Nil
end;
end;
end;

5. Dodawanie nowego wierzchoka. Procedura rekurencyjna dodaj


dodaje nowy wierzchoek wskazywany przez w do drzewa binarnych
poszukiwa o korzeniu wskazywanym przez r zachowujc struktur
drzewa binarnego. Nowy wierzchoek jest zawsze dodawany jako nowy
li w drzewie. Procedura woa parametr korzenia r przez zmienn
poniewa, gdy drzewo jest puste, jest on modykowany.
procedure dodaj(var r:wsk;w:wsk);
begin

97

w^.lewy:=Nil; w^.prawy:=Nil;
if r=Nil then
begin w^.ojciec:=Nil; r:=w end
else
if r^.klucz<w^.klucz then
if r^.prawy<>Nil then dodaj(r^.prawy,w)
else
begin r^.prawy:=w; w^.ojciec:=r end
else
if r^.lewy<> Nil then dodaj(r^.lewy,w)
else begin r^.lewy:=w; w^.ojciec:=r end
end;

6. Usuwanie wierzchoka z drzewa. Jeeli wierzchoek wskazywany


przez w, ktry mamy usun ma co najwyej jedno niepuste poddrzewo
(lewe lub prawe) to go usuwamy a to poddrzewo (o ile takie istnieje)
podczepiamy bezporednio do jego ojca. Jeeli wierzchoek wskazywany przez w, ktry mamy usun ma dwa niepuste poddrzewa to
usuwamy wierzchoek nastpny (wtedy on ma co najwyej jedno niepuste poddrzewo) a dane z tego wierzchoka przepisujemy do wierzchoka wskazywanego przez w. Ponadto, jeli usuwamy korze, to
musimy zmodykowa wskanik do korzenia r oraz gdy usunity wierzchoek jest rny od wskazywanego przez w to musimy zmodykowa
w by wskazywa usunity wierzchoek. W procedurze uywamy dodatkowych zmiennych x,y typu wsk, y wskazuje rzeczywicie usuwany
wierzchoek a x jego jedynego syna (o ile takiego posiada). Procedura woa oba parametry przez zmienn, gdy zarwno wskanik do
korzenia jaki i do usuwanego wierzchoka moe by zmieniony.
A:
w
 A
A

 A
 A
AA


B:
w=y

C:

A
A

w=y



 A
 A
AA


 A
 A


D:
w=y
x=Nil

AA

A
A

Powyszy rysunek przedstawia wartoci zmiennych x i y w poddrzewie


o wierzchoku wskazywanym przez w w rnych moliwych przypad98

kach. A gdy w ma dwch synw, B, C gdy w ma jednego syna, D gdy


w nie ma synw.
procedure usun(var r,w:wsk);
var x,y:wsk;
begin
if (w^.lewy=Nil) or (w^.prawy=Nil) then y:=w
else y:=next(w);
{y wskazuje na wierzcholek ktory latwo usunac,
bo ma co najwyzej jedno podrzewo}
if y^.lewy<>Nil then x:=y^.lewy
else x:=y^.prawy;
{x wskazuje na jedynego syna y, o ile taki istnieje}
if x<>Nil then x^.ojciec:=y^.ojciec;
{o ile x istnieje, to modyfikujemy ojca x tak
by teraz byl nim ojciec y}
if y^.ojciec=Nil then r:=x
{jesli y wskazuje korzen to modyfikujemy korzen}
else
if y=y^.ojciec^.lewy then y^.ojciec^.lewy:=x
else y^.ojciec^.prawy:=x;
{jesli y nie wskazuje korzenia to modyfikujemy ojca
y tak by teraz jego synem (z wlasciwej strony) byl x}
if y<>w then begin
w^.klucz:=y^.klucz
....
end;
{jesli usuniety wierzcholek wskazywany przez y jest
rozny od wierzcholka wskazywanego przez w to
przepisujemy wszystkie dane z pola klucz (i innych
pol przechowujacych dane o ile takie istnieja) ale
nie z pol 'administrujacych drzewem': lewy, prawy,
ojciec}
w:=y;
{zwracamy na w wskaznik usunietego wierzcholka}
end;

7. Inne przykadowe procedury rekurencyjne na drzewach. Jeli


funkcj rekurencyjn mona obliczy znajc jej wartoci dla obu synw,
to denicja takiej funkcji jest zwykle prosta, tak jak w pierwszych
99

dwch przykadach. Natomiast gdy tak nie jest, jak w przypadku


trzecim, to musimy skonstruowa now funkcje, ktra bdzie miaa t
wasno. W praktyce taka funkcja oblicza wiele wartoci, z ktrych
jedna jest przez nas poszukiwan a inne s tylko pomocnicze.
(a) Obliczanie liczby wierzchokw drzewa.
function rozmiar(w:wsk):integer;
begin
if w=Nil then rozmiar:=0
else rozmiar:=1+rozmiar(w^.lewy)+rozmiar(w^.prawy)
end;

(b) Obliczanie wysokoci drzewa.


function wysokosc(w:wsk):integer;
var l,p:integer;
begin
if w=Nil then wysokosc:=0
else begin
l:=wysokosc(w^.lewy);
p:=wysoksc(w^.prawy);
if l<p then l:=p;
wysokosc:=l+1
end;
end;

(c) Znajdowanie wskanika do wierzchoka drzewa, dla

ktrego rnica wysokoci poddrzew, lewego i prawego,


jest najwiksza. Funkcja roznica ma jako parametr tylko

korze drzewa i zwraca jako warto tylko dany wskanik.


Poniewa do obliczenia wartoci funkcji w danym wierzchoku
potrzebujemy wicej informacji dotyczcej obu poddrzew, funkcja
roznica uywa procedury lokalnej roznica1, ktra zwraca
potrzebne informacje przez parametry woane przez zmienn.
Ciao samej funkcji roznica zawiera tylko jedno wywoanie procedury roznica1 z odpowiednimi parametrami i wstawienie jednego
z nich jako wartoci funkcji.
function roznica(w:wsk):wsk;
var u:wsk;
d,h:integer;
procedure roznica1(r:wsk; var u:wsk; var d,h:integer);

100

var u1,u2:wsk;
d1,d2,h1,h2:integer;
begin
if r=Nil then begin u:=Nil; d:=0; h:=0 end
else begin
roznica1(r^.lewy,u1,d1,h1);
roznica1(r^.prawy,u2,d2,h2);
{obliczamy rekurencyjnie wartosci dla obu
poddrzew}
if h1>h2 then begin h:=h1+1; d:= h1-h2 end
else begin h:=h2+1; d:=h2-h1 end;
if (d>d1) and (d>d2) then u:=r
{jestesmy w miejscu gdzie jest najwieksza
roznica poddrzew}
else if d1>d2 then begin d:=d1; u:=u1 end
else begin d:=d2; u:=u2 end;
{wstawiamy warosci poprzednie}
end;
end;
begin{cialo funkcji roznica}
roznica1(w,u,d,h);
roznica:=u
end;

6.5 Struktury danych dla rodziny zbiorw rozcznych


Rozwizywanie szeregu problemw wymaga grupowania elementw w zbiory
rozczne. W takiej sytuacji potrzebna jest nam struktura, ktra pozwala
na szybkie wykonywanie trzech operacji:
1. make-set(k) - tworzenia zbioru, ktrego jedynym elementem jest k;
2. union(k,l) - sumowania dwch zbiorw rozcznych, do ktrych
nale elementy k i l;
3. find(k) - znajdowania reprezentanta zbioru, do ktrego naley element k.
Teraz opisz tak struktur. Zakadamy, e operacji make-set jest co
najwyej n. Kady zbir jest reprezentowany przez list. Elementy listy
maj wskaniki do nastpnego elementu i do elementu reprezentujcego dany
101

zbir. Dodawanie bdzie polegao na czeniu list. By przyspieszy dodawanie list bdziemy te pamitali w reprezentancie zbioru dugo listy
(by dodawa krtsz list do duszej) i wskanik do ostatniego elementu
listy. Wskaniki do elementw bdziemy pamitali w osobnej tablicy. Na
obrazku mona to przedstawi tak:
V:
k1 :

nazwa:
dugo:
next:

k2 :

rep:
last:

k3 :

k2
3

k3
?


k?
1
?
- N il

gdzie ? oznacza, e przechowywana w tym polu warto nie jest aktualna.


Operacje make-set i find s wykonywane w czasie staym, natomiast union jest wykonywana w czasie proporcjonalnym do mniejszego z
sumowanych zbiorw.
type wsk=^element;
element=record
nazwa,dlugosc:integer;
rep,next,last:wsk
end;
var V:array[1..n] of wsk;

W V [k] jest wskanik do elementu k lub Nil, jeli jeli k nie naley do
adnego zbioru.
procedure make-set(k:integer);
var u:wsk;
begin
new(u); V[k]:=u;
with u^ do begin
nazwa:=k;
next:=Nil;
rep:=u;

102

dlugosc:=1;
last:=u
end;
end;
function find(k:integer):wsk;
begin
find:=V[k]^.rep
end;
procedure union(k,l:integer);
var u,w,z:wsk;
begin
u:=find(k); w:=find(l);
{u i w wskazuja na reprezentantow zbiorow
do ktorych naleza k i l, odpowiednio}
if w^.dlugosc<u^.dlugosc then begin
z:=u; u:=w; w:=z
end;
{teraz w wskazuje na reprezentanta dluzszej listy}
w^.last^.next:=u; {polaczenie list}
w^.dlugosc:=w^.dlugosc+u^.dlugosc; {uaktualnienie dlugosci}
w^.last:=u^.last; {uaktualnienie ostatniego elementu}
while u<>Nil do begin {uaktualnienie reprezentanta}
u^.rep:=w;
u:=u^.next;
end;
end;

Fakt 6.1

n operacji make-set, union, i find wrd, ktrych jest m operacji


make-set jest wykonywanych w czasie O(n + m log(m)).

Dowd. Procedury make-set i find dziaaj w czasie staym. Zatem n


takich operacji jest wykonywanych w czasie O(n).
Pozostaje do pokazania, e jeli wykonanych zostao m operacji make-set
to czny czas wykonania operacji union jest O(m log(m)).
Procedura union modykuje szereg wartoci reprezentanta sumy zbiorw
i jeden wskanik (next) ostatniego elementu duszej listy. Te operacje s
przy kadym wykonaniu procedury union wykonywane w czasie staym.
Poniewa procedura union moe by wykonana co najwyej m 1 razy

103

(poniewa wszystkich elementw we wszystkich zbiorach jest m), to czny


czas wykonania tej czci procedury union jest O(m).
Pozostaje do pokazania, e czny czas wykonania drugiej czci procedury union modykujcy reprezentanta na krtszej licie jest O(m log(m)).
W tym celu policzymy ile razy cznie moe by modykowany reprezentant jednego elementu. Poniewa modykujemy reprezentantw elementw
tylko na krtszej licie, to po jednej modykacji lista, na ktrej znajduje
si element ma co najmniej dwa elementy, po dwch modykacjach lista, na
ktrej znajduje si element ma co najmniej cztery elementy, ... po k modykacjach lista, na ktrej znajduje si element ma co najmniej 2k elementw.
Poniewa wszystkich elementw jest m to 2k m. A std k log2 (m).
Czyli liczba modykacji reprezentanta kadego elementu jest niewiksza ni
log2 (m). Stad czna liczba modykacji reprezentantw wszystkich m elementw jest rwna O(m log(m)). Q.E.D.

104

Algorytmy grafowe (5)

7.1 Grafy i reprezentacje grafw


Grafy s to bardzo proste struktury, ktre jednak pozwalaj na modelowanie
wielu 'rzeczywistych' sytuacji. Algorytmy grafowe pozwalaj rozwizywa
problemy dotyczce takich sytuacji. Dlatego s jednymi najwaniejszych
podstawowych algorytmw i maj szerokie zastosowania. Poniej zdeniuj
szereg podstawowych poj dotyczcych grafw, poka kilka sytuacji, ktre
mona modelowa przy pomocy grafw, oraz poka jak mona reprezentowa grafy w komputerze. W dalszym cigu omwi najbardziej podstawowe algorytmy grafowe.
Graf zorientowany G jest par uporzdkowan (V, E) tak, e V jest
zbiorem (skoczonym) wierzchokw, a E jest podzbiorem V V . Elementy
E nazywany krawdziami. Czyli graf zorientowany jest to zbir (skoczony)
z relacj binarn. Jeli e = (u, v) E to mwimy, e e jest krawdzi z u do
v , lub krawdzi o pocztku u i kocu v .
1

-2

 

 ?
?
-5
i  6
P

7P
i 

Graf niezorientowany G jest par uporzdkowan (V, E) tak, e V jest


zbiorem (skoczonym) wierzchokw, a E , zbir krawdzi, jest podzbiorem
zbioru par nieuporzdkowanych z V , tzn. zbioru {(u, v) : u 6= v, u, v V }.
W grae niezorientowanym E mona utosamia z relacj binarn na V V ,
ktra jest symetryczna i antyzwrotna, pamitajc jednak, e (u, v) i (v, u)
oznacza t sam krawd. Jeli e = (u, v) E to mwimy, e e jest krawdzi
z u do v , lub krawdzi o pocztku u i kocu v , lub krawdzi o kocach w
u i v.
1

Wiele denicji dla obu rodzajw grafw s identyczne, nawet jeli ich
znaczenie jest rne. Jeli kontekst nie okrela jasno czy dany graf jest
zorientowany czy nie, to znaczy, e chodzi mi w takim przypadku o oba
rodzaje grafw.
105

Stopniem wierzchoka v w grae niezorientowanym G, nazywamy liczb


krawdzi G o pocztku w v .
Stopniem wyjciowym wierzchoka v w grae zorientowanym G, nazywamy liczb krawdzi G o pocztku w v . Stopniem wejciowym wierzchoka
v w grae zorientowanym G, nazywamy liczb krawdzi G o kocu w v .
ciek (lub drog) dugoci k z wierzchoka u do wierzchoka v w grae
G = (V, E), nazywamy cig wierzchokw < v0 , v1 , . . . , vk >, taki, e v0 = u,
vk = v oraz (vi , vi+1 ) E dla i = 0, . . . , k . Dugoci cieki jest liczba
krawdzi na ciece. cieka jest prosta, jeli wszystkie wierzchoki na ciece
s rne.
Cyklem, w grae zorientowanym, nazywamy ciek, ktra zaczyna si
i koczy w tym samym wierzchoku i posiada co najmniej jedn krawd.
Cykl < v0 , v1 , . . . , vk > jest prosty, jeli wszystkie wierzchoki v1 , . . . , vk s
rne.
cieka < v0 , v1 , . . . , vk >, w grae niezorientowanym, jest cyklem, o ile
v0 = vk oraz wierzchoki v1 , . . . , vk s rne.
Graf, w ktrym nie ma cykli nazywamy acyklicznym.
Jeli istnieje cieka z u do v to v jest osigalny z u i oznaczamy u 7 v
Graf niezorientowany jest spjny, jeli kade dwa wierzchoki czy
cieka. Skadowe spjne grafu niezorientowanego, s to klasy abstrakcji
relacji osigalnoci w grae.
Graf G0 = (V 0 , E 0 ) jest podgrafem grafu G = (V, E), jeli V 0 V i
0
E E . G0 jest podgrafem penym G jeli E 0 = E (V V ).

Macierze incydencji. Grafy mona reprezentowa przy pomocy


macierzy incydencji.
Przy takiej reprezentacji graf G = (V, E),
gdzie V = {v1 , . . . vn } jest reprezentowany przez macierz M typu
array[1..n,1..n] of integer, tak, e
(

M [i, j] =

1
0

gdy (vi , vj ) E;
w przeciwnym przypadku.

Wtedy atwo jest sprawdzi czy (vi , vj ) jest krawdzi w grae G. Ale
zwykle jest to reprezentacja bardzo pamiciochonna. Reprezentacja grafu o
n wierzchokach, niezalenie od liczby krawdzi, zuywa ona O(n2 ) pamici.
Uywajc macierzy incydencji atwo jest obliczy liczb cieek danej
dugoci k pomidzy wierzchokami. W tym celu wystarczy obliczy k-krotny
iloczyn macierzy A przez siebie, tzn. Ak . Jeli nas interesuj
cieki dugoci
Pk
i
co najwyej k, to moemy je obliczy nastpujco i=1 A .

Listy incydencji. Listy incydencji s czsto bardziej ekonomicznym

sposobem reprezentowania grafw. Zwykle grafy pojawiajce si w praktyce


106

maj may stopie (wyjciowy) wierzchokw i liczb krawdzi rzdu O(n)


raczej ni O(n2 ). W takiej sytuacji lepiej je reprezentowa przez listy incydencji. Przy takiej reprezentacji graf G = (V, E), gdzie V = {v1 , . . . vn } jest
reprezentowany przez listy incydencji. To znaczy dla kadego wierzchoka vi
tworzymy osobn list wierzchokw vj takich, e (vi , vj ) E . Wskaniki
do pierwszych elementw tych list przechowujemy w osobnej tablicy. Na
rysunku moe to wyglda tak:
A:

- 1 - 2 - 7 - 9 N il

- 1 - 4 N il
- 2 - 3 - 5 - 6 N il

Na licie wskazywanej przez A[i] znajduj si takie wierzchoki j , dla ktrych


(i, j) E .
Tak reprezentacja uywa O(|V |+|E|) pamici, czyli proporcjonalnie wiele
do rozmiaru grafu.
Przykady. Grafy s wszdzie...

1. Sie pocze drogowych, komputerowych, telefonicznych (i wielu innych) na danym terenie to graf... (czasem zorientowany, czasem nie).
2. Schemat montau dowolnego urzdzenia to graf skierowany. Oglniej, nastpstwo w procesach, ktre czciowo mog by wykonywane
rwnolegle jest grafem skierowanym. Na przykad, dla wykonania dziaa:
s1:
s2:
s3:
s4:
s5:
s6:

a:=0;
b:=1;
c:=a+1;
d:=b+a;
e:=d+c;
d:=d+1;

mamy taki graf nastpstwa:

107

s1

s2

@
R ?
?@

s3

s4

s5

s6

3. Relacje pomidzy ludmi mona reprezentowa przy pomocy grafw.


Na przykad zalenoci subowe w przedsibiorstwach, czy graf 'wpyww' taki, e krawd a b jest w grae o ile 'a moe wpywa na
zdanie b'.
Ja
@@
I

@@
R


Micha

@
R
@

Sta

Bartek

4. acuch ywieniowy zwierzt (Pies->Kot->Mysz etc.) jest grafem.


5. Wspzawodnictwo zwierzt w ekosystemie o to samo poywienie jest
grafem modelujcym zachodzce na siebie nisze ekologiczne. Krawd
a b jest w grae o ile 'poywienie a i b cho czciowo si pokrywaj'.
Szop

XXX
X
HH
X
HH
H

Opos H
Mysz

Sowa
Jastrzb

Wiewirka



HH
H

Wrona

HH
HH
H
H
H
HH
Ryjwka

XXX


Dzicio

6. Wyniki pojedynkw druyn w turnieju mona reprezentowa jako graf


taki, e krawd a b jest w grae o ile 'a wygra z b'.

7.2 Skadowe spjne grafu niezorientowanego


Podam teraz zastosowanie opisanej wczeniej struktury danych dla rodziny
zbiorw rozcznych. Poniszy algorytm oblicza skadowe spjne grafu
niezorientowanego.
108

procedure skladowe_spojne(G:graf);
begin
for v in V(G) do {tzn. 'dla kazdego wierzcholka grafu G'}
make-set(v);
{tworzymy zbiory jedno-elemenotowe dla kazdego wierzcholka grafu}
for (u,v) in E do {tzn. 'dla kazdej krawedzi grafu G'}
if find(u)<>find(v) then union(u,v);
end;

W procedurze skladowe_spojne tworzymy zbiory jednoelementowe, ktrych


elementami s wszystkie wierzchoki grafu G. W trakcie dziaania procedury
modykujemy te zbiory tak, by w kadym z nich byy tylko takie wierzchoki
pomidzy ktrymi istnieje cieka. Procedura przeglda kolejne krawdzie
grafy G. Jeli napotka krawd, ktra czy wierzchoki z dwch rnych
zbiorw to je do siebie dodaje. Po zakoczeniu procedury powstae zbiory
tworz skadowe spjne garfu G.
Bezporedni konsekwencj Faktu 6.1 jest

Fakt 7.1 Dla grafu niezorientowanego G = (V, E), procedura


skladowe_spojne dziaa w czasie O(n + m log(m)), gdzie |V | = m i
|E| = n.
Po wykonaniu procedury skladowe_spojne sprawdzenie czy dwa wierzchoki s w tej samej skadowej wyglda tak:
function ta_sama_skladowa(u,v):boolean;
begin
ta_sama_skladowa := (find(u)=find(v))
end;

109

7.3 Przeszukiwanie grafu wszerz (BFS)


Drzewo jest to zorientowany graf acykliczny taki, e

1. istnieje dokadnie jeden wierzchoek, ktry nie jest kocem adnej


krawdzi; wierzchoek ten nazywa si korzeniem;
2. istnieje istnieje droga od korzenia do kadego wierzchoka grafu;
3. kady wierzchoek, z wyjtkiem korzenia, jest kocem dokadnie jednej
krawdzi.

J



^
JJ
J

 J





^
J

J
^
J

Niech D = (V, E) bdzie drzewem. Jeli (v, w) E to v jest poprzednikiem w a w jest nastpnikiem v . Jeli istnieje droga z v do w, to w jest potomkiem v (a v jest przodkiem w). Jeli ponadto v 6= w, to w jest potomkiem
waciwym v . Liciem nazywamy wierzchoek bez potomkw waciwych.
Podgraf peny drzewa D zawierajcy wierzchoek v wraz z jego potomkami
nazywamy poddrzewem drzewa D o korzeniu v . Gbokoci wierzchoka v w
drzewie nazywamy dugo drogi od korzenia do v . Wysokoci wierzchoka
v w drzewie nazywamy dugo najduszej drogi od v do jakiego licia.
Wysokoci drzewa nazywamy wysoko korzenia tego drzewa.
Algorytm przeszukiwania grafu wszerz systematycznie bada krawdzie
grafu G, by dotrze do kadego wierzchoka osigalnego z s. Oblicza drzewo
przeszukiwania wszerz z wierzchoka s i odlego od s do kadego wierzchoka osigalnego z s.
Drzewem przeszukiwania wszerz grafu G = (V, E) z wierzchoka s V
nazywamy podgraf D = (V 0 , E 0 ) grafu G bdcy drzewem o korzeniu s taki,
e:
1. V 0 zawiera wszystkie wierzchoki osigalne z s w G;
2. dla kadego wierzchoka v V 0 cieka z s do v w drzewie D jest
najkrtsz ciek z s do v w grae E .
Problem (przeszukiwanie grafu wszerz).

110

Dane wejciowe: graf G = (V, E) i wierzchoek s V .


Wynik: tablice d i indeksowane zbiorem V , takie e

1. d[v] jest dugoci najkrtszej cieki z s do v lub (np. 1)


jeli nie ma takiej cieki;
2. P [v] jest poprzednikiem v na najkrtszej ciece z s do v , lub N il
gdy v = s lub v nie jest osigalny z s.
Podczas przeszukiwania algorytm uywa pomocniczej tablicy kolor:
kolor[v] =

bialy

szary

czarny

gdy v jest jeszcze nie odwiedzony;


gdy v zosta odwiedzony;
gdy v i jego nastpniki zostali odwiedzeni.

i kolejki:
1. kolejka<=v - wstaw v do kolejki na koniec;
2. v<=kolejka - wstaw pierwszy element kolejki na v ;
3. usun_z_kolejki - usu pierwszy element z kolejki;
4. kolejka<>0 - - test pustoci kolejki.
Zakadamy, e graf G jest reprezentowany przez listy incydencji. LI[v]
jest list kocw krawdzi o pocztku v .
procedure BFS(G,s);
begin
for v in V-{s} do begin
{inicjalizacja}
P[v]:=Nil; d[v]:=-1; kolor[v]:=bialy
end;
d[s]:=0; kolor[s]:=szary; kolejka<=s;
while kolejka<>0 do begin
{petla glowna}
u<=kolejka;
for v in LI[u] do {przegladamy nastepniki u}
if kolor[v]=bialy then begin {wlasnie odkrylismy v}
d[v]:=d[u]+1; P[v]:=u;
kolor[v]:=szary; kolejka<=v;
end;
usun_z_kolejki; kolor[u]:=czarny; {opuszczamy wierzcholek u}
end;
end;
end;

111

Przykad. Poniszy rysunek przedstawia efekt dziaania procedury


BSF(G,s). Wierzchokami grafu s liczby 1, . . . 9, krawdzie grafu s 'takie
jak wida', wierzchoek s jest wierzchokiem numer 7. W wierzchokach zaznaczone s kolejno trzy wartoci: numer wierzchoka v , odlego d[v] od
wierzchoka s = 7, przedostatni wierzchoek P [v] na jednej z najkrtszych
cieek z 7 do v :

1 3 2

- 3 2 6
- 4 3 3
2 2 6

odlego
od 7
poprzedni na
3
3


Q
Q
6
J najkrtszej

Q 
Q
numer


Q
Q
J ciece do 7
wierzchoka
 Q


Q
s ? 
Q
s
Q
?
?
? QQ JJ


^
s
Q
- 6 1 7 
4 1
7 0 Nil 
8 3 3
9 Nil

Opis procedury BFS.

1. Inicjalizacja: nadaje wartoci pocztkowe tablicom d i P .


2. Ptla gwna (while): jest wykonywana dopki s jeszcze wierzchoki
odkryte, ktre maj nieodkryte nastpniki (tzn. szare).
3. Ptla wewntrzna: przeglda wszystkich ssiadw pierwszego wierzchoka z kolejki i odwiedza (maluje na szaro) te wierzchoki, ktre
jeszcze nie byy odwiedzone (biae).
Czas dziaania procedury BFS.

1. Inicjalizacja: O(|V |).


2. Kady wierzchoek jest raz (i nigdy wicej) malowany na biao, przy inicjalizacji. Przy wstawianiu do kolejki malujemy wierzchoek na szaro.
Zatem kady wierzchoek jest co najwyej raz wstawiany do kolejki i
raz z niej zdejmowany. Zatem czna liczba operacji ptli zewntrznej,
bez ptli wewntrznej jest O(|V |).
3. czna liczba iteracji ptli wewntrznej jest nie wiksza od cznej
dugoci list incydencji grafu G, czyli |E| - gdy graf jest zorientowany i
2|E| - gdy graf jest niezorientowany. Zatem czas dziaania wszystkich
iteracji ptli wewntrznej jest O(|E|).
Std otrzymujemy

Fakt 7.2 Czas dziaania procedury BFS dla grafu

O(|V | + |E|).

112

G = (V, E) jest rwny

Poprawno algorytmu BFS.


Ustalmy graf G = (V, E) i wierzchoek s V . Niech (u, v) bdzie
dugoci najkrtszej cieki z u do v w G lub gdy nie ma takiej cieki.

Lemat 7.3

1. Jeli (u, v) E , to (s, v) (s, u) + 1.

2. Po wykonaniu BF S(G, s), (s, v) d[v], dla v V .


Dowd. Ad. 1. Oczywiste.
Ad 2. Pokaemy przez indukcj ze wzgldu na liczb wstawie wierzchokw do kolejki, e
(s, v) d[v]

dla v V

(12)

Zaoenie jest prawdziwe po wstawieniu pierwszego wierzchoka (s) do kolejki. Wtedy mamy
(s, s) = d[s],

(s, v) = d[v],

dla v V \ {s}

Krok indukcyjny. Rozwamy teraz biay wierzchoek v odkryty podczas przeszukiwania listy incydencji wierzchoka u. Z zaoenia indukcyjnego mamy [s, u] d[u]. Po odkryciu v wykonujemy podstawienie
d[v] := d[u] + 1. Wtedy uywajc punktu 1. mamy:
d[v] = d[u] + 1 (s, u) + 1 (s, v).

W tym momencie malujemy v na szaro i wobec tego warto d[v] si ju nie


zmieni. Std teza. Q.E.D.
Poniszy lemat opisuje dziaanie kolejki w trakcie wykonywania si procedury BF S .

Lemat 7.4 Przypumy, e w czasie wykonywania si procedury BF S(G, s)


kolejka zawiera wierzchoki < v1 , . . . , vr > (v1 pierwszy vr ostatni). Wtedy
d[vr ] d[v1 ] + 1

oraz
d[vi ] d[vi+1 ]

dla i = 1, . . . , r.

113

Dowd. Lemat udowodnimy przez indukcj ze wzgldu na liczb wstawie


do i usuni z kolei.
Po wstawieniu s do kolejki teza lematu jest prawdziwa.
Jeli teza lematu jest prawdziwa przed usuniciem wierzchoka z kolejki
to tym bardziej jest prawdziwa po usunici wierzchoka z kolejki.
Jeli kolejna operacja jest dodaniem wierzchoka vr+1 do kolejki <
v1 , . . . , vr > to dzieje si to w czasie przeszukiwania listy ssiadw v1 . Zatem
podstawiamy d[vr+1 ] := d[v1 ] + 1. Wtedy
d[vi ] d[v1 ] + 1 = d[vr+1 ]

dla i = 1, . . . , r i oczywicie d[vr+1 ] d[v1 ] + 1. Zatem teza jest prawdziwa


w dowolnym momencie wykonywania procedury BF S . Q.E.D.

Twierdzenie 7.5 Procedura BF S(G, s) odwiedza kady wierzchoek v V

osigalny z s. Po jej wykonaniu d[v] = (s, v), dla v V .


Ponadto dla dowolnego v 6= s i osigalnego z s ostatni krawdzi na
jednej z najkrtszych cieek z s do v jest krawd (P (v), v).
Dowd. Niech v V bdzie nieosigalny z s. Wtedy z Lematu 7.3(2)
d[v] (s, v) = . Zatem v nie zosta odkryty, bo w przeciwnym razie

miaby warto skoczon.


S
Niech Vk = {v V : (s, v) = k}. W szczeglnoci kN Vk jest zbiorem
wszystkich wierzchokw osigalnych z s. Dla wierzchokw osigalnych z s
pokaemy tez twierdzenia przez indukcj po k N .
Zaoenie indukcyjne: w czasie wykonywania procedury BF S(G, s), dla
dowolnego wierzchoka v Vk , zdarzy si dokadnie raz taka sytuacja, e v
zostanie odkryty oraz:
1. v zostanie pomalowany na szaro;
2. d[v] przyjmie warto k;
3. jeli v 6= s to P [v] przyjmie warto w Vk1 ;
4. v zostanie wstawiony do kolejki.
Dla k = 0 mamy V0 = {s}. Ten 'jedyny raz' dla s zdarzy si przy
inicjalizacji.
Niech k > 0, zaoenie indukcyjne bdzie prawdziwe dla wierzchokw z
Vk1 oraz v Vk .
Kilka obserwacji:
114

1. kolejka jest niepusta a do zakoczenia wykonywania algorytmu;


2. po wstawieniu wierzchoka u do kolejki d[u] i P [u] nie zmieniaj si;
3. jeli wierzchoki v1 , . . . , vr s kolejno wstawiane do kolejki to d[v1 ]
. . . d[vr ].
Poniewa, z Lematu 7.3, d[v] k, to z 3. i zaoenia indukcyjnego mamy,
e o ile v zostanie odkryty, to zostanie odkryty po odkryciu i wstawieniu do
kolejki wszystkich wierzchokw z Vk1 . Poniewa (s, v) = k, to istnieje
u Vk1 taki, e (u, v) E . Niech u bdzie pierwszym takim wierzchokiem
wstawionym do kolejki. Zatem v zostanie odkryte podczas przeszukiwania
ssiadw u. Wtedy
1. v zostanie pomalowany na szaro;
2. d[v] := d[u] + 1 = k;
3. P [v] := u;
4. v zostanie wstawiony do kolejki.
Poniewa v by dowolny to otrzymujemy tez indukcyjn.
By zobaczy, e (P [v], v) jest ostatni krawdzi na najkrtszej ciece z
s do v wystarczy zauway, e P [v] Vk1 .
Q.E.D.
Majc tablice d i P obliczone w procedurze BF S(G, s) drzewo przeszukiwania wszerz D = (VP , EP ) grafu G z wierzchoka s otrzymujemy w nastpujcy sposb:
VP = {v V : P [v] 6= N il} {s}

oraz
EP = {(P [v], v) : v VP \ {s}}

Ponisza procedura rekurencyjna drukuje najkrtsz ciek z s do dowolnego wierzchoka G:


procedure sciezka (G,s,v);
begin
if v=s then write(s)
else if P[v]=Nil then write('Nie ma sciezki.')
else begin
sciezka(G,s,P[v]);

115

end;

write(v)
end;

116

7.4 Przeszukiwanie grafu w gb (DFS)


Przeszukiwanie grafu w gb (DFS), jest drugim po BFS, podstawowym
sposobem przeszukiwania grafu, i jak zobaczymy pniej, czsto bardzo
uytecznym przy konstruowaniu innych algorytmw. Idea przeszukiwania
w gb polega na tym by i jak najgbiej jest to tylko moliwe. Gwna
techniczn rnic algorytmu DFS w stosunku do BFS jest to, e w DFS
wkadamy odwiedzane wierzchoki na stos a nie jak w BFS, do kolejki.
Przeszukujc graf w gb odwiedzamy wszystkie wierzchoki a nie tylko
te, ktre s osigalne z ustalonego wierzchoka. Dlatego w rezultacie
przeszukiwania w gb otrzymujemy las (a nie drzewo) przeszukiwania w
gb. Ponadto przeszukujc graf w gb zapamitujemy moment, w ktrym
wierzchoki odkrywamy (malujemy na szaro) i opuszczamy (malujemy na
czarno).
Las jest to zorientowany graf acykliczny taki, e
1. istnieje co najmniej jeden wierzchoek, ktry nie jest kocem adnej
krawdzi; wierzchoki takie nazywa si korzeniami;
2. istnieje droga do kadego wierzchoka od dokadnie jednego korzenia
grafu;
3. kady wierzchoek, z wyjtkiem korzeni, jest kocem dokadnie jednej
krawdzi.

J



^
JJ
J

^
   JJ
J
^
J

J



^
JJ


  

Problem (przeszukiwanie grafu w gb).

Dane wejciowe: graf G = (V, E).


Wynik: tablice d, f i P indeksowane zbiorem V , takie e

1. P [v] = u oznacza, e v zosta odkryty w czasie przeszukiwania


listy incydencji wierzchoka u;
2. d[v] jest czasem odkrycia wierzchoka v ;
3. f [v] jest czasem opuszczenia wierzchoka v .
117

Po wykonaniu procedury DFS dla grafu G = (V, E) krawdzie lasu GP =


(V, EP ) przeszukiwania w gb grafu G deniujemy nastpujco:
EP = {(P [u], u) : P [u] 6= N il}

Procedura DFS podobnie jak BFS uywa pomocniczej tablicy kolor do


barwnego zaznaczania statusu wierzchokw.
procedure DFS(G:graf);
begin
for v in V do begin {inicjalizacja}
kolor[v]:=bialy; P[v]:=Nil
end;
time:=0;
for v in V do {budowa kolejnych drzew lasu przeszukiwania w glab}
if kolor[v]=bialy then DFS-odwiedz(v)
end;
procedure DFS-odwiedz(u:wierzcholek);
begin
kolor[u]:=szary; time:=time+1; d[u]:=time; {wlasnie odkrylismy u}
for v in LI(u) do {przegladanie sasiadow u wraz z ich potomkami}
if kolor[v] = bialy then begin
P[v]:=u;
DFS-odwiedz(v);
end;
kolor[u]:=czarny; time:=time+1; f[u]:=time
end;

Przykad. Poniszy przykad ilustruje sposb dziaania procedury DFS.


- 3
2 2 9 1

3
3


Q
6

Q 


Q
 Q

s ? 
Q
?
- 6 5 6 7 
5 10 11 1
7
1 1 12 Nil

3 8

4 13 16 Nil

Q
k
Q
Q
Q
Q

?
4 7

W wierzchokach zaznaczone s kolejno wartoci:


118

moment
opuszczenia
moment
odkrycia

ojciec w lesie
A przeszukiwania
w gb
numer
J A
wierzchoka

A
? QQ JJ

^
U
A

s
Q

8 14 15 4

9 17 18 Nil

1. numer wierzchoka x;
2. moment odkrycia wierzchoka d[x];
3. moment opuszczenia wierzchoka f [x];
4. ojciec wierzchoka w lesie przeszukiwania w gb P [x].
Las przeszukiwania w gb powyszego grafu wyglda tak:
1

Q
s
Q

+


Opis procedury DFS.

1. Inicjalizacja: nadaje wartoci pocztkowe tablicom kolor i P .


2. Ptla for procedury DFS przeglda wszystkie wierzchoki grafu G;
dla wierzchokw biaych woa procedur DFS-odwiedz; kade takie
woanie tworzy jedno drzewo lasu przeszukiwania w gab grafu G;
3. procedura DFS-odwiedz(u) wraz z rekurencyjnymi odwoaniami
odwiedza wierzchoek u, wszystkich jego ssiadw, i wszystkich ssiadw ssiadw, etc. ktrzy jeszcze nie zostali odkryci; na koniec procedura opuszcza wierzchoek u;
4. Ptla for procedury DFS-odwiedz(u) przeglda wszystkich ssiadw
wierzchoka u, dla tych wierzchokw, ktre jeszcze nie byy odwiedzone (biae) woa rekurencyjnie siebie sam.
Czas dziaania procedury DFS.

1. Procedura DFS, nie liczac woa procedury DFS-odwiedz, wykonuje


O(|V |) operacji.
2. Procedura DFS-odwiedz jest woana dokadnie jeden raz dla kadego
wierzchoka; w momencie woania DFS-odwiedz(v) wierzchoek v musi
by biay, jest malowany na szaro i nigdy potem nie jest malowany
119

na biao; w czasie woania DFS-odwiedz(v)


ptla for jest wykonyP
wana |LI(v)| razy; poniewa vV |LI(v)| = O(|E|), to czna liczba
wykona ptli for jest O(|E|).
Zatem

Fakt 7.6 Czas dziaania procedury DFS dla grafu


O(|V | + |E|).

G = (V, E) jest rwny

Teraz pokaemy kilka wasnoci procedury DFS.

Fakt 7.7 (Twierdzenie o nawiasowaniu) Po wykonaniu procedury DFS


dla grafu G = (V, E), dla dowolnych dwch wierzchokw u, v V zachodzi
dokadnie jeden z warunkw:
1. przedziay < d[v], f [v] > i < d[u], f [u] > s rozczne;
2. przedzia < d[v], f [v] > jest zawarty w przedziale < d[u], f [u] > oraz v
jest potomkiem u w lesie przeszukiwania w gb;
3. przedzia < d[u], f [u] > jest zawarty w przedziale < d[v], f [v] > oraz u
jest potomkiem v w lesie przeszukiwania w gb;
Dowd. Niech u, v V , u 6= v . Moemy zaoy, e d[u] < d[v] (przypadek d[u] > d[v] jest analogiczny).
Rozpatrzymy dwa przypadki:

1. d[v] < f [u];


2. f [u] < d[v].
Ad 1. Gdy d[v] < f [u], to w momencie d[v] wierzchoek u jest szary, tzn.
v zostaje odkryty gdy przeszukujemy potomkw wierzchoka u. Zatem v jest
potomkiem u.
Ponadto po momencie d[v] krawdzie wychodzce z v zostan
przeszukane i v zostanie pomalowane na czarno i opuszczony, zanim zostanie
opuszczony u. Std f [v] < f [u] oraz mamy
d[u] < d[v] < f [v] < f [u].

Ad 2. Gdy f [u] < d[v], to przedziay < d[v], f [v] > i < d[u], f [u] >
s rozczne. Ponadto aden z wierzchokw nie zostanie odkryty podczas
przeszukiwania potomkw drugiego. Q.E.D.
120

Wniosek 7.8 Wierzchoek v jest potomkiem wierzchoka u w lesie przeszukiwania w gb grafu G wtedy i tylko wtedy gdy d[u] < d[v] < f [v] < f [u].

Fakt 7.9 (Twierdzenie o biaej ciece) W lesie przeszukiwania w gb


grafu G = (V, E), v jest potomkiem u wtedy i tylko wtedy gdy w momencie d[u] (tzn. momencie odkrycia u) istnieje cieka z u do v przechodzca
wycznie po biaych wierzchokach.

Dowd. : Zamy, e v jest potomkiem u w lesie przeszukiwania w


gb grafu G. Niech w bdzie wierzchokiem na ciece z u do v w lesie
przeszukiwania w gb GP (V, EP ). Z Wniosku 7.8, d[u] < d[w]. Zatem w
jest biay w momencie d[u], odkrycia u.
: Przypumy, e w momencie d[u] odkrycia u istnieje biaa cieka
z u do v biegnca po biaych wierzchokach ale v nie jest potomkiem u w
lesie przeszukiwania w gb grafu G. Moemy przyj, e wszystkie poprzednie wierzchoki na tej ciece s potomkami u. W przeciwnym przypadku
moemy za v przyj pierwszy wierzchoek na tej ciece, ktry nie jest potomkiem u. Niech w bdzie poprzednim wierzchokiem przed v na tej ciece.
Wtedy, z Wniosku 7.8, f [w] f [u] (w moe by rwny u). Poniewa v jest
biay w momencie d[u] i (w, v) E , to v musi by odkryty po odkryciu u
ale przed opuszczeniem w. Zatem
d[u] d[v] < f [w] f [u].

Z Faktu 7.7 mamy, e przedzia < d[v], f [v] > jest zawarty w < d[u], f [u] >.
A zatem, z Wniosku 7.8, v jest jednak potomkiem u. Q.E.D.

121

7.5 Sortowanie topologiczne


Problem sortowania topologicznego polega uporzdkowaniu liniowym wierzchokw zorientowanego grafu acyklicznego G = (V, E) tak, by wierzchoek
u by przed wierzchokiem v , o ile (u, v) E .
Problem (sortowanie topologiczne).

Dane wejciowe: zorientowany graf acykliczny G = (V, E).


Wynik: lista zawierajca wszystkie wierzchoki z V taka, e jeeli
(u, v) E to u jest przed v na tej licie.

Przykad. Wierzchokami poniszego grafu acyklicznego s czci garderoby. Krawd x y oznacza, e ubierajc si x naley woy przed
y . Poniewa na raz moemy woy tylko jedn cze garderoby to by si
ubra musimy (mniej lub bardziej wiadomie) zastosowa algorytm sortowania topologicznego.

koszula

marynarka

skarpetki

buty
6

krawat
?

zegarek

majtki

spodnie

Opis algorytmu sortowania topologicznego:

1. przeszukujemy graf G w gb procedur DFS;


2. w momencie f [u] wstawiamy u na pocztek listy;
3. lista, ktr otrzymujemy po zakoczeniu procedury DFS jest dan
list.

122

7.6 Silnie spjne skadowe grafu


Algorytm znajdujcy silnie spjne skadowe zorientowanego grafu G jest
kolejnym zastosowaniem algorytmu przeszukiwania grafu w gb (DFS).
Niech G = (V, E) bdzie grafem zorientowanym. Dla u, v V , u 7 v
oznacza, e istnieje cieka z u do v w G. Deniujemy relacj binarn na
zbiorze V tak, e
u v wiw gdy u 7 v i v 7 u

dla u, v V . Oczywicie relacja jest przechodnia. Klasy abstrakcji relacji


nazywamy silnie spjnymi skadowymi grafu G. Graf GT = (V, E T ) nazywamy grafem transponowanym grafu G = (V, E), jeeli
(u, v) E T iff (v, u) E

Uwaga. Skadowe silnie spjne grafw G i GT s rwne.


Problem (znajdowanie silnie spjnych skadowych).

Dane wejciowe: zorientowany graf G = (V, E).


Wynik: zbir silnie spjnych skadowych grafu G.

Opis algorytmu znajdowania silnie spjnych skadowych:

1. przeszukujemy graf G w gb procedur DFS w celu obliczenia tablicy


f;
2. obliczamy graf transponowany GT ;
3. przeszukujemy graf GT w gb procedur DFS z tym, e tym razem w
w ptli gwnej procedury DFS przeszukujemy wierzchoki w porzdku
malejcych wartoci poprzednio obliczonego f ;
4. Wypisujemy wierzchoki drzew lasu przeszukiwania w gb grafu GT
jako kolejne silnie spjne skadowe grafu G.
Przykad. Ten algorytm ma, na pierwszy rzut oka, niewiele wsplnego
z problemem, ktry rozwizuje. Zanim uzasadni, e algorytm powyszy
poprawnie rozwizuje problem znajdowania silnie spjnych skadowych
warto przeledzi przykad, ktry nieco to uprawdopodabnia. W przykadzie

123

kolejno przeszukujemy grafy G i GT procedur DF S z tym, e przeszukujc graf GT , tak jak jest to powiedziane w algorytmie, w procedurze DF S
przeszukujemy wierzchoki w kolejnoci malejcych wartoci f . atwo te
sprawdzi, e wierzchoki drzew lasu przeszukiwania w gb grafu GT tworz
silnie spjne skadowe grafu G (i GT ).
Przeszukanie w gb grafu G procedur DF S(G):
1 1 10 Nil

2 2 9





+

5 3 4

3 5 8

4 11 16 Nil

moment
opuszczenia

moment
ojciec w lesie
3 6
3


odkryciaA przeszukiwania


w gb
A
numer


J
wierzchoka



A
J

+
? 
? QQ J
^
A
U


s
Q
6 7 3 
7 13 14 8 
8 12 15 4
9 17 18 Nil

Las przeszukiwania w gb grafu G:


1

Q
s
Q


+
2

Przeszukanie w gb grafu GT procedur DF S(GT ):


1 9 14 Nil

2 10 11 1

3




?
5 12 13 1

3 15 18 Nil

4 3 8 Nil

3









+
+

?
- 7 4 7 4 
6 16 17 3
8
6

moment
odkrycia

ojciec w lesie
A przeszukiwania
w gb
A
numer
J
wierzchoka

A
J
Q
^
J
U
A


Q
s
Q

5 6

moment
opuszczenia

9 1 2 Nil

Las przeszukiwania w gb grafu GT :


9

Q
s
Q

+

2

Poniej pokaemy, e ten algorytm poprawnie znajduje silnie spjne


skadowe grafu zorientowanego. Ustalmy do koca tej sekcji zorientowany
graf G = (V, E).
124

Lemat 7.10 Jeeli dwa wierzchoki nale do tej samej silnie spjnej skad-

owej S grafu G, to kada cieka pomidzy nimi jest cakowicie zawarta w

S.

Dowd. Niech S bdzie silnie spjn skadow grafu G, u, v S oraz


w V bdzie wierzchokiem na ciece z u do v . Wtedy mamy u 7 w i
w 7 v oraz poniewa u v to u 7 v i v 7 u. Poniewa relacja 7 jest
przechodnia to mamy u 7 w i w 7 u czyli w u. A std u i w le w tej
samej silnie spjnej skadowej S . Pokazalimy zatem, e kady wierzchoek
w na dowolnej ciece z u do v ley w silnie spjnej skadowej S . Zatem
kada cieka z u do v biegnie tylko po wierzchokach z S . Q.E.D.

Lemat 7.11 Procedura DFS umieszcza wszystkie wierzchoki tej samej silnie
spjnej skadowej grafu w jednym drzewie lasu przeszukiwania w gb.

Dowd. Niech S bdzie silnie spjn skadow grafu G, r bdzie pierwszym wierzchokiem z S odkrytym podczas przeszukiwania grafu G, oraz
v dowolnym wierzchokiem z S . Zatem momencie d[r] odkrycia r wszystkie
wierzchoki z S s biae. Poniewa r, v S to istnieje cieka z r do v . Z
Lematu 7.10 cieka ta biegnie tylko po wierzchokach z S , zatem tylko po
biaych wierzchokach. Z Faktu 7.9 (Twierdzenie o biaej ciece) v jest potomkiem r w drzewie lasu przeszukiwania w gb grafu G. Z dowolnoci v ,
wszystkie wierzchoki z S s potomkami r, zatem skadowa S jest umieszczona w jednym drzewie lasu przeszukiwania w gb grafu G. Q.E.D.
Notacja. Niech f bdzie tablic obliczon w czasie wykonania procedury DFS dla grafu G. Deniujemy funkcj : V V tak, e (u) = w
jeli u mona doj do w i f [w] jest maksymalnym momentem opuszczenia
wierzchoka do ktrego mona doj z u, tzn.
u 7 w oraz f (w) = max{f (v) : u 7 v}.
(u) nazywamy praojcem u.

Lemat 7.12 Niech u, v V .


1. f (u) f ((u));
2. jeli u 7 v to f ((u)) f ((v));
3. (u) = (u).

125

Dowd. Ad 1. Poniewa u 7 u oraz (u) jest takim wierzchokiem w,


e u 7 w i f (w) jest maksymalne to f (u) f ((u)).
Ad 2. Mamy
f ((u)) = max{f (w) : u 7 w}

oraz
f ((v)) = max{f (w) : v 7 w}.

Poniewa u 7 v to
{f (w) : u 7 w} {f (w) : v 7 w}.

Zatem
f ((u)) = max{f (w) : u 7 w} {f (w) : v 7 w} = f ((v)).

Ad 3. Z 1. mamy, e
f ((u)) f ((u)).

Poniewa u 7 (u) to z 2. mamy, e


f ((u)) f ((u)).

Zatem
f ((u)) = f ((u)).

Poniewa funkcja f jest rnowartociowa (jako e rne wierzchoki


opuszczamy w rnych momentach) to mamy te
(u) = (u).

Q.E.D.

Lemat 7.13 Praojciec

(u) wierzchoka u V jest przodkiem u w lesie


przeszukiwania w gb grafu G.

Dowd. Jeli u = (u) to Lemat jest prawdziwy. Niech u 6= (u).


Rozwamy kolor (u) w momencie d(u). Jeli (u) jest szary to (wietnie
bo) u zosta odkryty w czasie przeszukiwania potomkw (u). Zatem (u)
jest przodkiem u w lesie przeszukiwania w gb grafu G. Pokaemy, e (u)
nie moe by ani czarny ani biay .
Jeli (u) jest czarny to
f ((u)) < d(u) < f (u)

i mamy sprzeczno z Lematem 7.12.1.


Pokaemy teraz, e (u) nie moe by biay. Przypumy przeciwnie, e
(u) jest biay w momencie d(u). Mamy dwa przypadki:
126

1. w momencie d(u) cieka z u do (u) biegnie tylko po biaych wierzchokach;


2. w momencie d(u) na ciece z u do (u) s niebiae wierzchoki.
W przypadku 1, z Twierdzenia o biaej ciece (Fakt 7.9) mamy, e (u)
bdzie potomkiem u w lesie przeszukiwania w gb grafu G. Zatem
d(u) < d((u)) < f ((u)) < f (u)

i otrzymujemy sprzeczno z Lematem 7.12.1.


W przypadku 2, niech t bdzie ostatnim niebiaym wierzchokiem na
ciece z u do (u):
u . . . t . . . (u)
|

{z

biae

Wierzchoek t jest szary w momencie d(u) poniewa nie ma krawdzi od


czarnych do biaych wierzchokw. Zatem w momencie d(t) < d(u) istniaa
biaa cieka z t do (u). Zatem (u) jest potomkiem t w lesie przeszukiwania w gb grafu G. A std f ((u)) < f (t). Poniewa u 7 t to otrzymujemy
sprzeczno z denicj (u).
Zatem (u) nie moe by biay w momencie d(u).
Q.E.D.

Wniosek 7.14 Dla

u V , wierzchoki u i (u) le w tej samej silnie

spjnej skadowej grafu G.

Dowd. Z denicji (u) mamy u 7 (u). Lematu 7.13 (u) 7 u. Zatem

u (u).

Q.E.D.

Lemat 7.15 Niech

u, v V . Wtedy u i v le w tej samej silnie spjnej


skadowej grafu G wtedy i tylko wtedy gdy (u) = (v).

Dowd. wynika bezporednio z Wniosku 7.14.


. Jeli u i v le w tej samej silnie spjnej skadowej to u 7 v i v 7 u
oraz Lematu 7.12.2 mamy, e f ((u)) = f ((v)). Zatem z rnowartociowoci f mamy, e (u) = (v).
Q.E.D.

Twierdzenie 7.16 Powyszy algorytm poprawnie znajduje silnie spjnej


skadowe grafu G.

127

Dowd. Dowd przeprowadzimy przez indukcj ze wzgldu dla liczb


drzew w lesie przeszukiwania w gb grafu GT .
Pokaemy, e jeli do tej pory skonstruowane drzewa lasu przeszukiwania w gb grafu GT stanowi silnie spjne skadowe grafu GT (i G) to
wierzchoki kolejnego drzewa skonstruowanego przez procedur DF S(GT )
stanowi kolejn silnie spjna skadow.
Krok bazowy jest oczywisty, bo na pocztku nie ma jeszcze adnych
drzew.
Krok indukcyjny. Niech r bdzie korzeniem kolejnego drzewa T skonstruowanego przez DF S(GT ).
Jeli bymy mieli, e r 6= (r) to, poniewa przeszukujemy wierzchoki
wzgldem malejcych wartoci funkcji f , f (r) < f ((r)). Zatem (r) zostao
ju umieszczone w jakim drzewie, a r jeszcze nie. Ale to jest niemoliwe z
Lematu 7.11 i Wniosku 7.14. Zatem r = (r).
Niech
S(r) = {w V : (w) = r}

bdzie silnie spjn skadow wierzchoka r. Pokaemy, e v jest wierzchokiem T wtedy i tylko wtedy gdy v S(r).
. Poniewa wierzchoki v i r le w tej samej silnie spjnej skadowej to
DF S(GT ) umieszcza je na tym samym drzewie. Poniewa r jest korzeniem
T , to v jest wierzchokiem T .
. Pokaemy, e jeli w V oraz
1. f ((w)) > f (r) lub
2. f ((w)) < f (r)
to w nie jest umieszczone w drzewie T .
Ad 1. Z zaoenia indukcyjnego gdy r zosta wybrany na korze T , to w
zosta ju wczeniej odkryty i wstawiony do drzewa o korzeniu (w).
Ad 2. Jeli w zostanie wstawiony do drzewa T , to r 7 w w grae GT .
Zatem w 7 r w grae G. A to jest sprzeczne z denicj (w), poniewa
w 7 r i f ((w)) < f (r).
Q.E.D.

128

7.7 Minimalne drzewo rozpinajce


Niech G = (V, E) bdzie grafem niezorientowanym. Przez drzewo w tej
sekcji bdziemy rozumieli spjny acykliczny graf niezorientowany. Funkcj
W : E R+ ze zbioru krawdzi grafu G do zbioru dodatnich liczb rzeczywistych nazywamy funkcj wag. Graf G, na ktrym jest okrelona funkcja
wag nazywamy grafem z wagami. Dla (u, v) E waga W (u, v) moe oznacza koszt poczenia u z v , lub odlego z u do v , i tym podobne wartoci.
Problem znajdowania minimalnego drzewa rozpinajcego polega na
znalezieniu zbioru krawdzi, ktre cz wszystkie wierzchoki w 'najtaszy'
sposb.
Problem (znajdowanie minimalnego drzewa rozpinajcego).

Dane wejciowe: spjny graf niezorientowany G = (V, E) z funkcja wag


W.
Wynik: spjny (i acykliczny) graf niezorientowany G0 = (V, T ) taki, e
T E oraz waga zbioru T
W (T ) =

W (e)

eT

jest minimalna.
Poniszy algorytm uywa struktury danych dla rodziny zbiorw
rozcznych. Jest to algorytm zachanny. Pochodzi on od Kruskala.
Opis algorytmu Kruskala znajdowania minimalnego drzewa rozpinajcego:

1. T := ;
2. dla kadego wierzchoka z V tworzymy zbir {v};
3. sortujemy krawdzie grafu G wzgldem niemalejcych wag;
4. przegldamy krawdzie (u, v) E w porzdku niemalejcych wag i
jeeli f ind(u) 6= f ind(v) to wykonujemy
(a) T := T {(u, v)};
(b) union(u, v) (dodajemy zbiory do ktrych nale wierzchoki u i
v ).
129

Czas dziaania algorytmu Kruskala.

1. Na pocztku inicjalizujemy zbir T jako zbir pusty i wykonujemy |V |


operacji make-set;
2. Nastpnie sortujemy zbir krawdzi E w czasie O(|E| log(|E|);
3. Na koniec dla kadej krawdzi z E wykonujemy dwie operacje find i
by moe po jednej operacji union i przypisania;
4. W sumie algorytm wykonuje O(|E| + |V |) operacji make-set, union,
find, wrd ktrych jest |V | operacji make-set; zatem, z Faktu 6.1
wynika, e te operacje s wykonane w czasie O(|E| + |V | log(|V |).
Poniewa graf jest spjny wic |E| |V | 1. Std otrzymujemy

Fakt 7.17 Czas dziaania algorytmu Kruskala dla spjnego niezorientowanego grafu z wagami G = (V, E) jest rwny O(|E| log(|E|).
Przykad. W grae z wagami
7

1
6



Q
8
Q  2

Q
 Q

Q
Q
3

3


2





4

6


6

Q
Q
3

Q
Q
Q
Q
5







krawdzie wybrane przez algorytm maj wagi wzite w ramk. Zauwamy,


e minimalne drzewo rozpinajce zaley od porzdku w jakim przegldamy
krawdzie o rwnych wagach. By zbudowa drzewo takie jak zaznaczone na
grae algorytm mg kolejno docza nastpujce krawdzie:
(4, 2), (5, 3), (2, 3), (3, 6), (4, 8), (4, 7), (8, 9), (4, 1).

Zanim uzasadni, e powyszy algorytm poprawnie znajduje minimalne


drzewo rozpinajce potrzeba kilku denicji.
130

Niech G = (V, E) bdzie grafem niezorientowanym. Podziaem zbioru V


nazywamy par (S, V \ S) tak, e S V . Krawd (u, v) przecina podzia
(S, V \S) jeli jeden z jej kocw jest w S a drugi w V \S . Krawd (u, v) E
jest krawdzi lekk dla podziau, (S, V \ S), jeli (u, v) przecina ten podzia
oraz ma najmniejsz wag spord wszystkich krawdzi przecinajcych ten
podzia. Niech A E bdzie podzbiorem minimalnego drzewa rozpinajcego. Podzia (S, V \ S) respektuje zbir krawdzi A, gdy adna krawd
z A nie przecina (S, V \ S). Krawd (u, v) E jest krawdzi bezpieczn
dla A, gdy A {(u, v)} te jest podzbiorem krawdzi pewnego minimalnego
drzewa rozpinajcego.
Uwaga. Krawdzie bezpieczne to takie ktre maja interesujce nas wasnoci a krawdzie lekkie to takie, ktre s charakteryzowane przez atwy do
sprawdzenia warunek. Poniszy Lemat mwi, e lekko gwarantuje bezpieczestwo.

Lemat 7.18 Niech

G = (V, E) bdzie spjnym grafem niezorientowanym z


funkcj wag W : E R+ , A E podzbir jakiego minimalnego drzewa
rozpinajcego dla G. Niech podzia (S, V \ S) respektuje A oraz (u, v) E
bdzie krawdzi lekk dla (S, V \ S). Wtedy (u, v) jest krawdzi bezpieczn
dla A.

Dowd. Niech podzia (S, V \ S) respektuje A oraz (u, v) E bdzie


krawdzi lekk dla (S, V \ S) oraz (V, T ) bdzie minimalnym drzewem
rozpinajcym takim, e A T . Musimy pokaza, e istnieje minimalne
drzewo rozpinajce zawierajce A {(u, v)}.
Jeli (u, v) T to teza jest oczywista. Zamy zatem, e (u, v) 6 T .
Skonstruujemy drzewo T 0 E takie, e A {(u, v)} T 0 oraz (V, T 0 )
te jest minimalnym drzewem rozpinajcym. Poniewa (V, T ) jest spjny, to
istnieje cieka z u do v w (V, T ). Poniewa (u, v) przecina (S, V \S), to na tej
ciece w (V, T ) istnieje co najmniej jedna krawd (x, y) T i przecinajca
(S, V \ S). Poniewa (V, T ) jest spjny i acykliczny, to (V, T \ {x, y}) ma
dokadnie dwie skadowe, ktre czy krawd (u, v). Zatem kadc T 0 =
(T \ {(x, y)}) {(u, v)} otrzymujemy (V, T 0 ) jako spjny i acykliczny graf.
Musimy jeszcze pokaza, e W (T ) = W (T 0 ). Z minimalnoci T mamy, e
W (T ) W (T 0 ). Z drugiej strony
W (T 0 ) W (T ) =

X
eT 0

W (e)

W (e) = W (u, v) W (x, y) 0

eT

gdzie ostatnia nierwno wynika std, e (u, v) i (x, y) przecinaj podzia


(S, V \ S) oraz (u, v) jest lekka dla tego podziau. Zatem W (T ) W (T 0 ).
131

Q.E.D.

Wniosek 7.19 Niech G = (V, E) bdzie spjnym grafem niezorientowanym

z funkcj wag W : E R+ , A E podzbir jakiego minimalnego drzewa


rozpinajcego dla G. Niech C bdzie skadow spjn grafu GA = (V, A).
Jeli (u, v) E jest krawdzi lekk dla (C, V \ C) to (u, v) jest krawdzi
bezpieczn dla A.
Dowd. Poniewa C jest skadow spjn grafu GA , to podzia (C, V \C)
respektuje A. Zatem z Lematu 7.18 otrzymujemy tez Wniosku.
Q.E.D.

W ten sposb pokazalimy

Twierdzenie 7.20 Algorytm znajdowania minimalnego drzewa rozpinajcego jest poprawny.

132

Zoono algorytmw (3)

8.1 Problemy decyzyjne


Problemy atwo obliczalne

Problem
Zoono
Szukanie sowa w sowniku
O(ln n)
Minimum w tablicy
O(n)
Sortowanie
O(n ln n)
Sortowanie topologiczne
O(|V | + |E|)
Znajdowanie silnie spjnych skadowych O(|V | + |E|)
Pierwszo liczb
O(n12 ) (2002)
S to problemy wielomianowe. Uwaa si, e tylko takie problemy s efektywnie obliczalne na komputerach. Poniej przytocz trzy powody dlaczego
tak jest.
1. Algorytm o zoonoci O(n100 ) nie jest efektywny ale takich zoonoci
w praktyce 'nie ma'. Zwykle wykadnik jest niewikszy ni 3 lub 4.
2. To czy algorytm dziaa w czasie wielomianowym czy nie nie zaley od
modelu oblicze (komputera).
3. Problemy wielomianowe maj dobre wasnoci (np. zoenie problemw wielomianowych jest problemem wielomianowym).
eby mc atwiej porwnywa problemy musimy je troch ujednolici,
tzn. popatrze na nie troch abstrakcyjniej.
Abstrakcyjny problem algorytmiczny jest to relacja binarna Q I S
gdzie I - jest zbiorem poprawnych danych wejciowych a S zbiorem moliwych rozwiza. Jeli (i, s) Q to s jest poprawnym rozwizaniem problemu
dla danych i.
Przykad. Problem znajdowania najkrtszej cieki w grae pomidzy
dwoma wierzchokami mona w abstrakcyjny sposb przedstawi tak:
I = {(G, x, y) : G graf , x, y V (G)},
S jest zbiorem cieek w grafach (skoczone cigi). Wtedy ((G, x, y), s)
QN S i s jest najkrtsz ciek w G z x do y .

133

By jeszcze uproci rozwaania ograniczymy si do problemw decyzyjnych.


Abstrakcyjny problem decyzyjny jest to abstrakcyjny problem algorytmiczny Q I S taki, e S = {0, 1} oraz Q jest funkcj.
Przykad. Problem znajdowania najkrtszej cieki w grae QN S
pomidzy dwoma wierzchokami mona te przedstawi jako problem decyzyjny QDN S tak: QDN S (G, x, y, k) = 1 wtedy i tylko wtedy gdy najkrtsz
ciek w G z x do y ma dugo co najwyej k.

Problemy decyzyjne s atwiejsze ale czsto abstrakcyjne problemy algorytmiczne mona do nich zredukowa. Ponadto, jeeli umiemy szybko rozwiza problem algorytmiczny to te umiemy szybko rozwiza
odpowiadajcy mu problem decyzyjny. Na og jest te odwrotnie. W
szczeglnoci, jeli problem decyzyjny nie daje si szybko rozwiza to
problem algorytmiczny odpowiadajcy mu tym bardziej nie ma szybkiego
rozwizania.
Jak zwykle, zakadamy, e na danych wejciowych I kadego problemy
jest okrelona rozsdna funkcja | | : I N przyporzdkowujca danym
i I rozmiar |i| N .
Problem decyzyjny Q jest wielomianowo obliczalny jeli istnieje algorytm
dziaajcy w czasie wielomianowym sprawdzajcy czy Q(i) = 1 dla i I .
Klas takich problemw oznaczamy P.

8.2 Algorytmy werykujce


Dla wielu problemw atwo jest sprawdzi, e pewien obiekt jest poprawnym
rozwizaniem cho trudno jest takie rozwizanie znale. Na przykad,
atwiej jest sprawdzi czy dany cig x0 , . . . , xl reprezentuje ciek dugoci
niewikszej ni k w grae G z x do y , ni takiej cieki szuka.
Innym przykadem jest problem HAM znajdowania cyklu Hamiltona w
grae. Dla grafu G, HAM (G) = 1 (lub G HAM ) gdy istnieje w G
cykl Hamiltona tzn. taki cykl, ktry przechodzi przez kady wierzchoek
dokadnie jeden raz. atwo jest sprawdzi czy pewien cig wierzchokw
wyznacza cykl Hamiltona ale trudno jest taki cykl znale.
Niech I zbir danych wejciowych, Q I problem decyzyjny, W zbir
wiadkw. Algorytm A o dwch argumentach werykuje problem Q jeeli
i Q wtedy i tylko wtedy gdy istnieje w W taki, e A(i, w) = 1.
Problem Q I jest obliczalny w niedeterministycznym wielomianowym
134

czasie (naley do klasy NP) jeeli istnieje zbir wiadkw W , algorytm o


dwch argumentach A dziaajcy w wielomianowym czasie, oraz staa c > 0
takie, e Q(i) = 1 wtedy i tylko wtedy gdy istnieje wiadek w W , taki, e
|w| = O(|i|c ) oraz A(i, w) = 1.
Problem Q I naley do klasy co-NP, jeeli problem I \ Q I naley
do klasy NP.
Przykady. Niech Graf bdzie zbiorem grafw skoczonych.

1. HAM NP.
2. k-kolorowanie. k Kolor Graf . G k Kolor jeli istnieje takie
pokolorowanie wierzchokw grafu G, k kolorami, e adne dwa incydentne ze sob wierzchoki nie s pokolorowane tym samym kolorem.
k Kolor NP.
3. Kliki. k Klika Graf . G k Klika jeli istnieje zbir k wierzchokw w grae G, w ktrym kade dwa wierzchoki s ze sob incydentne. k Klika NP.
4. Spenialno. I -zbir formu klasycznego rachunku zda, SAT
I . SAT jeeli istnieje wartociowanie v zmiennych z takie, e
v() = 1. Na przykad x x, x (y z) SAT , x x 6 SAT .
SAT NP.
5. Tautologie. I -zbir formu klasycznego rachunku zda, T AU T I .
T AU T jeeli dla dowolnego wartociowania v zmiennych z mamy
v() = 1. T AU T co NP.
6. Izomorzm grafw. I = Graf Graf . GIzo I . (G, G0 ) GIzo gdy
G jest izomorczny z G0 . GIzo NP.
7. Pokrycie wierzchokowe grafu. k P W Graf . G k P W
gdy istnieje k-elementowy zbir wierzchokw W taki, e dla dowolnej krawdzi (i, j) w G, i W lub j W . k P W NP.
8. Liczby pierwsze. P RIM E N . n P RIM E gdy n jest liczb
pierwsz. P RIM E P (2002).
9. 3 CN F SAT NP.

135

8.3 Redukowalno problemw i problem P=NP


Mwimy, e problem decyzyjny Q I redukuje si do problemu decyzyjnego
Q0 I 0 (oznaczenie: Q P Q0 ) jeli istnieje wielomianowo obliczalna funkcja
f : I I 0 taka, e
i Q iff f (i) Q0 .

Gdy Q P Q0 i Q0 jest atwo obliczalny to Q te i jeeli Q nie jest atwo


obliczalny to Q0 te. Mamy

Fakt 8.1 Jeeli Q P

Q0 to

1. jeeli Q0 P to Q P;
2. jeeli Q 6 P to Q0 6 P;
Przykad redukcji kKolor P SAT .
Niech G = (V, E) bdzie grafem, V = {1, . . . , n}. Skonstruujemy formu klasycznego rachunku zda G rozmiaru wielomianowego w stosunku
do rozmiaru G tak, e G jest spenialna wtedy i tylko wtedy gdy G jest
k -kolorowalny.
Formua G ma zmienne
xij dla i = 1, . . . , n, j = 1, . . . , k.

Intuicyjnie zmienna xi,j ma oznacza, e i-ty wierzchoek jest pomalowany


na j -ty kolor.
Formua
1 =

n
^
^

k
_
_

i=1

j=1

xi,j

wyraa fakt, e kady wierzchoek jest pomalowany na co najmniej jeden z


k kolorw.
Formua
2 =

n
^
^

k
_
_

i=1

j,j 0 =1,j6=j 0

(xi,j xi,j 0 )

wyraa fakt, e kady wierzchoek jest pomalowany na co najwyej jeden z


k kolorw.
Formua
3 =

^
^

(i,i0 )E

k
_
_

j=1

136

(xi,j xi0 ,j )

wyraa fakt, e wierzchoki incydentne s pomalowane na rne kolory.


Niech G = 1 2 3 . Oczywicie formua G jest rozmiaru wielomianowego w stosunku do rozmiaru grafu G.
Jeli G jest speniona przez wartociowanie W to i-ty wierzchoek z V
malujemy na kolor j -ty wtedy i tylko wtedy gdy W (xi,j = 1 dla i = 1, . . . , n,
j = 1, . . . , k i w ten sposb otrzymujemy pokolorowanie grafu G na k kolorw.
Z drugiej strony, jeli C : V {1, . . . , k} jest pokolorowaniem grafu G
na k kolorw to wartociowanie W takie, e W (xi,j = 1 wtedy i tylko wtedy
gdy C(i) = j dla i = 1, . . . , n, j = 1, . . . , k spenia formu G .
Zatem formua G = 1 2 3 ma dane wasnoci.
Uwaga. Redukcja w drug stron pokazujca, e SAT P kKolor te
istnieje ale jest trudniejsza.

Mwimy, e problem Q jest NP-trudny, jeli dla kadego problemu Q0


NP, Q0 P Q. Problem Q jest NP-zupeny, jeli Q jest NP-trudny oraz
Q NP.
Poniszy diagram opisuje zalenoci pomidzy wprowadzonymi klasami
problemw. Przypomnijmy, e problem jest obliczalny, jeeli istnieje (jakikolwiek) algorytm, ktry go rozwizuje.

Problemy decyzyjne
Problemy obliczalne

co-NP
NP

Problemy

NP

-zupene

Problem P=NP. Czy P=NP?


Fakt 8.2 Jeli jeden problem NP-zupeny naley do Pto P=NP=co-NP.
137

Przykady problemw NP-zupenych.

1. HAM .
2. k Kolor.
3. k Klika.
4. SAT .
5. GIzo.
6. kP W .
7. 3 CN F SAT .

8.4 Problemy nieobliczalne


Pytanie czy istniej problemy nieobliczalne ma posmak 'lozoczny',
poniewa nie dotyczy ono naszej kondycji tu i teraz ale tego co w ogle da
si obliczy. Innymi sowy dotyka problemu 'granicy naszych moliwoci'.
Twierdzca odpowied na to pytanie pochodzca od K.Godla wywoaa sporo
zamieszania, ktre tu i wdzie trwa do dzi.
Pokae, e tak zwany problem stopu jest jednym z problemw nierozstrzygalnych.
Problem stopu.

Dane wejciowe: cigi znakw (dowolnej dugoci) s1 i s2 .


Wynik: true gdy s1 jest tekstem procedury (w Pascalu) majcej jako
parametr cig znakw oraz procedura s1 zatrzymuje si na danych s2 ,
false w przeciwnym przypadku.

Inaczej mwic, by rozwiza ten problem trzeba skonstruowa funkcj

Stop dziaajc na parach cigw znakw sprawdzajc czy pierwszy cig

zastosowany do drugiego jako procedura (o ile to ma sens) zatrzyma si czy


nie:

Stop[s1,s2] =

true gdy s1 jest tekstem procedury w Pascalu,

false

ktra ma jeden parametr typu


'cigu znakw dowolnej dgoci',
oraz s1 na danych s2 zatrzymuje si,
w przeciwnym przypadku.
138

Przypumy, e problem stopu jest obliczalny i e mamy tak procedur

Stop jak wyej. Wtedy moemy skonstruowa procedur Diag z jednym

parametrem typu cigu znakw w nastpujcy sposb:


procedure Diag (s);
begin
if Stop[s,s] then loop
end;

gdzie loop oznacza dowoln ptl nieskoczon, na przykad


while true do i:=i

Procedura Diag sprawdza czy procedura s zatrzymuje si dla parametru


aktualnego bdcego tekstem tej procedury. Jeli zatrzymuje si to Diag
wchodzi w ptl nieskoczon loop a jeli nie to Diag zatrzymuje si.
Niech 'Diag' oznacza tekst procedury Diag. Powstaje pytanie co si
stanie gdy wykonamy Diag['Diag']? W szczeglnoci, czy procedura si
zatrzyma czy nie?
Jeli Diag['Diag'] zatrzyma si to procedura Stop['Diag','Diag']
zwrci warto true. Ale to oznacza, e Diag['Diag'] wejdzie w nieskoczon ptl loop i si nie zatrzyma. Czyli mamy sprzeczno!
Przypumy teraz, e Diag['Diag'] nie zatrzyma si. Wtedy procedura
Stop['Diag','Diag'] zwrci warto false. I Diag['Diag'] po sprawdzeniu warunku nie wejdzie w nieskoczon ptl loop i si zatrzyma. Czyli
mamy znowu sprzeczno!
A to oznacza, e takiego programu Stop by nie moe! Czyli pokazalimy,
e

Twierdzenie 8.3 Problem stopu jest nieobliczalny.


Zauwamy, e problem stopu jest do skromnym problemem w stosunku do tego co by 'mona chcie'. W szczeglnoci, ciekawszy problem
czy dany program rozwizuje poprawnie dany problem algorytmiczny te
nie jest obliczalny.

8.5 Metody przyblione


Co robi jak nie mona rozwiza problemu efektywnie?
Jeeli nie moemy rozwiza problemu efektywnie takim jak on jest, to
trzeba nieco zliberalizowa nasze wymagania by 'zyska na szybkoci kosztem
139

jakoci'. Na przykad, moemy zmniejszy nasze oczekiwania dotyczce


dokadnoci rozwizania, i/lub pewnoci rozwizania. S trzy metody, ktre
pogarszajc jako rozwizania zwikszaj szybko dziaania algorytmw:
1. Heurystyki: by znale rozwizanie stosujemy pewne strategie, ktre
dostatecznie czsto, cho nie zawsze, dziaaj szybko i dostatecznie
czsto, cho by moe nie zawsze, daj poprawne rozwizania.
2. Algorytmy aproksymacyjne: szukamy rozwiza, ktre s troch gorsze
od optymalnych ale przy pomocy efektywnych algorytmw.
3. Algorytmy probabilistyczne: szukamy rozwiza optymalnych ale
znalezione rozwizania s poprawne tylko z pewnym, satysfakcjonujcym nas, prawdopodobiestwem.
Heurystyki s zwykle bardzo silnie zwizane z problemem, ktry
rozwizuj i s zwykle trudne do opisania w sposb oglny. Na przykad
istniejce algorytmy szachowe uywaj rnego rodzaju heurystyk, ktre
s wynikiem wielowiekowych docieka mistrzw szachowych. Nie daj one
pewnoci, e strategia wybrana przez komputer jest optymalna ale czsto
okazuje si skuteczna.
Poniej podamy przykad algorytmu aproksymacyjnego i dwch algorytmw probabilistycznych.

Algorytm aproksymacyjny dla pokrycia wierzchokowego grafu.


Problem pokrycia wierzchokowego grafu przedstawiony zosta wczeniej
jako problem decyzyjny. Odpowiedni problem optymalizacyjny wyglda tak:
Problem pokrycia wierzchokowego grafu.

Dane wejciowe: graf G = (V, E).


Wynik: minimalny podzbir W V taki, e dla dowolnej krawdzi
(i, j) E , i W lub j W .

Ten problem jest NP-zupeny, zatem nie moemy oczekiwa, e skonstruujemy algorytm znajdujcy efektywnie optymalne rozwizanie. Natomiast
istnieje prosty algorytm zachanny, ktry znajduje rozwizanie rozmiaru co
najwyej dwa razy wikszego od optymalnego rozwizania:
procedure approx-PW(G:graf);
begin

140

W:=[]; F:=E;
while F<>[] do begin
niech (u,v) pierwszy element z F;
W:=W+{u,v};
wyrzuc wszystkie krawedzie z F o koncu u lub v;
end;

Po wykonaniu tej procedury W jest zbiorem krawdzi takim, e dla


dowolnej krawdzi (i, j) E , i W lub j W . Ponadto, mona pokaza,
e W jest co najwyej dwa razy wikszy od kadego innego zbioru o tej
wasnoci. Procedura approx-PW(G) kopiuje zbir krawdzi E grafu G jako
nowy zbir F . W ptli while procedura wybiera kolejn krawd (u, v) z
F i dodaje do konstruowanego zbioru jej koce. Nastpnie usuwa wszystkie
krawdzie z F , ktrych jednym z kocw jest wierzchoek u lub v .

Algorytm probabilistyczny werykowania pierwszoci liczb.


Werykacja czy dua liczb naturalna jest pierwsza czy zoona te wydaje
si by trudnym problemem. Nie istnieje obecnie, aden algorytm, ktry by
mg efektywnie sprawdzi (nawet na najszybszych dostpnych komputerach) czy np. 300-cyfrowa liczba jest pierwsza. Z drugiej strony problem ten
ma fundamentalne znaczenie dla kryptograi z kluczem publicznym RSA.
Liczby pierwsze i zoone maj rne wasnoci, ktre mona efektywnie
sprawdza. Moe istnie na przykad liczba w, ktra jest niejako wiadkiem
zoonoci liczby n. Poniej wyliczone s trzy rne sposoby jak w moe
wiadczy o zoonoci liczby n. Majc n i w, obliczenie czy w taki wanie
sposb w wiadczy o zoonoci n jest efektywne.
1. wiadek Euklidesa: Jeeli N W D(w, n) > 0 to oczywicie n jest liczb
zoon. Problem w tym, e takich wiadkw w moe by bardzo
mao. Na przykad, jeeli n jest iloczynem dwch 100-cyfrowych liczb
pierwszych p i q to takich wiadkw jest (p 1) + (q 1) i szansa na
przypadkowe traenie na jednego z nich jest rzdu 101100 , czyli bardzo
maa.
2. wiadek Fermata: Jeeli w < n oraz wn1 6n 15 to, na mocy Maego
Twierdzenia Fermata, n jest liczb zoon. Niestety s liczby zoone
tzw. liczby Carmichaela, ktre w ogle nie maj wiadkw zoonoci w
sensie Fermata. Cho liczby Carmichaela s bardzo rzadkie to jednak
test przy uyciu wiadkw zoonoci w sensie Fermata jest uwaany
za niedoskonay.
5

n oznacza przystawanie modulo n.

141

3. wiadek Millera-Rabina: Jeeli 1 < w < n 1 oraz wn1 6n 1


lub w2 n 1 (tzn. w jest nietrywialnym pierwiastkiem z 1 modulo n), to n te jest liczb zoon. Dokadniej, w jest wiadkiem zoonoci w sensie Millera-Rabina dla liczby nieparzystej n,
jeli swiadekMR(n,w)=true, gdzie swiadekMR jest funkcj zdeniowan
poniej. wiadkw zoonoci w sensie Millera-Rabina jest bardzo
duo. W rzeczywistoci, o ile n jest nieparzyst liczb zoon, to co
najmniej poowa liczb pomidzy 1 a n jest takimi wiadkami. Ta mnogo wiadkw pozwala na skonstruowanie zadowalajacego (na razie)
algorytmu, werykujacego czy dana liczba jest pierwsza.
Werykacj czy dana liczba w jest wiadkiem zoonoci w sensie MilleraRabina dla liczby n mona wykona przy pomocy nastpujcej procedury:
function swiadekMR(n,w:integer):boolean;
begin
niech (b_k,...,b_0) bedzie dwojkowa reprezentacja liczby n-1;
d:=1; OK:=false; i:=k;
while (i>=0) and not OK do begin
x:=d;
d:=(d*d) mod n;
if (d=1) and (x<>1) and (x<>n-1) then
OK:=true; {wykryto nietrywialny pierwiastek z 1 modulo n}
if b_i=1 then d:=(d*a) mod n;
i:=i-1;
end;
swiadekMR:=OK or (d<>1);
{wykryto nietrywialny pierwiastek z 1 modulo n
lub w jest swiadkiem w sensie Fermata}
end;

Procedura swiadekMR(n,w) sprawdza czy wn1 n 1 a trakcie obliczania wartoci wn1 mod n sprawdza przy okazji czy nie ma nietrywialnego
(rnego od 1 i 1) pierwiastka z 1.
By zobaczy, jak jest liczona potga wn1 mod n, zauwamy, e formua
d = we oraz e = (bk , . . . , bi+1 )2 6 jest niezmiennikiem ptli while.
Jeli dla jednej liczby w liczba n przesza pozytywnie prb to z prawdopodobiestwem 21 jest liczb pierwsz. Ale nic nie stoi na przeszkodzie
6

Czyli, e e = 2i

Pk
j:=i+1

bj 2j

142

by taki test powtrzy wielokrotnie. Moemy wylosowa na przykad 100


liczb pomidzy 1 i n i dla nich przeprowadzi powyszy test. Jeli liczba n
wszystkie te testy przejdzie pozytywnie to prawdopodobiestwo, e n jest
1
liczb zoona jest 2100
zatem prawdopodobiestwo, e n jest liczba pierwsz
1
jest 1 2100 . Ponisza procedura implementuje t ide.
procedure test-Millera-Rabina(n:integer);
begin OK:=false;
for i:=1 to 100 do begin
a:=random(1,n-1);
OK:=OK or swiadekMR(n,w);
end;
test-Millera-Rabina:=OK;
end;

Jeli test-Millera-Rabina(n)=true to n jest liczb zoon na pewno,


a jeli test-Millera-Rabina(n)=false to n jest liczb pierwsz prawie na
pewno.

Algorytm probabilistyczny dla problemu wyboru par.


Technicznym powodem, dla ktrego liczba wiadkw zoonoci w sensie Millera-Rabina jest dua jest fakt mwicy o tym, e 'niewiadkowie'
stanowi waciw podgrup grupy Zn , liczb {0, . . . , n 1} z dodawaniem
modulo n. Z elementarnej teorii grup (Twierdzenie Lagrange'a) wiadomo, e
liczba elementw podgrupy dzieli liczb elementw grupy. A zatem podgrupa
'niewiadkw' Zn ma co najwyej n2 elementw.
Algorytm probabilistyczny dla problemu wyboru par jest oparty na obserwacji dotyczcej mnogoci wiadkw dla innego innego zjawiska. Jeli
mianowicie mamy dwa wielomiany o wspczynnikach rzeczywistych (by
moe wielu zmiennych) p(x1 , . . . , xn ) i q(x1 , . . . , xn ), ktre s rne to s
one rne dla bardzo wielu argumentw. Innymi sowy rzadko si zdarza
by rne wielomiany przyjmoway te same wartoci dla tych samych argumentw. A to powoduje, e by sprawdzi czy s one rwne, mona wybra
losowo n liczb rzeczywistych a1 , . . . , an i sprawdzi czy liczby rzeczywiste
p(a1 , . . . , an ) i q(a1 , . . . , an ) s rwne. Jeli nie, s rwne to na pewno wielomiany s rne ale jeli tak, to 'prawie na pewno' s one rwne! Algorytm,
ktry opisz poniej jest oparty na tej obserwacji.
Problem (decyzyjny) zgodnego wyboru par.

Dane wejciowe: graf skierowany G = (V, E) taki, e V = {1, . . . , 2n}


oraz jeli (i, j) E to 1 i n i n < j n.

143

Wynik:

TAK, jeeli istnieje zbir n krawdzi E 0 E taki, e


kady wierzchoek z {1, . . . , n} jest pocztkiem a kady wierzchoek
z {n + 1, . . . , 2n} jest kocem pewnej krawdzi E 0 . NIE, w przeciwnym
przypadku.

Opis algorytmu.

1. Niech A bdzie (n n)-macierz tak, ktrej wyrazy s rnymi zmiennymi albo rwne 0.
(

ai,j =

xi,j
0

gdy (i, n + j E)
w przeciwnym przypadku

dla i, j = 1, . . . , n.
2. Niech d(< xi,j >(i,n+j)E ) bdzie wielomianem, ktry jest wyznacznikiem (formalnym) macierzy A.
3. Wybieramy losowo liczby ri,j dla (i, n + j) E) wielomianie d.
4. Obliczamy warto w = d(< ri,j >(i,n+j)E ).
5. Jeeli w 6= 0 to zgodny wybr par istnieje na pewno i odpowiadamy
TAK. Jeeli w = 0 to zgodny wybr par nie istnieje 'prawie na pewno'
i odpowiadamy NIE.
Powyszy algorytm opiera si na obserwacji, e d(< xi,j >(i,n+j)E ) jest
wielomianem tosamociowo rwnym 0 wtedy i tylko wtedy gdy nie istnieje zgodny wybr par. Natomiast sprawdzenie czy d(< xi,j >(i,n+j)E
) jest wielomianem tosamociowo rwnym 0 ma charakter probabilistyczny. Korzystamy ze wspomnianego wyej faktu, e jeeli wielomian d(<
xi,j >(i,n+j)E ) nie jest tosamociowo rwny zero, to przypadkowe traenie
na punkt w ktrym si zeruje jest mao prawdopodobne.
Przypomnijmy, e wyznacznik (nn)-macierzy mona obliczy ze wzory:
detA =

sgn() x1,(1) . . . xn,(n)

Sn

gdzie Sn jest zbiorem permutacji zbioru {1, . . . , n} a sgn() jest znakiem


permutacji . Zatem wielomian d(< xi,j >(i,n+j)E ) nie jest tosamociowo rwny zero wtedy i tylko wtedy gdy istnieje permutacja Sn
taka, e ai,(i) = xi,(i) . A to ma miejsce tylko wtedy gdy zbir {(1, n +
144

(1)), . . . , (n, n + (n))} jest zawarty w E z zatem jest zgodnym wyborem

par.
Poniewa wyznacznik (n n)-macierzy mona obliczy efektywnie (patrz
nastpny rozdzia) to cay algorytm jest efektywny.
Przykad. Niech G = (V, E) bdzie nastpujcym grafem:

1 H
5
*

H
J 
H
2
3
4

j
J H
J
*
J
J

^
J
H
*
HH

j
H

-

6
7
8

Wtedy macierz A ma posta:

A=

0 x1,2 x1,3
0
x2,1
0
0
0
0 x3,2
0 x3,4
0
0 x3,4 x4,4

a jej wyznacznik
d(< xi,j >(i,n+j)E ) = detA = x1,2 x2,1 x3,4 x4,3 + x1,3 x2,1 x3,2 x4,4

ma dwa niezerowe skadniki odpowiadajce dwm rnym zgodnym


wyborom par:
{(1, 6), (2, 5), (3, 8), (4, 7)}

oraz
{(1, 7), (2, 5), (3, 6), (4, 8)}.

Zauwamy jednak, e powyszy algorytm probabilistyczny pozwala tylko


na stwierdzenie czy zgodny wybr par istnieje i nie daje moliwoci by go
efektywnie skonstruowa. Dzieje si tak
dlatego, e z informacji, e istniej
P
niezerowe skadniki wyraenia detA = Sn sgn() x1,(1) . . . xn,(n) nie
moemy wywnioskowa, ktre z nich rzeczywicie s niezerowe.

145

Rozwizywanie ukadw rwna liniowych

Rozwizywanie ukadw rwna liniowych wymaga operacji na macierzach


a zatem jest zwizane wykonywaniem operacji arytmetycznych na liczbach
rzeczywistych. Takie operacje s zwykle obarczone pewnym bdem
zwizanym z zaokrgleniami do liczb w postaci dziesitnej. Nie kada
metoda poprawna matematycznie jest te poprawna numerycznie tzn. daje
dobre przyblienie rzeczywistego wyniku. Poniej omwimy kilka operacji na macierzach: mnoenie, rozkad LUP i odwracanie. Rozkad LUP
macierzy nieosobliwej ma zastosowanie do efektywnego i stabilnego numerycznie rozwizywania ukadw rwna liniowych niejednorodnych. Jest
to pewna wersja metody eliminacji Gaussa.
Ustalmy w caej sekcji typ tablica=array[1..n,1..n] of real jako
typ (nn)-macierzy rzeczywistych a typ wektor=array[1..n] of real jako
typ n-wymiarowych wektorw rzeczywistych.

9.1 Mnoenie macierzy


Mnoenie macierzy mona atwo zaimplementowa w czasie O(n3 ) nastpujc procedur.
procedure mnozenie (var A,B,C :tablica);
begin
for i:=1 to n do
for j:=1 to n do begin
C[i,j]:=0;
for k:=1 to n do
C[i,j]:=C[i,j]+A[i,k]*B[k,j]
end;
end;

Po wykonaniu tej procedury C = A B . Istnieje te bardziej skomplikowany i bardziej efektywny algorytm mnoenia macierzy pochodzcy od
Strassena i dziaajcy w czasie O(nlg 7 O(n2.81 ).

9.2 Rozwizywanie ukadw rwna liniowych niejednorodnych metod rozkadu LUP


Niech A bdzie (n n)-macierz, ~b = [b1 , . . . , bn ] wektorem wierszowym,
~x = [x1 , . . . , xn ] wektorem wierszowym zmiennych. Wtedy, ukad n rwna
146

liniowych z n niewiadomymi ma posta:


A ~xT = ~bT .

Zajmiemy si rozwizaniem tego ukadu tylko w przypadku gdy detA 6= 0.


Mona to zrobi odwracajc macierz A o obliczajc ~xT = A1 ~bT . Jednak
obliczenie A1 jest zwykle obarczone duym bdem zaokrgle. Natomiast
jest inna metoda zwizana rozkadem LUP macierzy, ktra jest szybsza i
dokadniejsza.
Rozkad LUP polega na znalezieniu trzech (n n)-macierzy L, U i P
takich, ze
LU =P A

gdzie
1. L jest doln macierz trjktn z jedynkami na gwnej przektnej, tzn.
nad przektn w L wystpuj same zera a na przektnej same jedynki;
2. U jest grn macierz trjktn, tzn. pod przektn w U wystpuj
same zera;
3. P jest macierz permutacji, tzn. kadej kolumnie i kadym wierszu
macierzy P wystpuje dokadnie jedna jedynka a poza tym same zera.
Przykad rozkadu LUP. Niech

1 2 3

A= 2 4 2
1 1 2

Wtedy (3 3)-macierze

1 0 0
1 0 0
1 2
3

P = 0 0 1 L = 1 1 0 U = 0 1 1
0 1 0
2 0 1
0 0 4

maj dan posta oraz


L U = P A.

Zatem jest to rozkad LUP macierzy A.


Jeli P jest (nn)-macierz permutacji a Q jest dowoln (nk)-macierz
to iloczyn P Q ma te same wiersze co macierz Q lecz w innej kolejnoci.
Dokadniej, jeeli jest permutacj zbioru {1, . . . , n} tak, e pi,(i) = 1 dla
147

1, . . . , n, to i-ty wiersz macierzy P Q jest (i)-tym wierszem macierzy Q.


Na przykad, w powyszym przykadzie mnoenie przez macierz P z lewej
strony zostawia pierwszy wiersz na swoim miejscu ((1) = 1) oraz wymienia
wiersz drugi z trzecim ((2) = 3, (3) = 2).
Zauwamy te e, poniewa wiersze (n n)-macierzy permutacji P
stanowi baz ortonormaln Rn , to P 1 = P T (P T jest macierz
transponowan macierzy P ).

Majc rozkad LUP (n n)-macierzy A dla wektora ~b moemy rozwiza


ukad rwna A ~xT = ~bT wykorzystujc fakt, e rozwizanie ukadu rwna
liniowych w przypadku gdy macierz ukadu jest trjktna, jest szczeglnie
proste.
By rozwiza ukad rwna
A ~xT = ~bT

(13)

P A ~xT = P ~bT

(14)

wystarczy rozwiza ukad

poniewa jeli ~x spenia (14) to


A ~xT = P 1 P A ~xT = P 1 P ~bT = ~bT

Zatem ~x spenia te ukad (13). Poniewa P A = L U to by rozwiza


ukad (14) wystarczy rozwiza ukad
L U ~xT = P ~bT .

(15)

W tym celu rozwizujemy dwa ukady rwna liniowych


L ~y T = P ~bT

U ~xT = ~y T

z macierzami ukadu w postaci trjktnej. Wtedy


P A ~xT = L U ~xT = L ~y T = P ~bT .

Zatem ~x jest te rozwizaniem ukadu (13).


Przykad. Zanim przedstawi ogln procedur rozwizujc ukad rwna (13), zobaczmy jak to mona zrobi 'na piechot' na konkretnym
przykadzie.

148

Niech macierz

1 2 3

A= 2 4 2
1 1 2

bdzie macierz ukadu rwna, z rozkadem LUP

1 0 0
1 0 0
1 2
3

P = 0 0 1 L = 1 1 0 U = 0 1 1
0 1 0
2 0 1
0 0 4

tak jak w poprzednim przykadzie, a ~b = [2, 1, 3]. Wtedy ukad rwna


L ~y T = P ~bT

ma posta

y1

y + y2
+ y3

2y
1

=2
=3
=1

A std, rozwizujc 'od gry do dou' otrzymujemy


y1 = 2
y2 = 3 2y1 = 1
y3 = 1 3y1 + y2 = 3

Natomiast ukad rwna


U ~xT = ~y

majce posta

x1 + 2x2 + 3x3

=2
x2 x3 = 1
4x3 = 3

rozwizujemy 'od dou do gry':


x3 = 3/ 4 = 0.75
x2 = (1 + x3 )/ 1 = 1.75
x1 = (2 2x2 3x3 )/1 = 3.25

Ponisza Procedura implementuje ten sposb rozwizania (Perm jest


tutaj tablic typu tab=array[1..n] of integer zawierajc permutacj
zbioru {1, . . . , n} odpowiadajc tablicy P ):
149

procedure rozwiazanieLUP(var L,U: tablica;var Perm : tab; var b,x:wektor);


begin
{obliczenie wektora y}
for i:=1 to n do begin
z:=0;
for j:=1 to i-1 do z:=z+L[i,j]*y[j];
y[i]:=b[Perm[i]]-z;
end;
{obliczenie wektora x}
for i:=n downto 1 do begin
z:=0;
for j:=i+1 to n do z:=z+U[i,j]*x[j];
x[i]:=(y[i]-z)/U[i,i];
end;

9.3 Obliczanie rozkadu LUP


Zanim opiszemy rozkad LUP dla (n n)-macierzy A, opiszemy rozkad LU,
ktry jest nieco prostszy ale nie zawsze dziaa. Macierz A mona przedstawi
jako

a1,1

A = ...

an,1

#
"
. . . a1,n
a1,1 w
~

... ... =
~v T A0
. . . an,n

gdzie w
~ i ~v s wierszowymi (n 1)-wymiarowymi wektorami rzeczywistymi.
Tak przedstawion macierz A, o ile a1,1 6= 0 moemy rozoy w nastpujcy
sposb
"

A=

a1,1 w
~
T
~v
A0

"

~0
1
T
~v /a1,1 In1

# "

a1,1
w
~
~0T A0 ~v T w/a
~ 1,1

gdzie ~0 jest (n 1)-wymiarowym wektorem zerowym oraz ~v T w/a


~ 1,1 jest
(n 1, n 1)-macierz powsta z ~v T i w
~ przez zwyke mnoenie macierzowe i podzieleniu wszystkich wyrazw przez a1,1 . Poniewa macierz A jest
macierz nieosobliw to macierz A0 ~v T w/a
~ 1,1 te musi by macierz
nieosobliw. Nastpnie, indukcyjnie obliczamy (n 1, n 1)-macierze L0
i U 0 takie, ze
A0 ~v T w/a
~ 1,1 = L0 U 0

150

i otrzymujemy rozkad LU macierzy A:


"

A=

~0
1
T
~v /a1,1 In1
"

# "

# "

~0
1
T
~v /a1,1 In1
"

a1,1
w
~
~0T A0 ~v T w/a
~ 1,1

~0
1
T
~v /a1,1 L0

# "

a1,1
w
~
~0T L0 U 0
a1,1 w
~
~0T U 0

=LU

W ten sposb, o ile nie podzielilimy pod drodze przez 0 otrzymujemy


rozkad LU macierzy A. Rozkad LUP jest potrzebny wanie dlatego by
unikn takich dziele przez 0 lub, o ile to moliwe, liczby bliskie 0. Istotn
rnic w rozkadzie LUP w stosunku do rozkadu LU jest to, e zanim
wyeliminujemy w macierzy A wyrazy w pierwszej kolumnie przy pomocy
wyrazu a1,1 zamieniamy pierwszy wiersz z takim wierszem ktry ma najwikszy co do moduu pierwszy element. Cho proces rozkadu LU zosta
opisany rekurencyjnie procedur implementujca rozkad LU macierzy A
mona zapisa iteracyjnie:
procedure rozkladLU(var A,L,U:tablica);
begin
for k:=1 to n do begin
U[k,k]:=A[k,k];
for i:=k+1 to n do begin
L[i,k]:=A[i,k]/U[k,k];
U[k,i]:=A[k,i];
end;
for i:=k+1 to n do
for j:=k+1 to n do
A[i,j]:=A[i,j]-L[i,k]*U[k,j];
end;
end;
end;

Uwaga. Niech E(i)+c(k) bdzie macierz powsta z (n n)-macierzy


jednostkowej In przez Zastpienie 0 w k-tym wierszu i i-tej kolumnie liczb
c.

151

Redukujc macierz A do macierzy trjktnej metod eliminacji Gaussa,


eliminujemy pierwszym wyrazem pierwszego wiersza (a1,1 ) pierwsze wyrazy
pozostaych wierszy macierzy, eliminujemy drugim wyrazem drugiego wiersza (a2,2 ) drugie wyrazy pozostaych wierszy macierzy, itd. Eliminacja elementem ai,i elementu ak,i polega na pomnoeniu macierzy A z lewej strony
przez macierz E(i)ak,i /ai,i (k) . Zatem cay proces eliminacji Gaussa polega
na pomnoeniu macierzy A przez pewn odwracaln macierz G bdc
iloczynem macierzy postaci E(i)+c(k) . Poniewa A jest macierz nieosobliw,
to w efekcie eliminacji otrzymujemy grn macierz trjktn U tak, e
U = G A. Poniewa L U = A to L = G1 . Zatem L opisuje proces
odwrotny do eliminacji Gaussa dla macierzy A.
Jak ju wiemy, proces rozkadu LU moe si nie powie gdy bdziemy
prbowa dzieli przez 0. Ten problem nie wystpuje w rozkadzie LUP gdy
tam, dziki dodatkowej macierzy P permutujcej wiersze zapewniamy sobie
to, e nigdy prbujemy nie dzieli przez 0. W procesie rozkadu LUP, by
zminimalizowa bdy zaokrgle, tak permutujemy wiersze by nie tylko nie
dzieli przez 0 ale by eliminowa elementem o najwikszym module.
Pierwsz operacj przy rozkadzie LUP macierzy A jest znalezienie wiersza k macierzy A takiego, e
|ak,1 | = max{|al,1 | : i = 1, . . . , k}

Poniewa macierz A jest nieosobliwa to |ak,1 | > 0. Niech Q bdzie macierz


permutacji wymieniajc pierwszy wiersz z k-tym. Wtedy macierz Q A
moemy podobnie jak poprzednio przedstawi w postaci:
"

QA=

ak,1 w
~
~v T A0

oraz j rozoy, podobnie jak poprzednio macierz A:


"

A=

ak,1 w
~
T
~v
A0

"

~0
1
T
~v /ak,1 In1

# "

ak,1
w
~
~0T A0 ~v T w/a
~ k,1

Dalej rekurencyjnie znajdujemy rozkad LUP macierzy A0 ~v T w/a


~ k,1 taki,
e
P 0 (A0 ~v T w/a
~ k,1 ) = L0 U 0

Wtedy kadc

"

P =

1
~0T

152

~0
P0

Otrzymujemy rozkad LUP macierzy A.


"

P A=

# "

~0
1
0
T
P ~v /ak,1 L0

ak,1 w
~
~0T U 0

=LU

Oczywicie wszystkie trzy macierze L, U , P maj wymagana posta. By si


przekona, e jest to rzeczywicie rozkad macierzy A liczymy:
"

P A=

"

~0
P0

1
~0T
"

"

# "

~0
1
0
T
P ~v /ak,1 In1
"

# "

# "

ak,1
w
~
~0T A0 ~v T w/a
~ k,1

ak,1
w
~
~0T A0 ~v T w/a
~ k,1

~0
1
P 0 ~v T /ak,1 L0

# "

# "

ak,1
w
~
~0T L0 U 0

ak,1 w
~
~0T U 0

ak,1
w
~
~0T P 0 (A0 ~v T w/a
~ k,1 )

~0
1
0
T
P ~v /ak,1 In1
"

QA=

# "

~0
1
T
~v /ak,1 In1

~0
1
0
T
P ~v /ak,1 P 0

~0
P0

1
~0T

=LU

Podobnie jak w przypadku rozkadu LU, procedura implementujca


rozkad LUP macierzy A jest iteracyjna:
procedure rozkladLUP(var A,L,U:tablica; Perm:tab);
begin
for i:=1 to n do Perm[i]:=i;
for k:=1 to n do begin
max:=0;
for i:=k to n do {obliczanie maksymalnego modulu}

153

if abs(A[i,k])>max then begin


max:=abs(A[i,k]);
l:=i
end;
wymien(Perm[k],Perm[l]) {modyfikacja permutacji}
for i:=1 to n do {wymiana wierszy}
wymien(A[k,i],A[l,i])
U[k,k]:=A[k,k]; {obliczenie rozkladu LU}
for i:=k+1 to n do begin
L[i,k]:=A[i,k]/U[k,k];
U[k,i]:=A[k,i];
end;
for i:=k+1 to n do
for j:=k+1 to n do
A[i,j]:=A[i,j]-L[i,k]*U[k,j];
end;
end;
end;

Procedura wymien wymienia wartoci rejestrw.

9.4 Macierze odwrotne


Macierz odwrotn do (nn)-macierzy nieosobliwej A mona obliczy obliczajc rozkad LUP macierzy A i rozwizujc n niejednorodnych ukadw rwna z wyrazami wolnymi ~ei dla i = 1, . . . , n, gdzie ~ei jest i-tym wektorem
bazy standardowej Rn . Dokadniej, jeeli Xi jest kolumnowym wektorem
kolumnowym w Rn takim, e
A Xi = ~ei

dla i = 1, . . . , n, to wtedy
A1 = [X1 , . . . , Xn ].

9.5 Wyznacznik macierzy kwadratowej


Majc rozkad LUP macierzy A moemy atwo obliczy wyznacznik macierzy
A korzystajc z tego, e wyznacznik iloczynu macierzy jest iloczynem wyznacznikw oraz e, wyznacznik macierzy trjktnej jest iloczynem wyrazw
stojcych na przektnej. Niech
LU =P A

154

bdzie rozkadem LUP macierzy A. Poniewa na przektnej w macierzy L


stoj jedynki, to detL = 1. detP jest rwny 1 lub 1 w zalenoci od znaku
permutacjiQ reprezentowanej przez P . Poniewa U jest macierz trjktn
to detU = ni=1 L[i, i]. Zatem
detA = sgn()

n
Y

L[i, i].

i=1

By obliczy znak permutacji moemy w trakcie wykonywania procedury


rozkladLUP liczy na bieco liczb przestawie w tablicy Perm. Pon-

adto jeeli chcemy oblicza wyznacznik dowolnej macierzy kwadratowej


(niekoniecznie nieosobliwej) to moemy zmodykowa dodatkowo procedur rozkladLUP tak by sprawdza czy kadorazowo obliczony maksymalny
modu jest wikszy od 0. Jeli nie to macierz A jest osobliwa, a zatem
detA = 0.

155

Indeks

instrukcja
ptli for, 27
ptli while, 26
przypisania, 22
pusta, 24
warunkowa, 25
wejcia-wyjcia, 28
zoona, 25
iteracja
ograniczona, 27
warunkowa, 26

cieka, 106
algorytm, 6
-iczne rozwizanie, 6
-iczny problem, 6
aproksymacyjny, 140
Euklidesa, 5
probabilistyczny, 140
sortowania przez kopcowanie,
63
werykujcy, 134
zachanny, 59
analiza
numeryczna, 6
poprawnoci, 6
zoonoci, 6

jzyk
Pascal, 14
wysokiego poziomu, 14
klasa
NP, 135
P, 134
coNP, 135
kolejka, 84
kopiec, 63

bd
bezwzgldny, 75
wzgldny, 75
blok, 17
cecha, 74
cykl, 106
rozkazw, 12

lista
dwukierunkowa, 92
dwukierunkowa z wartownikiem, 93
jednokierunkowa, 91
listy
incydencji grafu, 106

diagramy skadniowe, 14
drzewo, 110
binarne, 85, 95
binarnych poszukiwa, 95
przeszukiwania wszerz, 110
graf

macierz
incydencji grafu, 106
magistrale komunikacyjne, 12
mantysa, 74
metoda
'dziel i rzd', 48
powrotw, 43

acykliczny, 106
niezorientowany, 105
skadowe spjne -u, 106
spjny, 106
zorientowany, 105
156

sortowania, 6
sortowania topologicznego,
122, 123
TAUT, 135
wie Hanoi, 9
wielomianowo obliczalny, 134
wyboru zaj, 59
wyszukiwania w sowniku, 10
znajdowania cyklu Hamiltona,
134
znajdowania
minimalnego
drzewa
rozpinajcego,
129
znajdowania
najkrtszej
cieki w grae, 133
znajdowania silnie spjnych
skadowych, 123
procedura, 29
dispose, 89
new, 89
rekurencyjna, 34
procesor, 12
program, 16
-owanie dynamiczne, 54
czciowo poprawny, 40
poprawny, 40

nadmiar, 76
niedomiar, 76
niezmiennik ptli, 5, 26, 28
notacja
O(f (n)), 8, 50
(f (n)), 50
(f (n)), 50
pami, 12
parametr
aktualny, 33
formalny, 33
procedury, 32
praojciec, 125
Problem
P=NP, 137
problem
hetmanw, 43
-w redukowalno, 136
abstrakcyjny - algorytmiczny,
133
algorytmiczny, 6
decyzyjny, 134
izomorzmu grafw, 135
kliki, 135
kolorowania grafu, 135
najduszego wsplnego podcigu, 54
NP-zupeny, 137
plecakowy
0-1, 61
uamkowy, 61
pokrycia
wierzchokowego,
135
przeszukiwania grafu w gb,
117
przeszukiwania grafu wszerz,
110
SAT, 135
scalania, 48

redukowalno problemw, 136


rekord, 20
reprezentacja
staopozycyjna, 71
zmiennopozycyjna, 74
rozmiar danych, 7
rozstrzygalno, 6
semantyka, 14
skadnia, 14
skadowe, silnie spjne, 123
staa, 18
stopie
157

-modu, 71
uzupenienie do 1, 71
uzupenienie do 2, 72

wierzchoka, 106
wyjciowy wierzchoka, 106
stos, 35, 82
system
dwjkowy, 69
dziesitny, 69
szesnastkowy, 70
tablica, 20
typ
acuchowy, 19
cakowity, 19
logiczny, 19
okrojony, 20
prosty, 18
rekordowy, 20
rzeczywisty, 19
standardowy, 18
strukturalny, 20
tablicowy, 20
wskanikowy, 86
wyliczeniowy, 19
znakowy, 19
ukad wejcia-wyjcia, 12
warunek
kocowy, 40
pocztkowy, 40
wzgldn dokadnoci komputera, 75
zoono algorytmu, 7
zapis logiczny, 23
zmienna, 17
dynamiczna, 86
globalna, 32
lokalna, 32
statyczna, 86
w procedurze, 32
znak
158

You might also like