Sie sind auf Seite 1von 39

IDZ DO

PRZYKADOWY ROZDZIA
SPIS TRECI

KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG

TWJ KOSZYK
DODAJ DO KOSZYKA

CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK

CZYTELNIA
FRAGMENTY KSIEK ONLINE

Algorytmy i struktury
danych
Autorzy: Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman
Tumaczenie: Andrzej Grayski
ISBN: 83-7361-177-0
Tytu oryginau: Data Structures and Algorithms
Format: B5, stron: 442
W niniejszej ksice przedstawiono struktury danych i algorytmy stanowice podstaw
wspczesnego programowania komputerw. Algorytmy s niczym przepis na
rozwizanie postawionego przed programist problemu. S one nierozerwalnie
zwizane ze strukturami danych listami, rekordami, tablicami, kolejkami, drzewami
podstawowymi elementami wiedzy kadego programisty.
Ksika obejmuje szeroki zakres materiau, a do jej lektury wystarczy znajomo
dowolnego jzyka programowania strukturalnego (np. Pascala). Opis klasycznych
algorytmw uzupeniono o algorytmy zwizane z zarzdzaniem pamici operacyjn
i pamiciami zewntrznymi.
Ksika przedstawia algorytmy i struktury danych w kontekcie rozwizywania
problemw za pomoc komputera. Z tematyk rozwizywania problemw powizano
zagadnienie zliczania krokw oraz zoonoci czasowej wynika to z gbokiego
przekonania autorw tej ksiki, i wraz z pojawianiem si coraz szybszych
komputerw, pojawia si bd take coraz bardziej zoone problemy
do rozwizywania i paradoksalnie zoono obliczeniowa uywanych
algorytmw zyskiwa bdzie na znaczeniu.
W ksice omwiono m.in.:

Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl

Tradycyjne struktury danych: listy, kolejki, stosy


Drzewa i operacje na strukturach drzew
Typy danych oparte na zbiorach, sowniki i kolejki priorytetowe wraz
ze sposobami ich implementacji
Grafy zorientowane i niezorientowane
Algorytmy sortowania i poszukiwania mediany
Asymptotyczne zachowanie si procedur rekurencyjnych
Techniki projektowania algorytmw: dziel i rzd, wyszukiwanie lokalne
i programowanie dynamiczne
Zarzdzanie pamici, B-drzewa i struktury indeksowe
Kademu rozdziaowi towarzyszy zestaw wicze, o zrnicowanym stopniu trudnoci,
pomagajcych sprawdzi swoj wiedz. Algorytmy i struktury danych to doskonay
podrcznik dla studentw informatyki i pokrewnych kierunkw, a take dla wszystkich
zainteresowanych t tematyk.

Spis treci

Od tumacza .............................................................................................................7
Wstp .....................................................................................................................11

1
Projektowanie i analiza algorytmw......................................................................15
1.1. Od problemu do programu ......................................................................................................................... 15
1.2. Abstrakcyjne typy danych.......................................................................................................................... 23
1.3. Typy danych, struktury danych i ADT ...................................................................................................... 25
1.4. Czas wykonywania programu .................................................................................................................... 28
1.5. Obliczanie czasu wykonywania programu................................................................................................. 33
1.6. Dobre praktyki programowania ................................................................................................................. 39
1.7. Super Pascal ............................................................................................................................................... 41
wiczenia .......................................................................................................................................................... 44
Uwagi bibliograficzne ....................................................................................................................................... 48

2
Podstawowe abstrakcyjne typy danych .................................................................49
2.1. Lista jako abstrakcyjny typ danych............................................................................................................ 49
2.2. Implementacje list ...................................................................................................................................... 52
2.3. Stosy ........................................................................................................................................................... 64
2.4. Kolejki........................................................................................................................................................ 68
2.5. Mapowania ................................................................................................................................................. 73
2.6. Stosy a procedury rekurencyjne ................................................................................................................. 75
wiczenia .......................................................................................................................................................... 80
Uwagi bibliograficzne ....................................................................................................................................... 84

3
Drzewa ...................................................................................................................85
3.1. Podstawowa terminologia .......................................................................................................................... 85
3.2. Drzewa jako abstrakcyjne obiekty danych................................................................................................. 92

SPIS TRECI

3.3. Implementacje drzew ................................................................................................................................. 95


3.4. Drzewa binarne ........................................................................................................................................ 102
wiczenia ........................................................................................................................................................ 113
Uwagi bibliograficzne ..................................................................................................................................... 116

4
Podstawowe operacje na zbiorach .......................................................................117
4.1. Wprowadzenie do zbiorw....................................................................................................................... 117
4.2. Sowniki ................................................................................................................................................... 129
4.3. Tablice haszowane ................................................................................................................................... 132
4.4. Implementacja abstrakcyjnego typu danych MAPPING ......................................................................... 146
4.5. Kolejki priorytetowe ................................................................................................................................ 148
4.6. Przykady zoonych struktur zbiorowych............................................................................................... 156
wiczenia ........................................................................................................................................................ 163
Uwagi bibliograficzne ..................................................................................................................................... 165

5
Zaawansowane metody reprezentowania zbiorw ..............................................167
5.1. Binarne drzewa wyszukiwawcze ............................................................................................................. 167
5.2. Analiza zoonoci operacji wykonywanych na binarnym drzewie wyszukiwawczym.......................... 171
5.3. Drzewa trie ............................................................................................................................................... 175
5.4. Implementacja zbiorw w postaci drzew wywaonych 2-3-drzewa................................................... 181
5.5. Operacje MERGE i FIND ........................................................................................................................ 193
5.6. Abstrakcyjny typ danych z operacjami MERGE i SPLIT ....................................................................... 202
wiczenia ........................................................................................................................................................ 207
Uwagi bibliograficzne ..................................................................................................................................... 209

6
Grafy skierowane .................................................................................................211
6.1. Podstawowe pojcia ................................................................................................................................. 211
6.2. Reprezentacje grafw skierowanych........................................................................................................ 213
6.3. Graf skierowany jako abstrakcyjny typ danych ....................................................................................... 215
6.4. Znajdowanie najkrtszych cieek o wsplnym pocztku....................................................................... 217
6.5. Znajdowanie najkrtszych cieek midzy kad par wierzchokw .................................................... 221
6.6. Przechodzenie przez grafy skierowane przeszukiwanie zstpujce.................................................... 229
6.7. Silna spjno i silnie spjne skadowe digrafu....................................................................................... 237
wiczenia ........................................................................................................................................................ 240
Uwagi bibliograficzne ..................................................................................................................................... 242

7
Grafy nieskierowane ............................................................................................243
7.1. Definicje ................................................................................................................................................... 243
7.2. Metody reprezentowania grafw.............................................................................................................. 245
7.3. Drzewa rozpinajce o najmniejszym koszcie........................................................................................... 246
7.4. Przechodzenie przez graf ......................................................................................................................... 253
7.5. Wierzchoki rozdzielajce i skadowe dwuspjne grafu .......................................................................... 256

SPIS TRECI

7.6. Reprezentowanie skojarze przez grafy................................................................................................... 259


wiczenia ........................................................................................................................................................ 262
Uwagi bibliograficzne ..................................................................................................................................... 264

8
Sortowanie ...........................................................................................................265
8.1. Model sortowania wewntrznego............................................................................................................. 265
8.2. Proste algorytmy sortowania wewntrznego............................................................................................ 266
8.3. Sortowanie szybkie (quicksort)................................................................................................................ 273
8.4. Sortowanie stogowe ................................................................................................................................. 283
8.5. Sortowanie rozrzutowe............................................................................................................................. 287
8.6. Dolne ograniczenie dla sortowania za pomoc porwna ....................................................................... 294
8.7. Szukanie k-tej wartoci (statystyki pozycyjne)........................................................................................ 298
wiczenia ........................................................................................................................................................ 302
Uwagi bibliograficzne ..................................................................................................................................... 304

9
Techniki analizy algorytmw ..............................................................................305
9.1. Efektywno algorytmw......................................................................................................................... 305
9.2. Analiza programw zawierajcych wywoania rekurencyjne.................................................................. 306
9.3. Rozwizywanie rwna rekurencyjnych ................................................................................................. 308
9.4. Rozwizanie oglne dla pewnej klasy rekurencji .................................................................................... 311
wiczenia ........................................................................................................................................................ 316
Uwagi bibliograficzne ..................................................................................................................................... 319

10
Techniki projektowania algorytmw ...................................................................321
10.1. Zasada dziel i zwyciaj ..................................................................................................................... 321
10.2. Programowanie dynamiczne .................................................................................................................. 327
10.3. Algorytmy zachanne ............................................................................................................................. 335
10.4. Algorytmy z nawrotami ......................................................................................................................... 339
10.5. Przeszukiwanie lokalne .......................................................................................................................... 349
wiczenia ........................................................................................................................................................ 355
Uwagi bibliograficzne ..................................................................................................................................... 358

11
Struktury danych i algorytmy obrbki danych zewntrznych .............................359
11.1. Model danych zewntrznych.................................................................................................................. 359
11.2. Sortowanie zewntrzne .......................................................................................................................... 362
11.3. Przechowywanie informacji w plikach pamici zewntrznych ............................................................. 373
11.4. Zewntrzne drzewa wyszukiwawcze ..................................................................................................... 381
wiczenia ........................................................................................................................................................ 387
Uwagi bibliograficzne ..................................................................................................................................... 390

SPIS TRECI

12
Zarzdzanie pamici ..........................................................................................391
12.1. Podstawowe aspekty zarzdzania pamici ........................................................................................... 391
12.2. Zarzdzanie blokami o ustalonej wielkoci ........................................................................................... 395
12.3. Algorytm odmiecania dla blokw o ustalonej wielkoci...................................................................... 397
12.4. Przydzia pamici dla obiektw o zrnicowanych rozmiarach ............................................................ 405
12.5. Systemy partnerskie ............................................................................................................................... 412
12.6. Upakowywanie pamici ......................................................................................................................... 416
wiczenia ........................................................................................................................................................ 419
Uwagi bibliograficzne ..................................................................................................................................... 421

Bibliografia ..........................................................................................................423
Skorowidz ............................................................................................................429

1
Projektowanie i analiza algorytmw

Stworzenie programu rozwizujcego konkretny problem jest procesem wieloetapowym. Proces ten
rozpoczyna si od sformuowania problemu i jego specyfikacji, po czym nastpuje projektowanie
rozwizania, ktre musi zosta nastpnie zapisane w postaci konkretnego programu, czyli zaimplementowane. Konieczne jest udokumentowanie oraz przetestowanie implementacji, a rozwizanie wyprodukowane przez dziaajcy program musi zosta ocenione i zinterpretowane. W niniejszym rozdziale zaprezentowalimy nasze podejcie do wymienionych krokw, nastpne rozdziay
powicone s natomiast algorytmom i strukturom danych, skadajcym si na wikszo programw komputerowych.

1.1. Od problemu do programu


Wiedzie, jaki problem tak naprawd si rozwizuje to ju poowa sukcesu. Wikszo problemw, w swym oryginalnym sformuowaniu, nie ma klarownej specyfikacji. Faktycznie, niektre (wydawaoby si) oczywiste problemy, jak sporzdzenie smakowitego deseru czy te zachowanie pokoju na wiecie wydaj si niemoliwe do sformuowania w takiej postaci, ktra
przynajmniej otwieraaby drog do ich rozwizania za pomoc komputerw. Nawet jednak, gdy
dany problem wydaje si (w sposb mniej lub bardziej oczywisty) moliwy do rozwizania przy
uyciu komputera, pozostaje jeszcze trudna zazwyczaj kwestia jego parametryzacji. Niekiedy bywa i tak, e rozsdne wartoci parametrw mog by okrelone jedynie w drodze eksperymentu.
Jeeli niektre aspekty rozwizywanego problemu daj si wyrazi w kategoriach jakiego
formalnego modelu, okazuje si to zwykle wielce pomocne, gdy rwnie w tych kategoriach poszukuje si rozwizania, a dysponujc konkretnym programem mona okreli (lub przynajmniej
sprbowa okreli), czy faktycznie rozwizuje on dany problem. Take abstrahujc od konkretnego programu majc okrelon wiedz o modelu i jego waciwociach, mona na tej podstawie podj prb znalezienia dobrego rozwizania.
Na szczcie, kada niemal dyscyplina naukowa daje si uj w ramy modelu (modeli) z jakiej
dziedziny (dziedzin). Moliwe jest modelowanie wielu problemw natury wybitnie numerycznej
w postaci ukadw rwna liniowych (w ten sposb oblicza si m.in. natenia prdu w poszczeglnych gaziach obwodu elektrycznego czy naprenia w ukadzie poczonych belek) bd
rwna rniczkowych (tak prognozuje si wzrost populacji i tak znajduje si stosunki ilociowe,
w jakich cz si substraty reakcji chemicznych). Rozwizywanie problemw natury tekstowej czy
symbolicznej odbywa si zazwyczaj na podstawie rozmaitych gramatyk wspomaganych zazwyczaj

16

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

obfitym repertuarem procedur wykonujcych rne operacje na acuchach znakw (w taki sposb
dokonuje si przecie kompilacja programu w jzyku wysokiego poziomu, tak rwnie dokonuje
si wyszukiwania konkretnych fraz tekstowych w obszernych bibliotekach).

Algorytmy
Kiedy ju dysponujemy odpowiednim modelem matematycznym dla naszego problemu, moemy
sprbowa znale rozwizanie wyraajce si w kategoriach tego modelu. Naszym gwnym
celem jest poszukiwanie rozwizania w postaci algorytmu pod tym pojciem rozumiemy skoczon sekwencj instrukcji, z ktrych kada ma klarowne znaczenie i moe by wykonana w skoczonym czasie przy uyciu skoczonego wysiku. Dobrym przykadem klarownej instrukcji, wykonywalnej w skoczonym czasie i skoczonym wysikiem, jest instrukcja przypisania w rodzaju
. Oczywicie, poszczeglne instrukcje algorytmu mog by wykonywane wielokrotnie
i niekoniecznie w kolejnoci, w ktrej zostay zapisane. Wynika std kolejne wymaganie stawiane
algorytmowi musi si on zatrzymywa po wykonaniu skoczonej liczby instrukcji, niezalenie
od danych wejciowych. Nasz program zasuguje wic na miano algorytmu tylko wtedy, gdy jego
wykonywanie nigdy (czyli dla adnych danych wejciowych) nie prowadzi do ugrznicia sterowania w nieskoczonej ptli.
Co najmniej jeden aspekt powyszych rozwaa nie jest do koca oczywisty. Okrelenie
klarowne znaczenie ma mianowicie charakter na wskro relatywny, poniewa to, co jest oczywiste
dla jednej osoby, moe by wtpliwe dla innej. Ponadto wykonywanie si kadej z instrukcji w skoczonym czasie moe nie wystarczy do tego, by algorytm koczy swe dziaanie po wykonaniu
skoczonej liczby instrukcji. Za pomoc serii argumentw i kontrargumentw mona jednak w wikszoci przypadkw osign porozumienie odnonie tego, czy dana sekwencja instrukcji faktycznie
moe by uwaana za algorytm. Zazwyczaj ostateczne wyjanienie wtpliwoci w tym wzgldzie
jest powinnoci osoby, ktra uwaa si za autora algorytmu. W jednym z kolejnych punktw niniejszego rozdziau przedstawilimy sposb szacowania czasu wykonywania konstrukcji powszechnie
spotykanych w jzykach programowania, dowodzc tym samym ich skoczonoci czasowej.
Do zapisu algorytmw uywa bdziemy jzyka Pascal wzbogaconego jednake o nieformalne opisy w jzyku naturalnym programy zapisywane w powstaym w ten sposb pseudojzyku nie nadaj si co prawda do wykonania przez komputer, lecz powinny by intuicyjnie zrozumiae dla Czytelnika, a to jest przecie w tej ksice najwaniejsze. Takie podejcie umoliwia
rwnie ewentualne zastpienie Pascala innym jzykiem, bardziej wygodnym dla Czytelnika, na
etapie tworzenia prawdziwych programw. Pora teraz na pierwszy przykad, w ktrym zilustrowalimy wikszo etapw naszego podejcia do tworzenia programw komputerowych.
Przykad 1.1. Stworzymy model matematyczny, opisujcy funkcjonowanie sygnalizacji wietlnej
na skomplikowanym skrzyowaniu. Ruch na takim skrzyowaniu opisa mona przez rozoenie go
na poszczeglne zakrty z konkretnej ulicy w inn (dla przejrzystoci przejazd na wprost rwnie uwaany jest za zakrt). Jeden cykl obsugi takiego skrzyowania obejmuje pewn liczb
faz, w kadej fazie mog by rwnoczenie wykonywane te zakrty (i tylko te), ktre ze sob nie
koliduj. Problem polega wic na okreleniu poszczeglnych faz ruchu i przyporzdkowaniu kadego z moliwych zakrtw do konkretnej fazy w taki sposb, by w kadej fazie kada para zakrtw by par niekolidujc. Oczywicie, rozwizanie optymalne powinno wyznacza najmniejsz
moliw liczb faz.
Rozpatrzmy konkretne skrzyowanie, ktrego schemat przedstawiono na rysunku 1.1. Skrzyowanie to znajduje si niedaleko Uniwersytetu Princeton i znane jest z trudnoci manewrowania,

17

1.1. OD PROBLEMU DO PROGRAMU

RYSUNEK 1.1.
Przykadowe
skrzyowanie

zwaszcza przy zawracaniu. Ulice C i E s jednokierunkowe, pozostae s ulicami dwukierunkowymi. Na skrzyowaniu tym mona wykona 13 rnych zakrtw; niektre z nich, jak AB
(czyli z ulicy A w ulic B) i EC, mog by wykonywane rwnoczenie, inne natomiast, jak AD i EB,
koliduj ze sob i mog by wykonane tylko w rnych fazach.
Opisany problem daje si atwo uj (modelowa) w postaci struktury zwanej grafem. Kady graf skada si ze zbioru wierzchokw i zbioru linii czcych wierzchoki w pary linie te
nazywane s krawdziami. W naszym grafie modelujcym sterowanie ruchem na skrzyowaniu
wierzchoki reprezentowa bd poszczeglne zakrty, a poczenie dwch wierzchokw krawdzi oznacza bdzie, e zakrty reprezentowane przez te wierzchoki koliduj ze sob. Graf odpowiadajcy skrzyowaniu pokazanemu na rysunku 1.1 przedstawiony jest na rysunku 1.2, natomiast w tabeli 1.1 widoczna jest jego reprezentacja macierzowa kady wiersz i kada kolumna
reprezentuje konkretny wierzchoek; jedynka na przeciciu danego wiersza i danej kolumny wskazuje, e odpowiednie wierzchoki poczone s krawdzi.

RYSUNEK 1.2.
Graf reprezentujcy
skrzyowanie pokazane
na rysunku 1.1

Rozwizanie naszego problemu bazuje na koncepcji zwanej kolorowaniem grafu. Polega ona
na przyporzdkowaniu kademu wierzchokowi konkretnego koloru w taki sposb, by wierzchoki
poczone krawdzi miay rne kolory. Nietrudno si domyli, e optymalne rozwizanie naszego
problemu sprowadza si do znalezienia takiego kolorowania grafu z rysunku 1.2, ktre wykorzystuje
jak najmniejsz liczb kolorw.

18

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

TABELA 1.1.
Macierzowa reprezentacja grafu z rysunku 1.2
AB

AC

AD

AB

BA

BC

BD

DA

DB







AC
AD

DC

EA

EB

EC








ED

BA
BC
BD
DA





DB


















DC
EA
EB
EC














ED

Zagadnienie kolorowania grafu studiowane byo przez dziesiciolecia i obecna wiedza na temat
algorytmw zawiera wiele propozycji w tym wzgldzie. Niestety, problem kolorowania dowolnego
grafu przy uyciu najmniejszej moliwej liczby kolorw zalicza si do ogromnej klasy tzw. problemw NP-zupenych, dla ktrych jedynymi znanymi rozwizaniami s rozwizania typu sprawd
wszystkie moliwoci. W przeoeniu na kolorowanie grafu oznacza to sukcesywne prby wykorzystania jednego koloru, potem dwch, trzech itd. tak dugo, a w kocu liczba uytych kolorw
okae si wystarczajca (czego stwierdzenie rwnie wymaga sprawdzenia wszystkich moliwoci). Co prawda wykorzystanie specyfiki konkretnego grafu moe ten proces nieco przyspieszy,
jednake w oglnym wypadku nie istnieje alternatywa dla oczywistego sprawdzania wszystkich
moliwoci.
Okazuje si wic, e znalezienie optymalnego pokolorowania grafu jest w oglnym przypadku
procesem bardzo kosztownym i dla duych grafw moe okaza si zupenie nie do przyjcia, niezalenie od tego, jak efektywnie skonstruowany byby program rozwizujcy zagadnienie. Zastosujemy w zwizku z tym trzy moliwe podejcia. Po pierwsze, dla maych grafw duy koszt czasowy nie bdzie zbytni przeszkod i sprawdzenie wszystkich moliwoci bdzie zadaniem
wykonalnym w rozsdnym czasie. Drugie podejcie polega bdzie na wykorzystaniu specjalnych
wasnoci grafu, pozwalajcych na rezygnacj a priori z do duej liczby sprawdze. Trzecie podejcie odwoywa si bdzie natomiast do znanej prawdy, e rozwizanie problemu mona znacznie
przyspieszy, rezygnujc z poszukiwania rozwizania optymalnego i zadowalajc si rozwizaniem dobrym, moliwym do zaakceptowania w konkretnych warunkach i czsto niewiele gorszym
od optymalnego tym bardziej, e wiele rzeczywistych skrzyowa nie jest a tak skomplikowanych, jak pokazane na rysunku 1.1. Takie algorytmy, szybko dostarczajce dobrych, lecz niekoniecznie optymalnych rozwiza, nazywane s algorytmami heurystycznymi.
Jednym z heurystycznych algorytmw kolorowania grafu jest tzw. algorytm zachanny
(ang. greedy). Kolorujemy pierwszym kolorem tyle wierzchokw, ile tylko moemy. Nastpnie
wybieramy kolejny kolor i wykona naley kolejno nastpujce czynnoci:
(1) Wybierz dowolny niepokolorowany jeszcze wierzchoek i przyporzdkuj mu aktualnie uywany kolor.

1.1. OD PROBLEMU DO PROGRAMU

19

(2) Przejrzyj list wszystkich niepokolorowanych jeszcze wierzchokw i dla kadego z nich
sprawd, czy jest poczony krawdzi z jakim wierzchokiem majcym aktualnie uywany
kolor. Jeeli nie jest, opatrz go tym kolorem.
Zachanno algorytmu wynika std, e w kadym kroku (tj. przy kadym z uywanych
kolorw) stara si on pokolorowa jak najwiksz liczb wierzchokw, niezalenie od ewentualnych
negatywnych konsekwencji tego faktu. Nietrudno wskaza przypadek, w ktrym mniejsza zachanno prowadzi do zastosowania mniejszej liczby kolorw. Graf przedstawiony na rysunku 1.3 mona
pokolorowa przy uyciu tylko dwch kolorw; jednego dla wierzchokw 1, 3 i 4, drugiego dla
pozostaych. Algorytm zachanny, analizujcy wierzchoki w kolejnoci wzrastajcej numeracji,
rozpoczby natomiast od przypisania pierwszego koloru wierzchokom 1 i 2, po czym wierzchoki
3 i 4 otrzymayby drugi kolor, a dla wierzchoka 5 konieczne byoby uycie trzeciego koloru.

RYSUNEK 1.3.
Przykadowy graf,
dla ktrego nie popaca
zachanno algorytmu
kolorowania

Zastosujmy teraz zachanne kolorowanie do grafu z rysunku 1.2. Rozpoczynamy od wierzchoka AB, nadajc mu pierwszy z kolorw niebieski; kolorem tym moemy take opatrzy1
wierzchoki AC, AD i BA, poniewa s one osamotnione. Nie moemy nada koloru niebieskiego
wierzchokowi BC, gdy jest on poczony z (niebieskim) wierzchokiem AB; z podobnych wzgldw nie moemy take pokolorowa na niebiesko wierzchokw BD, DA i DB, moemy to jednak
zrobi z wierzchokiem DC. Wierzchokom EA, EB i EC nie mona przyporzdkowa koloru niebieskiego w przeciwiestwie do osamotnionego wierzchoka ED.
Wemy kolejny kolor czerwony. Przyporzdkowujemy go wierzchokom BC i BD; wierzchoek DA czy si krawdzi z BD, wic nie moe mie koloru czerwonego, podobnie jak wierzchoek DB czcy si z BC. Spord niepokolorowanych jeszcze wierzchokw tylko EA mona
nada kolor czerwony.
Pozostay cztery niepokolorowane wierzchoki: DA, DB, EB i EC. Jeeli przypiszemy DA
kolor zielony, moemy go take przyporzdkowa DB, jednake dla EB i EC musimy wtedy uy
kolejnego (tego) koloru. Ostateczny wynik kolorowania przedstawiamy w tabeli 1.2. Dla kadego koloru w kolumnie Ekstra prezentujemy te wierzchoki, ktre nie s poczone z adnym
wierzchokiem w tym kolorze i przy innej kolejnoci przechodzenia zachannego algorytmu przez
wierzchoki mogyby ten wanie kolor uzyska.
Zgodnie z wczeniejszymi zaoeniami, wszystkie wierzchoki w danym kolorze (kolumna
Wierzchoki) odpowiadaj zakrtom uruchamianym w danej fazie. Oprcz nich mona take uruchomi inne zakrty, ktre z nimi nie koliduj (mimo e reprezentujce je wierzchoki maj inny
kolor), s one wyszczeglnione w kolumnie Ekstra.
Tak wic wedle otrzymanego rozwizania, sygnalizacja sterujca ruchem na skrzyowaniu
pokazanym na rysunku 1.1 powinna by sygnalizacj czterofazow. Po dowiadczeniach z grafem
przedstawionym na rysunku 1.3 nie mona nie zastanawia si, czy jest rozwizanie optymalne,
tzn. czy nie byoby moliwe rozwizanie problemu przy uyciu sygnalizacji trj- czy dwufazowej.
1

Zgodnie z kolejnoci przyjt w tabeli na rysunku 1.3 przyp. tum.

20

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

TABELA 1.2.
Jeden ze sposobw pokolorowania grafu z rysunku 1.2
za pomoc zachannego algorytmu
Kolor

Wierzchoki

Ekstra

niebieski
czerwony
zielony
ty

AB, AC, AD, BA, DC, ED


BC, BD, EA
DA, DB
EB, EC

BA, DC, ED
AD, BA, DC, ED
BA, DC, EA, ED

Rozstrzygniemy t wtpliwo za pomoc elementarnych wiadomoci z teorii grafw. Nazwijmy


k-klik zbir k wierzchokw, w ktrych kade dwa poczone s krawdziami. Jest oczywiste, e
nie da si pokolorowa k-kliki przy uyciu mniej ni k kolorw. Gdy spojrzymy uwanie na rysunek 1.2 spostrzeemy, e wierzchoki AC, DA, BD i EB tworz 4-klik, wykluczone jest zatem pokolorowanie grafu wykorzystujc mniej ni 4 kolory, zatem nasze rozwizanie jest optymalne pod
wzgldem liczby faz.

Pseudojzyki i stopniowe precyzowanie


Gdy tylko znajdziemy odpowiedni model matematyczny dla rozwizywanego problemu, moemy
przystpi do formuowania algorytmu w kategoriach tego modelu. Pocztkowa wersja takiego algorytmu skada si zazwyczaj z bardzo oglnych instrukcji, ktre w kolejnych krokach naley ucili,
czyli zastpi instrukcjami bardziej precyzyjnymi. Przykadowo, sformuowanie wybierz dowolny
niepokolorowany jeszcze wierzchoek jest intuicyjnie zrozumiae dla osoby studiujcej algorytm,
lecz aby z algorytmu tego stworzy program moliwy do wykonania przez komputer, sformuowania takie musz zosta poddane stopniowej formalizacji. Postpowanie takie nazywa si stopniowym
precyzowaniem (ang. stepwise refinement) i prowadzi do uzyskania programu w peni zgodnego ze
skadni konkretnego jzyka programowania.
Przykad 1.2. Poddajmy wic stopniowemu precyzowaniu zachanny algorytm kolorowania grafu,
a dokadniej jego cz zwizan z konkretnym kolorem. Zakadamy wstpnie, e mamy do czynienia z grafem G, ktrego niektre wierzchoki mog by pokolorowane. Ponisza procedura tworzy
zbir wierzchokw newclr, ktrym naley przyporzdkowa odnony kolor. Procedura ta wywoywana jest cyklicznie tak dugo, a wszystkim wzom grafu przyporzdkowane zostan kolory.
Pierwsze, najbardziej oglne sformuowanie wspomnianej procedury moe wyglda tak, jak na
listingu 1.1.
LISTING 1.1.
Pocztkowa wersja procedury greedy

 


  

  !"#"$%&'()%
% *+" ,$'&" (   
-
  
2

Symbol oznacza zbir pusty.

1.1. OD PROBLEMU DO PROGRAMU

21

.-/'$*%")+%' " (  '% !" 0


1- /'$ !* '%"2+*)+'%& !"& +*%&
"!+'(0  
3- '"  " (  '%
4-+ ++ 
 

 -

Na listingu 1.1 widoczne s podstawowe elementy zapisu algorytmu w pseudojzyku. Po


pierwsze, widzimy zapisane tustym drukiem i maymi literami sowa kluczowe, ktre odpowiadaj zastrzeonym sowom jzyka Pascal. Po drugie, sowa pisane w caoci wielkimi literami

i 3 s nazwami abstrakcyjnych typw danych. W procesie stopniowego precyzowania
typy te musz zosta zdefiniowane w postaci typw danych pascalowych oraz procedur wykonujcych na tych danych okrelone operacje. Abstrakcyjnymi typami danych zajmiemy si szczegowo w dwch nastpnych punktach.
Konstrukcje strukturalne Pascala, jak: if, for i while s uyte w naszym pseudojzyku w oryginalnej postaci, jednake ju np. warunek w instrukcji if (w wierszu {3}) zapisany jest w sposb
zupenie nieformalny, podobnie zreszt jak wyraenie stojce po prawej stronie instrukcji przypisania w wierszu {1}. Nieformalnie zosta take zapisany zbir, po ktrym iteracj przeprowadza
instrukcja for w wierszu {2}.
Nie bdziemy szczegowo opisywa procesu przeksztacania przedstawionej procedury do
poprawnego programu pascalowego, zaprezentujemy jedynie transformacj instrukcji if z wiersza
{3} do bardziej precyzyjnej postaci.
Aby okreli, czy dany wierzchoek  poczony jest krawdzi z ktrym z wierzchokw
nalecych do zbioru
 , rozpatrzymy kady element tego zbioru i bdziemy sprawdza, czy
w grafie istnieje krawd czca wierzchoki  oraz . Wynik sprawdzenia zapisywa bdziemy
w zmiennej boolowskiej 
 jeli rzeczona krawd istnieje, zmiennej tej nadana zostanie
warto $.
Zmieniona wersja procedury przedstawiona zostaa na listingu 1.2.
LISTING 1.2.
Rezultat czciowego sprecyzowania procedury greedy

 


  
'( !"#"$%&'()%
% *+" ,$'&" (   
-
 
.-/'$*%")+%' " ( '% !" 0
  
15-
6(
15.-/'$*7 ")+% !" 
 0
151- /$'76"2+8!** !" 0
153-
$
154- 
6(  
'!*%2)+'%& !"& 
 3- '"  " (  '%
4-+ ++ 
 
3

Odrniamy tu abstrakcyjny typ danych  od typu zbiorowego  jzyka Pascal.

22

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

3-

 -

Zredukowalimy tym samym nasz algorytm do zbioru operacji wykonywanych na dwch


zbiorach wierzchokw. Ptla zewntrzna (wiersze od {2} do {5}) stanowi iteracj po niepokolorowanych wierzchokach grafu ; ptla wewntrzna (wiersze od {3.2} do {3.4}) iteruje natomiast
po wierzchokach znajdujcych si aktualnie w zbiorze
 . Instrukcja w wierszu {5} dodaje
nowy wierzchoek do zbioru
 .
Jzyk Pascal oferuje wiele moliwoci reprezentowania zbiorw danych niektrymi z nich
zajmiemy si dokadniej w rozdziaach 4. i 5. Na potrzeby reprezentowania zbioru wierzchokw
w naszym przykadzie wykorzystamy inny abstrakcyjny typ danych, 9: , ktry moe by zaimplementowany jako lista liczb cakowitych ('$7), zakoczona specjaln wartoci
 (ktra
moe by reprezentowana przez warto ;). Lista ta moe mie posta tablicy, lecz jak zobaczymy w rozdziale 2. istnieje wiele innych sposobw jej reprezentowania.
Zastpmy instrukcj for w wierszu 3.2 na listingu 1.2 przez ptl, w ktrej zmienna reprezentuje kolejne wierzchoki zbioru
  (w kolejnych obrotach ptli). Identycznemu zabiegowi
poddamy ptl rozpoczynajc si w wierszu {2}. W rezultacie otrzymamy now, bardziej precyzyjn wersj procedury, ktra zaprezentowana jest na listingu 1.3.
LISTING 1.3.
Kolejny etap sprecyzowania procedury ITGGF[

 


 9: 

  !"#"$%&'()%
% *+" ,$'&" ( 


 ('
# '$7
  

 ;
/%' " (  '% !"76 0
 /0
   

6(
 /% !" 
 0
  /0
   
 /$'76 "2+8!** !" 0

$
 /'$2'% !" 
 0

 
6(  
 '"  " (  '%
+ ++ 
 

/'$2'%' " (  '% !"76 0

 -

Procedurze pokazanej na listingu 1.3 sporo jeszcze brakuje do tego, by zostaa zaakceptowana przez kompilator Pascala. Poprzestaniemy jednak na tym etapie jej precyzowania, gdy chodzi
nam raczej o prezentacj okrelonego sposobu postpowania ni ostateczny wynik.

1.2. ABSTRAKCYJNE TYPY DANYCH

23

Podsumowanie
Na rysunku 1.4 przedstawiamy schemat procesu tworzenia programu, zgodnie z ujciem w niniejszej ksice. Proces ten rozpoczyna si etapem modelowania, na ktrym wybrany zostaje odpowiedni model matematyczny dla danego problemu (np. graf). Na tym etapie opis algorytmu ma
zazwyczaj posta wybitnie nieformaln.

RYSUNEK 1.4.
Proces rozwizywania
problemu za pomoc
komputera

Kolejnym krokiem jest zapisanie algorytmu w pseudojzyku stanowicym mieszank instrukcji


pascalowych i nieformalnych opisw wyraonych w jzyku naturalnym. Realizacja tego etapu polega
na stopniowym precyzowaniu oglnych, nieformalnych opisw do bardziej szczegowej postaci.
Niektre fragmenty zapisu algorytmu mog mie ju wystarczajco szczegow posta do tego,
by mona byo wyrazi je w kategoriach konkretnych operacji wykonywanych na konkretnych danych,
w zwizku z czym nie musz by ju bardziej precyzowane. Po odpowiednim sprecyzowaniu instrukcji algorytmu, definiujemy abstrakcyjne typy danych dla wszystkich struktur uywanych przez
algorytm (z wyjtkiem by moe struktur skrajnie elementarnych, jak: liczby cakowite, liczby rzeczywiste czy acuchy znakw). Z kadym abstrakcyjnym typem danych wiemy zestaw odpowiednio
nazwanych procedur, z ktrych kada wykonuje konkretn operacj na danych tego typu. Kada
nieformalnie zapisana operacja zostaje nastpnie zastpiona wywoaniem odpowiedniej procedury.
W trzecim kroku wybieramy odpowiedni implementacj dla kadego typu danych, w szczeglnoci dla zwizanych z tym typem procedur wykonujcych konkretne operacje. Zastpujemy take
istniejce jeszcze nieformalne zapisy prawdziwymi instrukcjami jzyka Pascal. W efekcie otrzymujemy program, ktry mona skompilowa i uruchomi. Po cyklu testowania i usuwania bdw
(mamy nadziej krtkiego) otrzymamy poprawny program dostarczajcy upragnione rozwizanie.

1.2. Abstrakcyjne typy danych


Wikszo omawianych dotychczas zagadnie powinna by znana nawet pocztkujcym programistom. Jedynym istotnym novum mog by abstrakcyjne typy danych, celowe wic bdzie uwiadomienie sobie ich roli w szeroko rozumianym procesie projektowania programw. W tym celu
posuymy si analogi dokonamy mianowicie wyszczeglnienia wsplnych cech abstrakcyjnych
typw danych i procedur pascalowych.
Procedury, jako podstawowe narzdzie kadego jzyka algorytmicznego, stanowi tak naprawd
uoglnienie operatorw. Uwalniaj one od kopotliwego ograniczenia do podstawowych operacji
(w rodzaju dodawania czy mnoenia liczb), pozwalajc na dokonywanie operacji bardziej zaawansowanych, jak np. mnoenie macierzy.
Inn uyteczn cech procedur jest enkapsulacja niektrych fragmentw kodu. Okrelony fragment programu, zwizany cile z pewnym aspektem funkcjonalnym programu, zamykany jest
w ramach cile zlokalizowanej sekcji. Jako przykad posuy procedura dokonujca wczytywania
i weryfikacji danych. Jeeli w pewnym momencie okae si, e program powinien (powiedzmy)

24

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

oprcz liczb dziesitnych honorowa take liczby w postaci szesnastkowej, niezbdne zmiany
trzeba bdzie wprowadzi jedynie w cile okrelonym fragmencie kodu, bez ingerowania w inne
fragmenty programu.

Definiowanie abstrakcyjnych typw danych


Abstrakcyjne typy danych, czsto dla prostoty oznaczane skrtem ADT (ang. Abstract Data Types),
mog by traktowane jak model matematyczny, z ktrym zwizano okrelon kolekcj operacji.
Przykadem prostego ADT moe by zbir liczb cakowitych, w stosunku do ktrego okrelono
operacje sumy, iloczynu i rnicy (w rozumieniu teorii mnogoci). Argumentami operacji zwizanych z okrelonym ADT mog by take dane innych typw, dotyczy to take wyniku operacji.
Przykadowo, wrd operacji zwizanych z ADT reprezentujcym zbir liczb cakowitych znajdowa si mog procedury badajce przynaleno okrelonego elementu do zbioru, zwracajce
liczb elementw czy te tworzce nowy zbir zoony z podanych parametrw. Tak czy inaczej,
macierzysty ADT wystpi musi jednak co najmniej raz jako argument ktrej ze swych procedur.
Dwie wspomniane wczeniej cechy procedur uoglnienie i enkapsulacja stosuj si jako
ywo do abstrakcyjnych typw danych. Tak jak procedury stanowi uoglnienie elementarnych
operatorw (, <, =, > itd.), tak abstrakcyjne typy danych s uoglnieniem elementarnych typw danych
('$7, (,  (' itd.). Odpowiednikiem enkapsulacji kodu przez procedury jest natomiast enkapsulacja typu danych w tym sensie, e definicja struktury konkretnego ADT wraz z towarzyszcymi tej strukturze operacjami zamknita zostaje w cile zlokalizowanym fragmencie programu.
Kada zmiana postaci czy zachowania ADT uskuteczniana jest wycznie w jego definicji, natomiast
przez pozostae fragmenty w ADT traktowany jest to wane jako elementarny typ danych.
Pewnym odstpstwem od tej reguy jest sytuacja, w ktrej dwa rne ADT s ze sob powizane,
czyli procedury jednego ADT uzalenione s od pewnych szczegw drugiego. Enkapsulacja nie
jest wwczas cakowita i niektrych zmian dokona trzeba na og w definicjach obydwu ADT.
By dokadniej zrozumie podstawowe idee tkwice u podstaw koncepcji abstrakcyjnych typw
danych, przyjrzyjmy si dokadniej typowi 9:  wykorzystywanemu w procedurze  na listingu
1.3. Reprezentuje on list liczb cakowitych ('$7) o nazwie
 , a podstawowe operacje
wykonywane w kontekcie tej listy s nastpujce:
(1)
(2)
(3)
(4)

Usu wszystkie elementy z listy.


Udostpnij pierwszy element listy lub warto
 , jeeli lista jest pusta.
Udostpnij kolejny element listy lub warto
 , jeeli wyczerpano zbir elementw.
Wstaw do listy nowy element (liczb cakowit).
Istnieje wiele struktur danych, ktre mogyby posuy do efektywnej implementacji typu

9:  zajmiemy si nimi dokadniej w rozdziale 2. Gdybymy w zapisie algorytmu na listingu 1.3,

uywajcym powyszych opisw, zastpili je wywoaniami procedur:


(1)
(2)
(3)
(4)

? @AB99
 ;
C: 
 ;
AD
 ;
:A #
 );

od razu widoczna staaby si podstawowa zaleta abstrakcyjnych typw danych. Ot program korzystajcy z ADT ogranicza si tylko do wywoywania zwizanych z nim procedur ich implementacja jest dla niego obojtna. Dokonujc zmian w tej implementacji nie musimy ingerowa
w wywoania procedur.

1.3. TYPY DANYCH, STRUKTURY DANYCH I ADT

25

Drugim abstrakcyjnym typem danych, uywanym przez procedur , jest 


reprezentujcy graf, z nastpujcymi operacjami podstawowymi:
(1)
(2)
(3)
(4)

Udostpnij pierwszy niepokolorowany wierzchoek.


Sprawd, czy dwa podane wierzchoki poczone s krawdzi.
Przyporzdkuj kolor wierzchokowi.
Udostpnij kolejny niepokolorowany wierzchoek.

Wymienione cztery operacje s co prawda wystarczajce w procedurze , lecz oczywicie zestaw
podstawowych operacji na grafie powinien by nieco bogatszy i powinien obejmowa na przykad:
dodanie krawdzi midzy podanymi wierzchokami, usunicie konkretnej krawdzi, usunicie kolorowania z wszystkich wierzchokw itp. Istnieje wiele struktur danych zdolnych do reprezentowania
grafu w tej postaci przedstawimy je dokadniej w rozdziaach 6. i 7.
Naley wyranie zaznaczy, e nie istnieje ograniczenie liczby operacji podstawowych zwizanych z danym modelem matematycznym. Kady zbir tych operacji definiuje odrbny ADT.
Przykadowo, zestaw operacji podstawowych dla abstrakcyjnego typu danych  mgby by nastpujcy:
(1) ? @AB99 procedura usuwajca wszystkie elementy ze zbioru A,
(2) BA:EA## procedura przypisujca zbiorowi C sum zbiorw A i B,
(3) :F funkcja zwracajca liczb elementw w zbiorze A.
Implementacja abstrakcyjnego typu danych polega na zdefiniowaniu jego odpowiednika (jako
typu) w kategoriach konkretnego jzyka programowania oraz zapisaniu (rwnie w tym jzyku) procedur implementujcych jego podstawowe operacje. Typ w jzyku programowania stanowi zazwyczaj kombinacj typw elementarnych tego jzyka oraz obecnych w tym jzyku mechanizmw
agregujcych. Najwaniejszymi mechanizmami agregujcymi jzyka Pascal s tablice i rekordy.
Na przykad abstrakcyjny zbir  zawierajcy liczby cakowite moe by zaimplementowany
jako tablica liczb cakowitych.
Naley take podkreli jeden istotny fakt. Abstrakcyjny typ danych jest kombinacj modelu
matematycznego i zbioru operacji, jakie mona na tym modelu wykonywa, dlatego dwa identyczne modele, poczone z rnymi zbiorami operacji, okrelaj rne ADT. Wikszo materiau
zawartego w niniejszej ksice powicona jest badaniu podstawowych modeli matematycznych, jak
zbiory i grafy, i znajdowaniu najodpowiedniejszych (w konkretnych sytuacjach) zestaww operacji
dla tych modeli.
Byoby wspaniale, gdybymy mogli tworzy programy w jzykach, ktrych elementarne typy
danych i operacje s jak najblisze uywanym przez nas modelom i operacjom abstrakcyjnych typw
danych. Jzyk Pascal (pod wieloma wzgldami) nie jest najlepiej przystosowany do odzwierciedlania najczciej uywanych ADT, w dodatku nieliczne jzyki, w ktrych abstrakcyjne typy danych
deklarowa mona bezporednio, nie s powszechnie znane (o niektrych z nich wspominamy w notce
bibliograficznej).

1.3. Typy danych, struktury danych i ADT


Mimo e okrelenia typ danych (lub po prostu typ), struktura danych i abstrakcyjny typ danych
brzmi podobnie, ich znaczenie jest cakowicie odmienne. W terminologii jzyka programowania
typem danych nazywamy zbir wartoci, jakie przyjmowa mog zmienne tego typu. Na przykad
zmienna typu  (' przyjmowa moe tylko dwie wartoci: $ i 6(. Poszczeglne jzyki

26

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

programowania rni si od siebie zestawem elementarnych typw danych; elementarnymi typami


danych jzyka Pascal s: liczby cakowite ('$7), liczby rzeczywiste ((), wartoci boolowskie ( (') i znaki (). Take mechanizmy agregacyjne, za pomoc ktrych tworzy si typy
zoone z typw elementarnych, rne s w rnych jzykach niebawem zajmiemy si mechanizmami agregacyjnymi Pascala.
Abstrakcyjnym typem danych (ADT) jest model, z ktrym skojarzono zestaw operacji podstawowych. Jak ju wspominalimy, moemy formuowa algorytmy w kategoriach ADT, chcc jednak
zaimplementowa dany algorytm w konkretnym jzyku programowania, musimy znale sposb
reprezentowania tych ADT w kategoriach typw danych i operatorw waciwych temu jzykowi.
Do reprezentowania modeli matematycznych skadajcych si na poszczeglne ADT su struktury danych, ktre stanowi kolekcje zmiennych (by moe rnych typw) poczonych ze sob
na rne sposoby.
Podstawowymi blokami tworzcymi struktury danych s komrki (ang. cells). Komrk mona
obrazowo opisa jako skrzynk, w ktrej mona przechowywa pojedyncz warto nalec do
danego typu (elementarnego lub zoonego). Struktury danych tworzy si przez nadanie nazwy agregatom takich komrek i (opcjonalnie) przez zinterpretowanie zawartoci niektrych komrek jako
poczenia (czyli wskanika) midzy komrkami.
Najprostszym mechanizmem agregujcym, obecnym w Pascalu i wikszoci innych jzykw
programowania, jest (jednowymiarowa) tablica (ang. array) stanowica sekwencj komrek zawierajcych wartoci okrelonego typu, zwanego czsto typem bazowym. Pod wzgldem matematycznym
mona postrzega tablic jako odwzorowanie zbioru indeksw (ktrymi mog by liczby cakowite)
w typ bazowy. Konkretna komrka w ramach konkretnej tablicy moe by identyfikowana w postaci
nazwy, ktrej towarzyszy konkretna warto indeksu. W jzyku Pascal indeksami mog by m.in.
liczby cakowite z okrelonego przedziau (noszcego nazw typu okrojonego) oraz wartoci typu
wyliczeniowego, jak np. typ (czarny, niebieski, czerwony, zielony). Typ bazowy tablicy moe by
w zasadzie dowolnym typem, tak wic deklaracja:



G'+H$%I(($%

okrela tablic o nazwie


, zoon z elementw typu bazowego (($%, indeksowanych wartociami typu '+H$%.
Jzyk Pascal jest skdind niezwykle bogaty pod wzgldem moliwoci wyboru typu indeksowego. Niektre inne jzyki, jak Fortran, dopuszczaj w tej roli jedynie liczby cakowite (z okrelonego przedziau). Chcc w takiej sytuacji uy np. znakw w roli typu indeksowego, musielibymy uciec si do jakiego ich odwzorowania w liczby cakowite, np. bazujc na ich kodach ASCII.
Innym powszechnie uywanym mechanizmem agregujcym s rekordy. Rekord jest komrk
skadajc si z innych komrek zwanych polami, majcych na og rne typy. Rekordy czsto czone
s w tablice typ rekordowy staje si wwczas typem bazowym tablicy. Deklaracja pascalowa:


 

G553I
(

'$7


okrela czteroelementow tablic, ktrej komrka jest rekordem zawierajcym dwa pola:  i
.
Trzecim mechanizmem agregujcym, dostpnym w Pascalu i niektrych innych jzykach, s
pliki. Plik, podobnie jak jednowymiarowa tablica, stanowi sekwencj elementw okrelonego typu.
W przeciwiestwie jednak do tablicy, plik nie podlega indeksowaniu; elementy dostpne s tylko
w takiej kolejnoci w jakiej fizycznie wystpuj w pliku. Poszczeglne elementy tablicy (i poszczeglne

1.3. TYPY DANYCH, STRUKTURY DANYCH I ADT

27

pola rekordu) s natomiast dostpne w sposb bezporedni, czyli szybciej ni w pliku. Plik odrnia jednak od tablicy istotna zaleta jego wielko (liczba zawartych w nim elementw) moe
zmienia si w czasie i jest potencjalnie nieograniczona.

Wskaniki i kursory
Oprcz mechanizmw agregujcych istniej jeszcze inne sposoby ustanawiania relacji midzy komrkami su do tego wskaniki i kursory. Wskanik jest komrk, ktrej zawarto jednoznacznie
identyfikuje inn komrk. Fakt, e komrka A jest wskanikiem komrki B, zaznaczamy na schemacie struktury danych rysujc strzak od A do B.
W jzyku Pascal to, e zmienna  moe wskazywa komrk o typie (($%, zaznaczamy
w nastpujcy sposb:


(($%

Strzaka poprzedzajca nazw typu bazowego oznacza typ wskanikowy (czyli zbir wartoci stanowicych wskazania na komrk o typie (($%). Odwoanie do komrki wskazywanej przez
zmienn  (zwane take dereferencj wskanika) ma posta  strzaka wystpuje za nazw zmiennej.
Kursor tym rni si od wskanika, e identyfikuje komrk w ramach konkretnej tablicy
wartoci kursora jest indeks odnonego elementu. W samym zamyle nie rni si on od wskanika jego zadaniem jest take identyfikowanie komrki jednak, w przeciwiestwie do niego,
nie mona za pomoc kursora identyfikowa komrek samodzielnych, ktre nie wchodz w skad
tablicy. W niektrych jzykach, jak np. Fortran i Algol, wskaniki po prostu nie istniej i jedyn
metod identyfikowania komrek s wanie kursory. Naley take zauway, e w Pascalu nie jest
moliwe utworzenie wskanika do konkretnej komrki tablicy, wic jedynie kursory umoliwiaj
identyfikowanie poszczeglnych komrek. Niektre jzyki, jak PL/I i C, s pod tym wzgldem
bardziej elastyczne i dopuszczaj wskazywanie elementw tablic przez prawdziwe wskaniki.
Na schemacie struktury danych kursory zaznaczane s podobnie jak wskaniki, czyli za pomoc strzaek, a dodatkowo w komrk bdc kursorem moe by wpisana jej zawarto4 dla zaznaczenia, i nie mamy do czynienia z typowym wskanikiem.
Przykad 1.3. Na rysunku 1.5 pokazano struktur danych skadajc si z dwch czci: tablicy
  (zdefiniowanej wczeniej w tym rozdziale) i kursorw do elementw tej tablicy; kursory
te poczone s w list acuchow. Elementy tablicy   s rekordami. Pole
 kadego z tych

rekordw jest kursorem do nastpnego rekordu i zgodnie z t konwencj, na rysunku 1.5 rekordy
tablicy uporzdkowane s w kolejnoci 4, 1, 3, 2. Zwr uwag, e pole
 rekordu 2 zawiera
warto 0, oznaczajc kursor pusty, czyli nie identyfikujcy adnej komrki, konwencja taka ma
sens jedynie wtedy, gdy komrki tablicy indeksowane s poczwszy od 1, nie od zera.

4
Wynika to z jeszcze jednej, fundamentalnej rnicy midzy wskanikiem a kursorem. Ot implementacja wskanikw w Pascalu (i wszystkich niemal jzykach, w ktrych wskaniki s obecne) bazuje na adresie
komrki w przestrzeni adresowej procesu. Adres ten (a wic i konkretna warto wskanika) ma sens jedynie
w czasie wykonywania programu nie istnieje wic jakakolwiek warto wskanika, ktr mona by umieci na schemacie. Kursor natomiast jest wielkoci absolutn, pozostajc bez zwizku z konkretnymi adresami komrek przyp. tum.

28

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

RYSUNEK 1.5.
Przykadowa
struktura danych

Kada komrka acucha (w grnej czci rysunku) jest rekordem o nastpujcej definicji:

 +$%
 '$7
 +$%


Pole  tego rekordu jest kursorem do jakiego elementu tablicy  , pole  zawiera
natomiast wskanik do nastpnej komrki w acuchu. Wszystkie rekordy acucha s rekordami
anonimowymi, nie maj nazw, gdy kady z nich utworzony zosta dynamicznie, w wyniku wywoania funkcji
 . Pierwszy rekord acucha wskazywany jest natomiast przez zmienn :


 +$%

Pole  pierwszego rekordu w acuchu zawiera kursor do czwartego elementu tablicy  ,
pole  jest natomiast wskanikiem do drugiego rekordu. W drugim rekordzie pole data ma warto 2, co oznacza kursor do drugiego elementu tablicy  ; pole  jest natomiast pustym
wskanikiem oznaczajcym po prostu brak wskazania na cokolwiek. W jzyku Pascal puste
wskazanie oznaczane jest sowem kluczowym nil.

1.4. Czas wykonywania programu


Programista przystpujcy do rozwizywania jakiego problemu staje czsto przed wyborem jednego spord wielu moliwych algorytmw. Jakimi kryteriami powinien si wwczas kierowa?
Ot istniej pod tym wzgldem dwa, sprzeczne ze sob, kryteria oceny:
(1) Najlepszy algorytm jest atwy do zrozumienia, kodowania i weryfikacji.
(2) Najlepszy algorytm prowadzi do efektywnego wykorzystania zasobw komputera i jest jednoczenie tak szybki, jak to tylko moliwe.

1.4. CZAS WYKONYWANIA PROGRAMU

29

Jeeli tworzony program ma by uruchamiany tylko od czasu do czasu, wice bdzie z pewnoci pierwsze kryterium. Koszty zwizane z wytworzeniem programu s wwczas znacznie wysze
od kosztw wynikajcych z jego uruchamiania, naley wic dy do jak najefektywniejszego
wykorzystania czasu programistw, bez szczeglnej troski o obcienie zasobw systemu. Jeeli
jednak program ma by uruchamiany czsto, koszty zwizane z jego wykonywaniem szybko si
zwielokrotni. Wwczas gr bior wzgldy natury efektywnociowej, gdzie liczy si szybki algorytm, bez wzgldu na jego stopie komplikacji. Warto niekiedy wyprbowa kilka rnych algorytmw i wybra najbardziej opacalny w konkretnych warunkach. W przypadku duych zoonych systemw moe okaza si take celowe przeprowadzanie pewnych symulacji badajcych
zachowania konkretnych algorytmw. Wynika std, e programici powinni nie tylko wykaza si
umiejtnoci optymalizowania programw, lecz take powinni umie okreli, czy w danej sytuacji zabiegi optymalizacyjne s w ogle uzasadnione.

Pomiar czasu wykonywania programu


Czas wykonywania konkretnego programu zaley od szeregu czynnikw, w szczeglnoci:
(1)
(2)
(3)
(4)

danych wejciowych,
jakoci kodu wynikowego generowanego przez kompilator,
architektury i szybkoci komputera, na ktrym program jest wykonywany,
zoonoci czasowej algorytmu uytego do konstrukcji programu.

To, e czas wykonywania programu zalee moe od danych wejciowych, prowadzi do wniosku, i czas ten powinien by moliwy do wyraenia w postaci pewnej funkcji wybranego aspektu
tych danych owym aspektem jest najczciej rozmiar danych. Znakomitym przykadem wpywu
danych wejciowych na czas wykonania programu jest proces sortowania danych w rozmaitych
odmianach, ktrymi zajmiemy si szczegowo w rozdziale 8. Jak wiadomo, dane wejciowe programu sortujcego maj posta listy elementw. Rezultatem wykonania programu jest lista zoona
z tych samych elementw, lecz uporzdkowana wedug okrelonego kryterium. Przykadowo, lista
2, 1, 3, 1, 5, 8 po uporzdkowaniu w kolejnoci rosncej bdzie mie posta 1, 1, 2, 3, 5, 8. Najbardziej intuicyjn miar rozmiaru danych wejciowych jest liczba elementw w licie, czyli dugo listy wejciowej. Kryterium dugoci listy wejciowej jako rozmiaru danych jest adekwatne
w przypadku wielu algorytmw, dlatego w niniejszej ksice bdziemy je stosowa domylnie
poza sytuacjami, w ktrych wyranie bdziemy sygnalizowa odstpstwo od tej zasady.
Przyjo si oznacza przez T(n) czas wykonywania programu, gdy rozmiar danych wejciowych wynosi n. Przykadowo, niektre programy wykonuj si w czasie T(n) = cn2, gdzie c jest
pewn sta. Nie precyzuje si jednostki, w ktrej wyraa si wielko T(n), wygodnie jest przyj,
e jest to liczba instrukcji wykonywanych przez hipotetyczny komputer.
Dla niektrych programw czas wykonania moe jednak zalee od szczeglnej postaci danych,
nie tylko od ich rozmiaru. W takiej sytuacji T(n) oznacza pesymistyczny czas wykonania (tzw. najgorszy przypadek ang. worst case), czyli maksymalny czas wykonania dla (statystycznie) wszystkich moliwych danych o rozmiarze n. Poniewa najgorszy przypadek stanowi sytuacj skrajn,
definiuje si take redni czas wykonania oznaczany przez Tavg(n) i stanowicy wynik (statystycznego)
urednienia czasu wykonania wszystkich moliwych danych rozmiaru n. To, e Tavg(n) stanowi miar
bardziej obiektywn ni czas pesymistyczny, staje si niekiedy rdem bdnego zaoenia, e
wszystkie moliwe postaci danych wejciowych s jednakowo prawdopodobne. W praktyce okrelenie
redniego czasu wykonania bywa znacznie trudniejsze, ni okrelenie czasu pesymistycznego zarwno
ze wzgldu na trudnoci zwizane z matematycznym podejciem do problemu, jak i z powodu

30

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

niezbyt precyzyjnego znaczenia okrelenia redni. Z tego wanie wzgldu przy szacowaniu zoonoci czasowej algorytmw bdziemy raczej bazowa na czasie pesymistycznym, ale bdziemy
uwzgldnia czas redni w sytuacjach, w ktrych da si to uczyni.
Zatrzymajmy si teraz nad punktami 2. i 3. przedstawionej listy, zgodnie z ktrymi czas wykonania programu zaleny jest zarwno od uytego kompilatora, jak i konkretnego komputera. Zaleno
ta uniemoliwia okrelenie czasu wykonania w sposb konwencjonalny, np. w sekundach, moemy
to uczyni jedynie w kategoriach proporcjonalnoci, mwic na przykad, e czas sortowania bbelkowego proporcjonalny jest do n2. Staa bdca wspczynnikiem tej proporcjonalnoci pozostaje
wielk niewiadom, zalen i od kompilatora, i od komputera oraz kilku innych czynnikw.

Notacja duego O i duej omegi


Wygodnym rodkiem wyraania funkcyjnej zoonoci czasowej algorytmu jest tzw. notacja duego O. Mwimy na przykad, e zoono programu T(n) jest rzdu duego O od n-kwadrat
i zapisujemy to w postaci T(n) = O(n2). Formalnie oznacza to, e istniej takie stae dodatnie c i n0,
e dla kadego n n0 zachodzi T(n) cn2.
Przykad 1.4. Zamy, e T(0) = 1, T(1) = 4 i oglnie T(n) = (n+1)2. Widzimy wic, e T(n) = O(n2)
oraz n0 = 1 i c = 4. Istotnie, dla n 1 mamy (n+1)2 4n2, co Czytelnik moe atwo sprawdzi. Zauwa,
e nie mona przyj n0 = 0, gdy T(0) = 1 nie jest mniejsze od c02 = 0 dla adnego c.
Przyjmujemy, e funkcje zoonoci czasowej okrelone s w dziedzinie nieujemnych liczb
cakowitych, a ich wartoci s take nieujemne, chocia niekoniecznie cakowite. Mwimy, e
T(n) = O(f(n)), jeeli istniej takie stae c i n0, e dla kadego n n0 zachodzi T(n) cf(n). O programie, ktrego zoono czasowa jest O(f(n)) mwimy, e ma on tempo wzrostu f(n).
Przykad 1.5. Funkcja T(n) = 3n2+2n2 jest O(n3). Istotnie, zamy n0 = 0 i c = 5. atwo pokaza,
e 3n3+2n2 5n3 dla kadego n 0. Zauwa, e O(n4) byoby dla tej funkcji rwnie oszacowaniem poprawnym, jednak mniej precyzyjnym5.
Udowodnimy, e funkcja 3n nie jest O(2n). Zamy mianowicie, e istniej takie stae n0 i c,
e dla kadego n n0 zachodzi 3n c2n. Musiaoby wwczas zachodzi c (3/2)n dla kadego n n0,
gdy tymczasem wielko (3/2)n ronie nieograniczenie wraz ze wzrostem n, nie istnieje wic staa
ograniczajca j od gry.
Stwierdzenie T(n) jest O(f(n)) albo T(n) = O(f(n)) oznacza, e funkcja f(n) stanowi grne
ograniczenie tempa wzrostu T(n). Na oznaczenie dolnego ograniczenia zoonoci czasowej wprowadzono notacj duej omegi6. Mwimy, e T(n) jest omega od g(n) i zapisujemy to T(n) = (g(n)),
co formalnie oznacza, e istnieje taka staa dodatnia c, e dla nieskoczenie wielu wartoci n zachodzi T(n) cg(n).
5

Kwestia ta zostaa szczegowo wyjaniona na stronach 17 18 ksiki Algorytmy i struktury danych


z przykadami w Delphi, wyd. Helion 2000 przyp. tum.
6
Zwr uwag na asymetri midzy definicjami duego O i duej omegi w pierwszym przypadku
mwi si o wszystkich n n0, w drugim o nieskoczenie wielu. Asymetria ta bywa bardzo czsto uyteczna,
poniewa istniej szybkie algorytmy, ktre jednak dla szczeglnych wartoci danych wejciowych staj si
bardzo powolne. Przykadowo, algorytm sprawdzajcy, czy dugo listy danych wejciowych wyraa si
liczb pierwsz, wykonuje si bardzo szybko, jeeli dugo ta jest liczb parzyst; w tej sytuacji nie moemy
poda dolnego ograniczenia obowizujcego dla wszystkich n n0, moemy jednak ustali takie, ktre obowizuje dla nieskoczenie wielu z nich.

1.4. CZAS WYKONYWANIA PROGRAMU

31

Przykad 1.6. Aby sprawdzi, czy funkcja T(n) = n3+2n2 jest (n3), zamy c = 1; wtedy T(n) cn3
dla n = 0, 1,
Zamy teraz, e T(n) = n dla n nieparzystych i T(n) = n2/100 dla n parzystych. Jeeli przyjmiemy c = 1/100, to dla wszystkich parzystych n (czyli dla nieskoczonej ich iloci) otrzymamy
T(n) = cn2, czyli T(n) cn2, wic T(n) jest (n2).

Tyraniczne tempo wzrostu


Przy porwnywaniu zoonoci czasowej dwch programw ignoruje si zazwyczaj sta proporcjonalnoci; przy tym zaoeniu program o zoonoci O(n2) jest lepszy od rozwizujcego ten sam
problem programu o zoonoci O(n3). Jak wczeniej stwierdzilimy, sta proporcjonalnoci w funkcji
zoonoci czasowej odzwierciedla konsekwencje uycia okrelonego kompilatora i uruchomienia
programu na komputerze o okrelonej szybkoci. Nie jest to jednak do koca prawd, poniewa swj
wkad do owej staej proporcjonalnoci wnosz te same algorytmy. Zamy na przykad, e
dwa rne programy rozwizuj ten sam problem rozmiaru7 n w czasie (odpowiednio) 100n2 i 5n3
milisekund (na tym samym komputerze, przy uyciu tego samego kompilatora). Czy drugi z tych
programw moe by lepszy od pierwszego?
Odpowied na to pytanie zaley od spodziewanego rozmiaru danych, jakie przyjdzie przetwarza
obydwu programom. Nierwno 5n3 < 100n2 speniona jest dla n < 20, zatem dla danych niewielkich
rozmiarw drugi program bdzie zdecydowanie lepszy zwaszcza przy czstym uruchamianiu
mimo wikszego tempa wzrostu. Gdy jednak rozmiar danych zaczyna wzrasta, wykadniki potg
staj si coraz bardziej istotne drugi program jest przecie 5n3/100n2 = n/20 razy wolniejszy, czyli
przewaga pierwszego programu pod wzgldem szybkoci oblicze jest proporcjonalna do rozmiaru
danych. Tumaczy to preferowanie samego tempa wzrostu programu i przywizywanie znacznie
mniejszej wagi do staych proporcjonalnoci.
Innym wanym czynnikiem, ktry przemawia przynajmniej za poszukiwaniem algorytmw
o jak najmniejszym tempie wzrostu, jest okrelenie, z jakiego rozmiaru danymi jest w stanie skutecznie poradzi sobie dany algorytm w danych warunkach, czyli na okrelonym komputerze przy
uyciu okrelonego kompilatora. Nieustanny postp technologiczny i zwikszajce si wci szybkoci
komputerw s rwnie przyczyn powierzania komputerom coraz bardziej zoonych zagadnie.
Jak za chwil zobaczymy, jedynie w przypadku algorytmw o niewielkiej zoonoci w rodzaju O(n)
czy O(n log n) zwikszenie szybkoci komputera ma znaczcy wpyw na wzrost rozmiaru problemu
moliwego do rozwizania (w okrelonym czasie).
Przykad 1.7. Na rysunku 1.6 pokazano graficzne przedstawienie czasu (mierzonego w sekundach)
wykonania programw o rnej zoonoci czasowej (kompilowanych tym samym kompilatorem
i uruchamianych na tym samym komputerze). Przypumy, e mamy do dyspozycji 1000 sekund.
Jak duy rozmiar danych zdolny jest w tym czasie przetworzy kady z programw?
Jak atwo odczyta z przedstawionego wykresu, rozmiar problemw moliwych do rozwizywania przez kady z programw w czasie 1000 sekund jest mniej wicej taki sam. Zamy teraz,
e bez adnych dodatkowych kosztw udao nam si wygospodarowa czas 10 razy wikszy lub,
co na jedno wychodzi, otrzymalimy dziesiciokrotnie szybszy komputer. Jak w tej sytuacji zmieni
si maksymalny rozmiar problemu moliwego do rozwizywania?

7
Okrelenie problem rozmiaru n jest tu wygodnym skrtem okrelajcym dane rozmiaru n przetwarzane przez program rozwizujcy problem przyp. tum.

32

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

RYSUNEK 1.6.
Zoono czasowa
czterech programw

Zestawienie widoczne w tabeli 1.3 nie pozostawia adnych wtpliwoci. Przewaga programu
o zoonoci O(n) jest wyranie widoczna, jego moliwoci wzrastaj dziesiciokrotnie. Pozostae
programy prezentuj si pod tym wzgldem mniej imponujco, poniewa wielko problemw
moliwych do rozwizywania przez nie wzrasta tylko nieznacznie. Szczeglnie program o zoonoci
O(2n) zdatny jest do rozwizywania jedynie problemw o niewielkich rozmiarach.
TABELA 1.3.
Wzrost maksymalnego rozmiaru moliwego do rozwizania problemu
w rezultacie dziesiciokrotnego przyspieszenia komputera
Zoono
czasowa T(n)

Komputer
oryginalny

Komputer
dziesiciokrotnie szybszy

Wzgldny przyrost
rozmiaru problemu

100n
5n2
n3/2
2n

10
14
12
10

100
45
27
13

10,0
3,2
2,3
1,3

Mona w pewnym sensie odwrci t sytuacj, porwnujc czas potrzebny na rozwizanie


(przez kady z programw) problemu o rozmiarze dziesiciokrotnie wikszym (w porwnaniu do
tego, jaki rozwizuj one w czasie 1000 sekund).
Z tabeli 1.4 wynika niezbicie, e najszybsze nawet komputery nie s w stanie pomniejszy
znaczenia efektywnych algorytmw.
TABELA 1.4.
Wzrost czasu wykonania programu odpowiadajcy dziesiciokrotnemu zwikszeniu rozmiaru problemu
Zoono czasowa T(n)

Rozmiar problemu

Czas wykonania
programu (s)

Wzgldny przyrost
czasu wykonania

100n
5n2
n3/2
2n

100
140
120
100

10 000
100 000
1 000 000
1030 ( 31022 lat)

10
100
1000
1029

Dochodzimy tym samym do nieco paradoksalnej konkluzji. Ot w miar, jak komputery


staj si coraz szybsze, jednoczenie pojawiaj si coraz bardziej zoone problemy (a raczej ch
wykorzystania komputerw do ich rozwizania). To, w jakim stopniu wzrost mocy obliczeniowej

1.5. OBLICZANIE CZASU WYKONYWANIA PROGRAMU

33

przekada si na wzrost rozmiaru problemw moliwych do rozwizania, zaley przede wszystkim


od zoonoci czasowej uywanych algorytmw. Nieustajcy postp technologiczny nie tylko wic
nie zwalnia z poszukiwania efektywnych algorytmw, lecz nadaje mu coraz wiksze znaczenie!
nawet jeli wydawaoby si, e powinno by odwrotnie.

Szczypta soli
Mimo fundamentalnego znaczenia zoonoci czasowej, istniej przypadki, gdy nie jest ona jedynym
ani te najwaniejszym kryterium wyboru algorytmu. Oto kilka przykadowych sytuacji, w ktrych
gwn rol odgrywaj inne czynniki.
(1) Jeeli program ma by uyty tylko raz lub kilka razy bd ma by wykorzystywany sporadycznie,
koszty jego wytworzenia i przetestowania znacznie przewysza bd koszt zwizany z jego
uruchamianiem. O wiele waniejsze od efektywnoci algorytmu jest wwczas jego poprawne
zaimplementowanie w prosty sposb.
(2) Tempo wzrostu czasu wykonania programu, wyraone przez notacj duego O algorytmu
staje si czynnikiem krytycznym w przypadku asymptotycznym, czyli wtedy, gdy rozmiar problemu zaczyna zmierza do nieskoczonoci. Dla maych rozmiarw istotne staj si wspczynniki proporcjonalnoci (w funkcji zoonoci czasowej) duy wspczynnik proporcjonalnoci moe zrekompensowa szybko wynikajc z maego wykadnika potgi. Istnieje
wiele algorytmw, np. algorytm Schonhagego-Strassena mnoenia liczb cakowitych [1971],
ktre pod wzgldem zoonoci asymptotycznej s zdecydowanie lepsze od konkurentw, lecz
due wspczynniki proporcjonalnoci dyskwalifikuj je pod wzgldem przydatnoci do rozwizywania problemw pojawiajcych si w praktyce.
(3) Skomplikowane algorytmy nieatwo zrozumie, a tworzone na ich bazie programy s trudne
do konserwacji i rozwijania dla osb, ktre nie s ich autorami. Jeeli szczegy danego algorytmu s powszechnie znane w danym rodowisku programistw, mona bez obaw algorytm ten
wykorzystywa. W przeciwnym razie moe si okaza, e opnienia i straty wynike z niezrozumienia lub, co gorsza, z bdnego zrozumienia algorytmu mog zniweczy wszelkie korzyci
wynikajce z jego efektywnoci.
(4) Znane s sytuacje, w ktrych efektywne czasowo algorytmy wymagaj znacznych iloci pamici. Wica si z tym konieczno wykorzystania pamici zewntrznych (np. do implementacji pamici wirtualnej) moe drastycznie obniy szybko realizacji programu, niezalenie
od efektywnoci samego algorytmu.
(5) W algorytmach numerycznych wzgldy dokadnoci i stabilnoci s zwykle nieporwnywalnie
waniejsze od szybkoci oblicze.

1.5. Obliczanie czasu wykonywania programu


Okrelenie czasu wykonania danego programu, nawet tylko z dokadnoci do staego czynnika,
moe stanowi skomplikowany problem matematyczny. Na szczcie, w wikszoci przypadkw
spotykanych w praktyce wystarczajce okazuje si zastosowanie kilku niezbyt skomplikowanych
regu. Zanim przejdziemy do ich omwienia, zatrzymajmy si na chwil na zagadnieniu pomocniczym dodawaniu i mnoeniu na gruncie notacji duego O.

34

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

Zamy, e T1(n) = O(f(n)) i T2(n) = O(g(n)) s czasami wykonania dwch fragmentw programu, odpowiednio, P1 i P2. czny czas wykonania obydwu fragmentw, kolejno P1 i P2, wynosi
wwczas T1(n)+T2(n) = O(max(f(n), g(n))). Aby przekona si, e jest tak istotnie, zdefiniujmy cztery
stae: c1, c2, n1, i n2 takie, e dla n n1 zachodzi T1(n) c1f(n) i, odpowiednio, dla n n2 zachodzi
T2(n) c2f(n). Niech n0 = max(n1, n2). Jeeli n n0, wtedy T1(n)+T2(n) c1f(n)+c2g(n) (c1+c2)
max(f(n), g(n)), czyli dla kadego n n0 zachodzi T1(n)+T2(n) c0max(f(n), g(n)), gdzie c0 = c1+c2.
Oznacza to (bezporednio na podstawie definicji), e T1(n)+T2(n) = O(max(f(n), g(n))).
Przykad 1.8. Opisan powyej regu sum wykorzysta mona do obliczenia zoonoci czasowej sekwencji fragmentw programu, zawierajcego ptle i rozgazienia. Zamy mianowicie,
e czasy wykonania trzech fragmentw wynosz, odpowiednio, O(n2), O(n3) i O(n log n). czny
czas wykonania dwch pierwszych krokw wyniesie wwczas O(max(n2, n3)) = O(n3), za czny
czas wykonania wszystkich trzech O(max(n3, n log n)) = O(n3).
W oglnym przypadku czas wykonania ustalonej sekwencji krokw rwny jest, z dokadnoci
do staego czynnika, czasowi kroku wykonywanego najduej. Niekiedy zdarza si, e dwa kroki programu (lub wiksza ich liczba) s w stosunku do siebie niewspmierne pod wzgldem czasu wykonania. Czas ten nie jest ani rwny, ani te systematycznie wikszy w przypadku ktrego z krokw.
Dla przykadu rozpatrzmy dwa kroki o czasie wykonania, odpowiednio, f(n) i g(n), gdzie:

n 4 dla n parzystych
f ( n) = 2
n dla n nieparzystych

n 2 dla n parzystych
f ( n) = 3
n dla n nieparzystych

Regu sum naley zastosowa w sposb bezporedni. czny czas wykonania wspomnianych krokw
rwny bdzie O(max(n4, n2)) = O(n4) dla n parzystych oraz O(max(n2, n3) = O(n3) dla n nieparzystych.
Innym poytecznym wnioskiem z reguy sum jest to, e w sytuacji, w ktrej g(n) f(n) dla
wszystkich n n0, O(f(n)+g(n)) jest tym samym, co O(f(n)). Na przykad O(n2+n) oznacza to samo, co O(n2).
W podobny sposb formuuje si regu iloczynw. Jeeli T1(n) = O(f(n)) i T2(n) = O(g(n)), to
T1(n) T2(n) rwne jest O(f(n)g(n)), co dociekliwy Czytelnik zweryfikowa moe samodzielnie w taki
sam sposb, jak zrobilimy to w przypadku reguy sum. W szczeglnoci O(cf(n)) jest tym samym,
co O(f(n)) (c jest tu dowoln sta dodatni).
Przed przystpieniem do omawiania oglnych regu analizy czasu wykonywania programw,
przyjrzyjmy si prostemu przykadowi ilustrujcemu wybrane elementy rzeczywistego procesu.
Przykad 1.9. Na listingu 1.4 widoczna jest procedura bubble sortujca tablic liczb rzeczywistych
w kolejnoci rosncej, metod sortowania bbelkowego (ang. bubblesort). Kade wykonanie ptli
wewntrznej powoduje przesunicie najmniejszych elementw w kierunku pocztku tablicy.
LISTING 1.4.
Procedura sortowania bbelkowego
 


G55
I'$7
  $$(2" (' J '*

##'$7
  
-

.-
 
1- G<I0GI  

35

1.5. OBLICZANIE CZASU WYKONYWANIA PROGRAMU

&K&&G<IGIG<I
3-G<IGI
4-GI
L-
  -

Rozmiar sortowanej tablicy, czyli liczba elementw do posortowania, jest tu niewtpliwie wiarygodn miar rozmiaru problemu. Oczywicie, kada instrukcja przypisania wymaga pewnego staego
czasu, niezalenego od danych wejciowych; kada z instrukcji {4}, {5} i {6} wykonuje si wic
w czasie O(1), czyli O(0) (O(c) = O(0) dla dowolnej staej c). czny czas wykonania tych instrukcji
rwny jest na mocy reguy sum O(max(1, 1, 1)) = O(1) = O(0).
Przyjrzyjmy si teraz instrukcjom ptli i instrukcji warunkowej. Instrukcje te s zagniedone,
musimy wic zacz analiz od najbardziej wewntrznej z nich. Testowanie warunku instrukcji if
wymaga O(1) czasu. Jeeli chodzi o ciao tej instrukcji, czyli instrukcje uwarunkowane {4}, {5} i {6},
nie sposb z gry przewidzie, ile razy zostan wykonane. Zaoymy wic pesymistycznie, e bd
wykonywane zawsze, w czasie O(1). Zatem koszt wykonania caej instrukcji if wynosi O(1).
Przemieszczajc si na zewntrz, natrafiamy na wewntrzn ptl for (wiersze {2} {6}).
Oglnie rzecz ujmujc, czas wykonania ptli for jest sum czasu wykonania poszczeglnych jej
obrotw, przy czym musimy jeszcze doda O(1) czasu w kadym obrocie, potrzebnego na zwikszenie i testowanie zmiennej sterujcej oraz skok do pocztku ptli. Kady obrt wspomnianej ptli
wymaga wic O(1) czasu, liczba obrotw rwna jest natomiast O(ni) (i jest wartoci zmiennej
sterujcej ptli zewntrznej). Daje to czny czas wykonania ptli O((ni)1) = O(ni).
Dochodzimy wreszcie do ptli zewntrznej (wiersze {1} {6}). Wykonuje si ona n1 razy,
tak wic czny czas jej wykonania wynosi O(k), gdzie k rwne jest:
n 1

(n i) = n(n 1) / 2 = n

/2n/2

i =1

Procedura   wykonuje si w czasie O(n2). W rozdziale 8. przedstawimy inne algorytmy sortowania, dziaajce w czasie O(n log n), a zatem efektywniejsze8, gdy log n jest mniejsze od n.
Zanim przejdziemy do omawiania oglnych regu analizowania zoonoci obliczeniowej, przypomnijmy, e precyzyjne okrelenie grnego ograniczenia tej zoonoci, cho czasami bardzo atwe,
to w wielu wypadkach moe stanowi prawdziwe wyzwanie intelektualne.
Nie sposb zreszt poda jakiego kompletnego zbioru regu tego procesu. Ograniczymy si
tylko do wymienienia pewnych wskazwek i koncepcji ilustrowanych stosownymi przykadami.
Czas wykonania okrelonej instrukcji lub grupy instrukcji uzaleniony jest od rozmiaru danych wejciowych i opcjonalnie od wartoci jednej zmiennej lub wielu zmiennych. Natomiast jedynym dopuszczalnym parametrem wpywajcym na czas wykonania caego programu jest rozmiar danych
wejciowych.
(1) Czas wykonania instrukcji przypisania, wczytywania lub wypisywania danych przyjmuje si
jako O(1). Od tej zasady istnieje kilka wyjtkw. Po pierwsze, niektre jzyki, w tym Pascal,
dopuszczaj kopiowanie caych tablic (by moe do duych) za pomoc pojedynczej instrukcji
przypisania. Po drugie, prawa strona instrukcji przypisania zawiera moe wywoanie funkcji,
ktrej czasu wykonania nie mona pomin.
8

Wszystkie uywane w tej ksice logarytmy maj podstaw 2, chyba e wyranie zaznaczona zostaa inna.
Dla notacji duego o podstawa logarytmu i tak nie ma znaczenia, poniewa zmiana podstawy logarytmu
rwnoznaczna jest z pomnoeniem jego wartoci przez stay czynnik: logan = clogbn, gdzie c = logab.

36

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

(2) Czas wykonania sekwencji instrukcji okrelony jest przez regu sum z dokadnoci do staego
czynnika. Jest on rwny czasowi wykonania tej instrukcji, ktra wykonuje si najduej.
(3) Na czas wykonania instrukcji if skada si czas wykonania instrukcji uwarunkowanej i czas
wartociowania wyraenia warunkowego ten ostatni przyjmuje si zwykle jako O(1). Czas
wykonania instrukcji if-then-else oblicza si natomiast jako sum czasu wartociowania wyraenia warunkowego oraz czasu wykonania tej spord sekcji uwarunkowanych, ktra wykonuje si duej.
(4) Czas wykonania ptli jest sum wykonania wszystkich jej obrotw. Na czas wykonania jednego
obrotu skada si czas wykonania ciaa ptli oraz czas czynnoci pomocniczych zwizanych
z obsug zmiennej sterujcej i skokiem do pocztku ptli (zakada si, e owe czynnoci pomocnicze wykonywane s w czasie O(1)). Czsto czas wykonania ptli oblicza si, mnoc
liczb wykonywanych obrotw przez najwikszy moliwy czas wykonania pojedynczego obrotu,
ale czasami nie mona z gry ustali liczby wykonywanych obrotw, zwaszcza w przypadku
ptli nieskoczonej.

Wywoania procedur
Jeeli mamy do czynienia z programem, w ktrym adna z procedur nie jest rekurencyjna9, moemy
rozpocz analizowanie czasu wykonania od tych procedur, ktre nie wywouj adnych innych
procedur (oczywicie, wywoanie funkcji w wyraeniu rwnie uwaane jest tu za wywoanie
procedury), a co najmniej jedna taka procedura musi istnie, skoro wszystkie s nierekurencyjne10.
9

Tzn. nie odwouje si do samej siebie ani bezporednio, ani porednio.


Warunek nierekurencyjnoci procedur jest warunkiem za sabym, by opisane postpowanie mogo si uda,
czego przykadem jest chociaby sekwencja:
10




 




 


 
 




  


 




  


 

Wbrew pozorom nie mamy tutaj do czynienia z rekurencj, lecz nie ma procedury, ktra nie wywoywaaby
adnych innych. Autorzy piszc o rekurencji mieli zapewne na myli take jej pozory, jak powyszy przykad przyp. tum.

1.5. OBLICZANIE CZASU WYKONYWANIA PROGRAMU

37

W kolejnych krokach analizujemy te procedury, ktre odwouj si wycznie do procedur o obliczonej ju zoonoci, i proces ten kontynuujemy a do przeanalizowania wszystkich procedur.
Kiedy niektre (lub wszystkie) procedury programu s rekurencyjne, nie jest moliwe ustawienie ich w opisanym powyej porzdku. Naley zatem uzna zoono czasow T(n) danej procedury za niewiadom funkcj zmiennej n, po czym sformuowa i rozwiza rwnanie rekurencyjne okrelajce t funkcj. Istnieje wiele sposobw analizowania rnego rodzaju zalenoci
rekurencyjnych. Niektrymi z nich zajmiemy si w rozdziale 9., natomiast w tym miejscu zaprezentujemy jedynie obliczanie zoonoci prostego programu rekurencyjnego.
Przykad 1.10. Widoczna na listingu 1.5 funkcja fact dokonuje rekursywnego obliczania funkcji
f(n) = n! (n! to iloczyn kolejnych liczb naturalnych od 1 do n).
LISTING 1.5.
Rekurencyjne obliczanie funkcji silnia
 6$
'$7'$7
 
'$
M  
- 
/
.- 

1- 
= 
<
  -

Miar rozmiaru problemu dla tej funkcji jest oczywicie jej argument oznaczmy zatem
przez T(n) czas wykonywania si tej funkcji dla argumentu
. Instrukcje w wierszach {1} i {2}
wykonuj si oczywicie w czasie O(1), za instrukcja w wierszu {3} w czasie O(1)+T(n1). Dla
pewnych staych c i d mamy wic:

c + T (n 1) dla n > 1
T ( n) =
dla n 1
d

(1.1)

Zakadajc, e n > 2, moemy rozwin wzr (1.1) do postaci:


T(n) = 2c+T(n2) (dla n > 2)
poniewa T(n1) = c+T(n2), o czym mona si przekona, zmieniajc we wzorze (1.1) n na n1.
Korzystajc z kolei z zalenoci:
T(n2) = c+T(n3) (dla n > 3)
moemy napisa:
T(n) = 3c+T(n3) (dla n > 3)
i oglnie:
T(n) = ic+T(ni) (dla n > i)

38

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

Ostatecznie, dla i = n1 otrzymamy:


T(n) = c(n1)+T(1) = c(n1)+d

(1.2)

Zatem, zgodnie ze wzorem (1.2), T(n) = O(n). Zauwa, e dla celw naszej analizy przyjlimy, e mnoenie dwch liczb cakowitych realizuje si w czasie O(1). Zaoenie to moe nie by suszne, jeeli n
bdzie tak due, e bdziemy musieli uywa wielosowowej reprezentacji liczb cakowitych.
Zaprezentowana tutaj oglna metoda rozwizywania rwna rekurencyjnych polega na sukcesywnym zastpowaniu po prawej stronie rwnania wartoci T(k) wartociami T(k1) tak dugo, a
dla jakiego argumentu x warto T(x) wyraona zostanie nierekurencyjnie. Jeeli nie bdzie moliwe
dokadne oszacowanie poszczeglnych wartoci T(k), moemy posuy si ich grnymi ograniczeniami, a otrzymany wynik te bdzie wwczas grnym ograniczeniem na T(n).

Programy z instrukcjami GOTO


Omawiane dotychczas metody analizy zoonoci czasowej przeznaczone s zasadniczo dla programw, ktrych struktura opiera si wycznie na ptlach i rozgazieniach, poniewa za pomoc
reguy sum i reguy iloczynw mona atwo analizowa ich sekwencje i zagniedenia. T wygodn regularno zepsu mog (i zazwyczaj psuj) instrukcje skoku (goto) znacznie utrudniajce
wszelk analiz kodu. Stanowi to argument przemawiajcy za unikaniem instrukcji goto, a przynajmniej za ich umiarkowanym uywaniem. W wielu przypadkach okazuj si one niezbdne, na
przykad wtedy, gdy trzeba przedwczenie zakoczy ptl while, for i repeat. W jzyku Pascal
bowiem, w przeciwiestwie do jzyka C, nie ma instrukcji ! i 

11.
Sugerujemy nastpujce podejcie do analizowania instrukcji goto realizujcych wyskok z ptli
i prowadzcych bezporednio za ptl to bodaj jedyny usprawiedliwiony sposb ich uycia.
Z reguy instrukcja goto w ptli wykonywana jest w sposb warunkowy, dlatego moemy zaoy,
e odnony warunek nigdy nie wystpi i ptla wykona si w sposb kompletny. Jako e skok wywoany przez instrukcj goto prowadzi do instrukcji wystpujcej bezporednio po ptli czyli tej
instrukcji, ktra wykonuje si jako pierwsza po normalnym wykonaniu ptli zaoenie takie
nigdy nie prowadzi do zanienia pesymistycznej zoonoci czasowej. Niebezpieczestwo takie
pojawioby si jednak, gdyby instrukcja goto bya faktycznie zakamuflowan instrukcj ptli. Bywaj
natomiast (rzadkie co prawda) sytuacje, w ktrych takie zachowawcze ignorowanie instrukcji goto
prowadzi do zawyenia zoonoci pesymistycznej.
Nie chcielibymy stwarza wraenia, e instrukcja goto prowadzca wstecz sama z siebie czyni
kod programu niezdatnym do analizy. Tak dugo, jak zaptlenia powodowane przez instrukcje
skoku maj rozsdn struktur to znaczy s zupenie rozczne bd zagniedone w sobie
opisane w tym rozdziale techniki analizy mona z powodzeniem stosowa (chocia osoba dokonujca analizy musi upewni si, czy owe zaptlenia nie kryj w sobie jakich niespodzianek).
Uwaga ta odnosi si szczeglnie do jzykw pozbawionych ptli warunkowych, jak np. Fortran.

11
Uwaga ta dotyczy wzorcowego jzyka Pascal. W 1992 roku ukazaa si wersja 7. Turbo Pascala, zawierajca wspomniane instrukcje. Niezalenie jednak od tego istniej sytuacje, w ktrych wyskok z gboko
zagniedonej ptli za pomoc instrukcji goto jest znacznie zgrabniejszy i czytelniejszy, ni mozolne przedzieranie si przez kilka poziomw wyrae warunkowych. Czytelnikw zainteresowanych problematyk
rozsdnego uywania instrukcji goto w Pascalu zachcam do przeczytania 2. rozdziau ksiki Delphi 7 dla
kadego, wyd. Helion 2003 przyp. tum.

1.6. DOBRE PRAKTYKI PROGRAMOWANIA

39

Analizowanie pseudoprogramw
Techniki stosowane do analizy zoonoci czasowej prawdziwych programw daj si take zastosowa do podobnej analizy w stosunku do pseudoprogramw zawierajcych nieformalne opisy
w jzyku naturalnym oczywicie pod warunkiem, e zna si zoono czasow czynnoci opisywanych przez te nieformalne instrukcje. Kopot polega na tym, e jest ona na og silnie uzaleniona od implementacji, wic w przypadku procedur zaimplementowanych poowicznie lub
niezaimplementowanych w ogle, o ich zoonoci czasowej moemy powiedzie niewiele lub
zgoa nic. Paradoksalnie nieznajomo ta kryje w sobie pewn zalet. Decydujc si mianowicie
na uycie w programie pewnego abstrakcyjnego typu danych, nie determinujemy jeszcze zoonoci
czasowej tego programu ta bowiem zalena bdzie od (dokonanego pniej) wyboru konkretnej
implementacji procedur zwizanych z ADT. Ta wanie moliwo wyboru jest jednym z najwaniejszych argumentw przemawiajcych za uywaniem abstrakcyjnych typw danych.
Skoro czasy wykonania pewnych procedur wywoywanych w programie s jak na razie nieznane, sama zoono czasowa tego programu moe by traktowana jedynie jako funkcja, ktrej
parametrami s owe czasy wykonania, uzalenione z kolei od rozmiarw argumentw przekazywanych wspomnianym procedurom. Znaczenie sowa rozmiar jest zawsze spraw konkretnego
przypadku i interpretacji osoby dokonujcej analizy, chocia wybrany model matematyczny zazwyczaj wskazuje najbardziej trafne podejcie w tym wzgldzie. Jeeli na przykad argument przekazany
do procedury jest zbiorem danych ( ), najbardziej odpowiedni miar jego rozmiaru jest liczba
zawartych w nim elementw. W kolejnych rozdziaach ksiki przedstawimy wiele podobnych przykadw zwizanych z analiz rozmaitych pseudoprogramw.

1.6. Dobre praktyki programowania


Istnieje kilka dobrych i sprawdzonych praktyk, ktrych warto przestrzega przy projektowaniu algorytmw i ich implementowaniu w postaci programw. Niestety, w powszechnym odczuciu s one
traktowane raczej jako banalne, a o ich prawdziwoci mona si dopiero przekona w przypadku
skutecznego rozwizania jakiego rzeczywistego problemu, nie za drog docieka teoretycznych.
Zamieszczamy je tutaj w gbokim przekonaniu, e zasuguj na powane potraktowanie, a Czytelnicy niniejszej ksiki bez trudu odnajd ich odzwierciedlenie w prezentowanych przez nas
programach. Mamy nadziej, e take w swej codziennej praktyce programistycznej poszukiwa
bd okazji do ich zastosowania.
(1) Sporzd projekt programu. Jak wspominalimy na pocztku rozdziau, kady program moe
by pocztkowo zaprojektowany w postaci szkicu, za pomoc nieformalnych opisw wykonywanych czynnoci, by pniej, w wyniku procesu stopniowego precyzowania, doprowadzony
zosta do formalnej postaci zdatnej do wykonania na komputerze (dokadniej, do przetumaczenia
przez kompilator). Strategia od szkicu do szczegw prowadzi zazwyczaj do powstania
programu dobrze zorganizowanego, atwego do zrozumienia, testowania i konserwacji.
(2) Zastosuj enkapsulacj danych i kodu. Abstrakcyjne typy danych i procedury wymuszaj precyzyjne zlokalizowanie (w konkretnych miejscach programu) definicji okrelonych struktur danych
i fragmentw kodu zwizanych z okrelonymi czynnociami. Jeeli konieczne bdzie dokonanie
zmian w programie, atwo bdzie wskaza w kodzie odpowiednie miejsca do modyfikacji.
(3) Wykorzystaj istniejce programy. Jedna z gwnych przyczyn nieefektywnego tworzenia programw wynika std, e tworzenie to czsto przypomina powtrne odkrywanie Ameryki.
Wykorzystanie istniejcych programw i procedur (czsto ju sprawdzonych i przetestowanych)

40

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

jest postpowaniem znacznie efektywniejszym, ni rozpoczynanie wszystkich dziaa od pocztku. Zasada ta dziaa take w drug stron, tworzc jaki program, we pod uwag, e by
moe kto zechce go wykorzysta w przyszoci do swych potrzeb.
(4) Bd kowalem swych narzdzi. W jzyku programistw narzdziami nazywane s programy
przeznaczone do wielokrotnego uytku, w rnych zastosowaniach. Piszc program, zastanw
si, czy nie naleaoby nada mu bardziej oglnej postaci i tym samym skonstruowa narzdzie
przydatne do rnych celw. Przykadowo, tworzc program ukadajcy harmonogram egzaminw, zastanw si, czy nie warto stworzy oglniejszego programu rozwizujcego problem
kolorowania grafu przy uyciu najmniejszej liczby kolorw. Znalezienie optymalnego harmonogramu sesji mogoby by wwczas tylko jednym z jego zastosowa, gdy wierzchoki grafu
reprezentowayby grupy studentw, rne kolory odzwierciedlayby rne terminy egzaminw,
za poczenie krawdzi dwch wierzchokw oznaczaoby, e w grupach reprezentowanych
przez te wierzchoki znajduj si wsplni studenci. Zastosowanie uniwersalnego programu
rozwizujcego problem optymalnego kolorowania grafu wykraczaoby natomiast daleko poza
problem organizacji sesji egzaminacyjnej, czego przykad pokazalimy na pocztku rozdziau, poszukujc optymalnego sposobu sterowania ruchem na skrzyowaniu.
(5) Wykorzystaj polecenia i programy systemu operacyjnego. Polecenia i programy systemw operacyjnych zdolne s wykona wiele poytecznych zada, dziaajc jednak w pojedynk, ograniczaj swe dziaanie do funkcji raczej elementarnych (do ktrych w kocu zostay stworzone).
Dobrze zaprojektowany system operacyjny udostpnia mechanizmy automatyzujce wspprac
poszczeglnych programw w taki sposb, by wyniki produkowane przez jeden z nich staway
si danymi wejciowymi drugiego. Zesp tak poczonych programw nazywamy potokiem, za poszczeglne programy nosz nazw filtrw. Jeeli repertuar polece i programw
danego systemu jest inteligentnie zaprojektowany, mona w nim tworzy potoki o zdumiewajcych moliwociach.
Przykad 1.11. Przykadem ciekawego potoku moe by program  , stworzony pierwotnie
przez S.C. Johnsona wycznie z polece systemu UNIX12. Program ten wczytuje z pliku tekst w jzyku
angielskim i wyprowadza wszystkie wystpujce w nim wyrazy, ktrych brakuje w doczonym
niewielkim sowniku. Program  przejawia co prawda tendencj do produkowania faszywych
alarmw w postaci sygnalizowania poprawnych sw jako sw bdnych13, lecz generowane
przez niego raporty s na tyle krtkie, e przy odrobinie inteligencji atwo zorientowa si, ktre
z wydrukowanych sw s rzeczywicie bdne (tre niniejszej ksiki zostaa zweryfikowana za
pomoc programu spell).
Pierwszym filtrem uytym w potoku (ktrym w kocu jest program  ) jest polecenie

 , ktre, dziki uyciu odpowiednich parametrw, suy do zamiany wielkich liter na ich
mae odpowiedniki oraz do zastpowania tzw. biaych znakw (blanks, czyli spacji i znakw
tabulacji) znakami nowego wiersza. W rezultacie otrzymujemy wykaz sw wystpujcych w tekcie, a wszystkie z nich pisane s wycznie maymi literami i kade znajduje si w osobnym wierszu.
Kolejne polecenie-filtr, , dokonuje posortowania tego wykazu w porzdku alfabetycznym. Kade
ze sw moe wystpowa w tekcie wiele razy, dlatego we wspomnianym wykazie mog si one
powtarza. Aby kade z nich wystpowao w wykazie tylko raz, wywoywane jest polecenie 
"
dokonujce eliminacji duplikatw w posortowanej licie. Tak znormalizowany wykaz jest nastpnie konfrontowany ze sownikiem w celu wychwycenia tych jego pozycji, ktre nie wystpuj
12

UNIX jest znakiem towarowym firmy Bell Laboratories.


Im wikszy sownik, tym mniej faszywych alarmw. Mona by uy kompletnego sownika jzyka
angielskiego, lecz nawet dla maych sownikw wikszo raportowanych przez program wyrazw to rezultaty
bdw ortograficznych lub tzw. literwek, a wyrazy te stwarzaj niekiedy pozory przynalenoci do jzyka
angielskiego, ale tak naprawd nikt o nich nigdy nie sysza.
13

1.7. SUPER PASCAL

41

w sowniku to zadanie wykonuje polecenie , ktrego parametrem jest nazwa wspomnianego
sownika. Oto wic kompletna tre programu-potoku  :
 
 G <FIG<I('"'('


"
+$ '%

Programowanie na poziomie potokw wymaga od programistw dyscypliny, a raczej wsparcia polegajcego na tym, by jak najwicej tworzonych programw mogo w razie potrzeby peni
rol filtrw. W ostatecznym rozrachunku, mierzonym stosunkiem osignitych efektw do woonego wysiku, postpowanie takie na dusz met naprawd si opaca.

1.7. Super Pascal


Wikszo prezentowanych w tej ksice programw zapisanych zostao w jzyku Pascal. Aby
uczyni je bardziej czytelnymi, uylimy trzech konstrukcji, ktre nie wystpuj w standardowym
Pascalu, atwo je jednak mechanicznie przetumaczy na t jego wersj. Pierwsz z tych konstrukcji s nienumeryczne etykiety instrukcja goto jest zdecydowanie bardziej intuicyjna ni
goto4L. Kad z takich instrukcji atwo doprowadzi do standardowej postaci, zastpujc kad nienumeryczn etykiet jej unikalnym numerycznym odpowiednikiem14 zarwno w deklaracji,
jak i w miejscu wystpienia i we wszystkich odwoujcych si do niej instrukcjach goto.
Druga niestandardowa konstrukcja ma posta instrukcji return powodujcej natychmiastowe
zakoczenie bieco wykonywanej procedury lub funkcji. W przypadku funkcji, parametr instrukcji
specyfikuje zwracana warto:
 #


W standardowym Pascalu instrukcja return moe by symulowana za pomoc skoku do etykiety


znajdujcej si bezporednio przed kocow dyrektyw end:
 $

'$7'$7


NNN
  
 
/;
  
$
;
 NNN

 
/1
  
$

 NNN
14
Znakomita wikszo uywanych obecnie implementacji jzyka Pascal w tym popularne Turbo Pascal
i Delphi dopuszcza uywanie etykiet nienumerycznych przyp. tum.

42

1. PROJEKTOWANIE I ANALIZA ALGORYTMW


$
$

<$

<.
NNN


Ponisza posta funkcji jest jednak bardziej zwarta i czytelna15:


 $

'$7'$7
  
 
/;
;
 
/1

$
$

<$

<.
( $

<$

<.

Przykad 1.12. Na listingu 1.6 widoczna jest funkcja   zapisana z uyciem instrukcji return, na listingu 1.7 zawarta zostaa natomiast jej posta dostosowana do wymogw standardowego Pascala.
LISTING 1.6.
Funkcja fact korzystajca z instrukcji return
  
'$7'$7
  
 
/



= 
<
  -

15

W Turbo Pascalu instrukcja returnexpr moe by symulowana przez sekwencj:



 

 

W Delphi mona to osign jeszcze bardziej uniwersalnie:


 

 

przyp. tum.

1.7. SUPER PASCAL

43

LISTING 1.7.
i po transformacji do postaci wymaganej przez standardowy Pascal
  
'$7'$7


NNN
  
 
/
  
 
 NNN


  
 
= 
<
 NNN

NNN
  -

Trzecie z zastosowanych przez nas rozszerze wynika std, e jzyk Pascal w pewnych sytuacjach wymaga uycia identyfikatora typu, nie tolerujc jego definicji in extenso. Na przykad deklaracja:
 

G55;I'$7(($%

musi by zapisana w nastpujcej postaci:



% 6$''$

G55;I'$7
$$ (((($%
 % 6$''$$$ ((

by kompilator uzna j za poprawn. Pierwotna posta, jakkolwiek niepoprawna syntaktycznie


(cho przecie rwnowana poprawnej postaci), jest jednak bardziej zwiza i zrozumiaa intuicyjnie,
dlatego bdziemy j konsekwentnie stosowa w prezentowanych programach, a jej ewentualna transformacja do wspomnianej postaci bdzie dla Czytelnika zadaniem czysto mechanicznym.
Na koniec krtka uwaga na temat zastosowanej przez nas konwencji typograficznej w listingach prezentujcych przykadowe programy. Zarezerwowane sowa jzyka Pascal wypisywane
bd czcionk pogrubion, nazwy typw czcionk prost, za nazwy zmiennych, procedur i funkcji czcionk  %&. Rozrnia bdziemy take wielkie i mae litery16.

16

Rozrnianie midzy wielkociami liter to w rzeczywistoci czwarte z odstpstw od standardowego


Pascala, bowiem adna ze znanych implementacji tego jzyka nie odrnia maych i wielkich liter w zapisie
identyfikatorw i sw kluczowych. Czytelnik dokonujcy konwersji prezentowanych programw na ktr
z rzeczywistych implementacji Pascala musi wic uwaa, by nie utosami ze sob rnych (biorc pod uwag
zastosowan konwencj) identyfikatorw przyp. tum.

44

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

wiczenia
1.1.

Sze druyn: Szakale, Lwy, Ory, Bobry, Tygrysy i Skunksy, przygotowuje si do kolejnych
rozgrywek ligi pikarskiej. Szakale rozegray ju mecze z Lwami i Orami, Lwy take gray
ju z Bobrami i Skunksami, za Tygrysy gray z Orami i Skunksami. Kada druyna rozgrywa tylko jeden mecz w tygodniu. Znajd taki harmonogram rozgrywek, by kada druyna graa z kad i aby zajo to jak najmniej czasu. Wskazwka. Stwrz graf, ktrego
wierzchoki prezentowa bd te pary, ktre jeszcze nie rozegray meczu ze sob. Jeeli
poszczeglne kolory reprezentowa bd kolejne tygodnie rozgrywek, jakie bdzie znaczenie krawdzi w tym grafie?

*1.2. Rozpatrz rami robota zakotwiczone na jednym kocu. Rami to ma dwa przeguby, z ktrych kady pozwala na obrt o 90 w gr lub w d w paszczynie pionowej. Jak mgby
wyglda model matematyczny odzwierciedlajcy moliwe ruchy wolnego koca ramienia? Skonstruuj algorytm jego przesunicia z jednej dozwolonej pozycji do innej.
*1.3. Mamy obliczy iloczyn czterech macierzy liczb rzeczywistych: M1M2M3M4. Macierz
M1 ma rozmiar 1020, M2 2050, M3 501, a M4 1100. Zamy, e pomnoenie
dwch macierzy o wymiarach, odpowiednio, pq i qr wymaga pqr operacji elementarnych
(zgodnie z klasycznym schematem macierzy). Znajd tak kolejno mnoenia wspomnianych macierzy, ktra zminimalizuje cakowit liczb wykonanych operacji elementarnych.
Jak mona uoglni rozwizanie tego zadania na dowoln liczb macierzy?
**1.4. Dane jest 100 liczb rzeczywistych bdcych pierwiastkami kwadratowymi z kolejnych liczb
naturalnych od 1 do 100. Naley posegregowa te liczby na dwie grupy w taki sposb, by
ich sumy w obydwu grupach byy jak najbardziej zblione do siebie. Gdyby dysponowa
dwiema minutami czasu komputera, jakich oblicze dokonaby w tym czasie w celu uatwienia sobie rozwizania tego zadania?
1.5. Zaproponuj zachanny algorytm gry w szachy. Jakich wynikw spodziewaby si w przypadku jego zastosowania?
1.6. W punkcie Abstrakcyjne typy danych rozpatrywalimy abstrakcyjny typ  z operacjami
elementarnymi: ? @AB99, BA:EA i :F. Zamy dla wygody, e ograniczamy si do zbiorw
stanowicych podzbiory zbioru ;##555#1-. Uwzgldniajc to ograniczenie, zaproponuj implementacje (w jzyku Pascal) wspomnianych operacji elementarnych.
1.7. Najwikszym wsplnym dzielnikiem dwch liczb cakowitych p i q nazywamy najwiksz
liczb cakowit d tak, e dzieli ona bez reszty zarwno p, jak i q. Zamierzamy zaimplementowa nastpujcy algorytm obliczania najwikszego wsplnego dzielnika p i q niech
r bdzie reszt z dzielenia p przez q; jeeli r rwne jest zero, to q jest szukanym najwikszym wsplnym dzielnikiem, w przeciwnym razie przypisujemy p:= q, q:= r i powtarzamy dzielenie17.
(a)
Udowodnij, e przedstawiony algorytm faktycznie znajduje najwikszy wsplny
dzielnik dwch liczb.
(b)
Zapisz ten algorytm w pseudojzyku.
(c)
Przekszta nieformalny program stworzony w punkcie (b) w poprawny program
w jzyku Pascal.
17
Algorytm ten wymylony zosta ponad 2300 lat temu przez Euklidesa i dzi jest powszechnie znany pod
jego nazwiskiem przyp. tum.

45

WICZENIA

1.8. Zamierzamy stworzy program formatujcy tekst, wyrwnujcy kady z wierszy do lewej
i prawej krawdzi. Program uywa dwch buforw: dla sw i dla wierszy. Pocztkowo
obydwa bufory s puste. Program wczytuje sowo do bufora sw i sprawdza, czy sowo
to zmieci si jeszcze w biecym wierszu (zapisanym tymczasowo w buforze wiersza).
Jeeli tak, sowo dopisywane jest do bufora wiersza i bufor sowa jest oprniany; jeeli
nie, w buforze wiersza midzy poszczeglne sowa zostaj rwnomiernie wstawione dodatkowe spacje, by wyrwna zawarto wiersza na obydwu krawdziach, po czym bufor
wiersza jest drukowany i oprniany.
(a)
Zapisz algorytm dziaania programu formatujcego w pseudojzyku.
(b)
Przekszta ten zapis w poprawny program w jzyku Pascal.
1.9. Jest n miast i dana jest tabela odlegoci midzy kad ich par. Napisz pseudoprogram,
ktry znajduje krtk ciek rozpoczynajc si i koczc w tym samym miecie, przechodzc przez kade z miast dokadnie jeden raz18. Poniewa jedyn znan metod znajdowania
najkrtszej cieki speniajcej podane warunki jest wyczerpujce poszukiwanie, zaproponuj
jaki algorytm heurystyczny znajdujcy ciek o dugoci moliwej do zaakceptowania.
1.10. Rozpatrzmy nastpujce funkcje zmiennej n:

f 1 ( n) = n 2
f 2 (n) = n 2 + 1000n

n dla n nieparzystych
f 3 ( n) = 3
n dla n parzystych
n dla n 100
f 4 ( n) = 3
n dla n > 100
Znajd wszystkie takie pary (i,j), e fi(n) = O(fj(n)) oraz takie, e fi(n) = (fj(n)).
1.11. Rozpatrzmy nastpujce funkcje zmiennej n:

n 2 dla parzystych n 0
g 1 ( n) = 3
n dla nieparzystych n 1
n dla 0 n 100
g 2 ( n) = 3
n dla n > 100
g 3 ( n) = n 2 , 5
Znajd wszystkie takie pary (i,j), e gi(n) = O(gj(n)) oraz takie, e gi(n) = (gj(n)).
1.12. Wyra w notacji duego O pesymistyczn zoono czasow (w funkcji ) nastpujcych procedur:
18

Zagadnienie to znane jest pod nazw problemu komiwojaera przyp. tum.

46

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

(a)





   
  
 
   

  
  

  
      



(b)

  



   
  
 
 
  
   !"


(c)

 



   
  
 
 
  
 
 
 
 



(*d)

  



  
 # 



 
 



1.13. Udowodnij prawdziwo poniszych rwnoci.


(a)
17 = O(1).
(b)
n(n1)/2 = O(n2).
(c)
max(n3, 10n2) = O(n3).
n

(d)

i
i =1

(e)

= O(n k +1 ) oraz

= (n k +1 ) dla cakowitych k.

i =1

Jeeli p(x) jest dowolnym wielomianem k-tego stopnia z dodatnim wspczynnikiem przy najwyszej potdze, to p(n) = O(nk) oraz p(n) = (nk).

47

WICZENIA

*1.14. Zamy, e T1(n) = (f(n)) oraz T2(n) = (g(n)). Ktre z poniszych stwierdze jest
prawdziwe?
(a)
T1(n)+T2(n) = (max(f(n), g(n))).
(b)
T1(n)T2(n) = (f(n)g(n)).
*1.15. Niektrzy autorzy definiuj wielko duej omegi w nastpujcy sposb: f(n) = (g(n)),
jeeli istniej takie stae dodatnie n0 i c, e dla wszystkich n n0 zachodzi f(n) cg(n).
(a)
Czy zgodnie z t definicj prawd jest, e f(n) = (g(n)) wtedy i tylko wtedy, gdy
g(n) = O(f(n))?
(b)
Czy stwierdzenie wyraone w punkcie a) jest prawdziwe w kontekcie definicji
(n) przedstawionej w podrozdziale Czas wykonywania programu?
(c)
Czy rozwizanie zadania 1.14 pozostaje niezmienne, jeeli przyj now definicj
duej omegi?
1.16. Uporzdkuj nastpujce funkcje pod wzgldem tempa wzrostu:
(a)
n
(b)
(c)
log n
(d)
log log n
(e)
log2n
(f)
n/log n
log2n
(g)
(h)
(1/3)n
(i)
(3/2)n
(j)
17
1.17. Zamy, e parametr  poniszej procedury jest dodatni potg liczby 2. Znajd formu
wyraajc wypisywan warto zmiennej  w funkcji .
 



 
  
 
 $
 #  
 $
 





1.18. Dana jest tablica i funkcja ,


zwracajca najwikszy element z cigu elementw
    . Przyjmujemy dla wygody, e  jest potg liczby 2.
  



 
  
  %

48

1. PROJEKTOWANIE I ANALIZA ALGORYTMW

 

  
   $

  $  $

 #








(a)

(b)

Niech T(n) bdzie pesymistycznym czasem wykonania w zalenoci od drugiego


parametru n oznaczajcego liczb przeszukiwanych elementw. Napisz rwnanie
wyraajce zaleno T(n) od T(j) dla jednej lub kilku wartoci j < n oraz podaj
sta (lub stae) reprezentujc (reprezentujce) czasy wykonywania poszczeglnych instrukcji funkcji .
Podaj (w notacji duego O) cis warto grnego ograniczenia T(n). Warto ta
powinna by rwna dolnemu ograniczeniu (wyraonemu w notacji duej omegi)
i powinna by jak najprostsza.

Uwagi bibliograficzne
Koncepcja abstrakcyjnego typu danych ma sw genez w klasie (typie class) jzyka Simula 67
(Birtwistle i in., [1973]). Od tego czasu powstao wiele innych jzykw zawierajcych abstrakcyjne
typy danych, midzy innymi Alphard (Shaw, Wulf i London [1977]), C++ (Stroustrup [1982]), MESA
(Geschke, Morris i Satterthwaite [1977]) i Russel (Demers i Donahue [1979]). Koncepcja ADT jest
przedmiotem rozwaa prac Gotliebw [1978] oraz Wulfa i in. [1981].
Dzieo Knutha [1968] jest pierwsz ze znaczcych publikacji promujcych systematyczne studia
nad czasem wykonywania programw. Aho, Hopcroft i Ullman [1974] odnosz zoono czasow
i pamiciow algorytmw do rnorodnych modeli obliczeniowych, jak maszyny Turinga i maszyny
o dostpie swobodnym. Zobacz take uwagi bibliograficzne do rozdziau 9. zawierajce wicej
odsyaczy do rde traktujcych o analizie algorytmw i programw.
Jako lektur uzupeniajc na temat programowania strukturalnego poleci mona opracowania
Hoarego, Dahla i Dijkstry [1972], Wirtha [1973], Kernighana i Plaugera [1974] oraz Yourdona i Constantine [1975]. Organizacyjne i psychologiczne aspekty realizacji duych projektw programistycznych dyskutowane s przez Brooksa [1974] i Weinberga [1971]. Kernighan i Plauger [1981] demonstruj sposoby budowania uytecznych narzdzi programistycznych w Pascalu.

Das könnte Ihnen auch gefallen