02.02.2015 Views

Graafid Kui ühendada elemendid omavahel viitadega vabamal kujul ...

Graafid Kui ühendada elemendid omavahel viitadega vabamal kujul ...

Graafid Kui ühendada elemendid omavahel viitadega vabamal kujul ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Graafid</strong><br />

Graaf<br />

<strong>Kui</strong> <strong>ühendada</strong> <strong>elemendid</strong> <strong>omavahel</strong> <strong>viitadega</strong> <strong>vabamal</strong> <strong>kujul</strong>, kui seda lubavad puude vōi lineaarnimistute kohta käivad<br />

reeglid, saadakse graaf. Graafi vōib kirjeldada kui andmestruktuuri, mis ei pea olema lineaarne. Graaf on kōige üldisem<br />

vōimalus andmete vaheliste seoste kujutamiseks. Nii lineaarnimistu kui ka puu on vaadeldavad graafi erijuhtudena.<br />

Põhimõisted graafi kohta (Vaata ka diskreetse matemaatika loenguid!!)<br />

Graaf koosneb tippudest ja tippe ühendavatest kaartest (servadest).<br />

Graaf on suunatud (orienteeritud), kui tema kaartel on suund, st iga kaare jaoks on määratud, millisest tipust ta<br />

algab ja millises tipus lōppeb e. teisisōnu vōib öelda, et on graafi tipud on järjestatud (seda tähistatakse noolega<br />

kaare otsas).<br />

Suunamata (orienteerimata) graafi puhul on seos kahe tipu vahel mōlemas suunas ja noolt ei märgita.<br />

Suunatud graafi puhul eristatakse neid tippe, kuhu ühtegi kaart ei sisene (source) ja neid, kust ühtegi kaart ei välju<br />

(sink).<br />

Kaks tippu v ja u on seotud, kui nende vahel on tee.<br />

Kaks tippu külgnevad, kui ühest tipust läheb kaar teise tippu.<br />

Graafis saab leida tee ehk ahela ühest tipust teise tippu (suunatud graafi puhul ei pruugi seda alati leiduda). Teel on<br />

pikkus. Tee ehk ahel on selline kaarte järgnevus, kus ühe kaare lõpp-punkt on järgmise kaare alguspunktiks. Suunamata<br />

graafis saab tee minna läbi kaare mõlemat pidi, suunatud graafis tuleb arvestada kindlasti kaare suunaga. Sama kaar või<br />

sama tipp võivad ahelas korduda.<br />

Elementaarahel on selline ahel, mis ei läbi ühtegi tippu üle ühe korra.<br />

Lihtahel on ahel, mis ei läbi ühtegi serva üle ühe korra.<br />

<strong>Kui</strong> ahela algus- ja lõpp-punkt on samad, siis on tegemist tsükliga.<br />

Ja siit saame vastavalt elementaartsükli (elementaarahel, mis lõppeb samas tipus) ja lihttsükli (lihtahel, mis lõppeb<br />

sama tipus) mõisted.<br />

Hamiltoni tsükkel on elementaartsükkel, mis läbib kõiki graafi tippe.<br />

Euleri tsükkel on lihttsükkel, mis läbib kõiki graafi servi ühe. (Graafi tutvustamine matemaatik Euleri poolt<br />

Königsbergi sildade probleemi läbi – kas linnakodanik saab pühapäevasel jalutuskäigul üle jõe ääres ja saartel liikuda<br />

nii, et ta ületab kõik sillad üks kord ja saab koju tagasi minna. Tulemuseks oli, et ei saa, st üle sildade ei saa<br />

<strong>Kui</strong> graafis ei ole ühtegi tsüklit (suvalisest tipust ei leidu teed samasse tippu tagasi), nimetatakse graafi atsükliliseks.<br />

Suunatud atsükliline graaf on oluline paljude ülesannete lahendamisel.<br />

Graafi nimetatakse täielikuks, kui tal on kaared kõigi tippude vahel. Tühigraafis ei ole ühtegi serva.<br />

<strong>Kui</strong> graafi kasutatakse mõne ülesande lahendamiseks, paigutatakse tippudesse info. Tipud saavad sõltuvalt rakendusest<br />

endale nimed, seega on tipud kui mingid objektid, sündmused vms. Kaar kahe tipu vahel tähistab seost nende kahe<br />

objekti või sündmuse vahel. Orienteerimata graafi saab kasutada mõlemapidise seose näitamiseks (seos on võrdne tipust<br />

u tippu v ja vastupidi). Orienteeritud graafi puhul on seosel suund (näiteks võib see näidata sündmuste järgnevust).<br />

Orienteeritud graafi puhul pannakse kahe tipu vahele 2 kaart, et kirjeldada mõlemat pidi seost. Orienteerimata graafis on<br />

kahe tipu vahel maksimaalselt üks seos (kaar)..<br />

Graafi kaartega saab siduda arvud. Sel juhul kannab kaar informatsiooni lisaks seoseinfole. Neid arve kutsutakse<br />

kaaludeks ning vastavat graafi kaalutud graafiks (weighted graph) e. võrguks (network)<br />

Olulisemad tegevused graafiga:<br />

• Kaare lisamine (milliste tippude vahele)<br />

• Tipu kustutamine (milline tipp)<br />

• Kaare kustutamine (milliste tippude vahelt)<br />

• Tipu nime küsimine<br />

• Tipu nimega X otsimine (vastus on true või false)<br />

Seoses sellega, et graafi tippe on erinevate algoritmide käigus vaja külastada, on vaja:<br />

1


<strong>Graafid</strong><br />

• märgistada, et tippu või kaart külastati<br />

• küsida, kas tippu või kaart on külastatud<br />

Graafi kohta saab mitmesugust infot küsida:<br />

• tippude arvu<br />

• kaarte arvu<br />

• ühe tipu naabreid<br />

• kas graaf on orienteeritud<br />

Ja graafis tuleb liikuda, st läbida tippe ja kaari mingis järjekorras.<br />

• kõigi kaarte läbimine üks kord (teatatakse kaarte kaalud, kui neid on)<br />

• kõigi tippude läbimine üks kord (teatatakse tippude nimed)<br />

Lisaks on mitmed traditsioonilised algoritmid, mida erinevate ülesannete lahendamiseks kasutada saab. Näiteks:<br />

• sügavuti otsimine<br />

• laiuti otsimine<br />

• topoloogiline sorteerimine<br />

• lühima tee leidmine kahe tipu vahel<br />

• lühima tee leidmine kõigi tippude vahel<br />

Realisatsioon<br />

<strong>Graafid</strong>e kujutamiseks on kaks peamist võimalust, millistele tuginedes ka vastavad algoritmid on väljatöötatud:<br />

külgnevusnimistuna ja külgnevusmaatriksina. Eelistatav realisatsioon sõltub graafi iseloomust. <strong>Graafid</strong>e puhul<br />

eristatakse tihedaid (dense) ja hõredaid (sparse) graafe.<br />

Hõreda graafiga on tegemist juhul, kui tema kaarte arv on palju väiksem tippude arvu ruudust<br />

<strong>Kui</strong> graafis on tippe palju (N on suur), siis nende mahutamine maatriksisse muutub raskeks, st maatriks läheb väga<br />

suureks. <strong>Kui</strong> selles graafis vähe kaari, siis täitub suurem osa maatriksist 0-ga ja sel juhul on tegemist mälu raiskamisega.<br />

<strong>Kui</strong> aga tippude arv ei ole suur ja kogu maatriksi hoidmine probleemi ei valmista, tasub kasutada maatriksit (massiivi),<br />

sest operatsioonid on lihtsamad.<br />

Staatiline realisatsioon<br />

Graafi kujutatakse külgnevusmaatriksina (adjacency matrix). Nii ridu kui veerge on maatriksis sama palju kui graafis<br />

tippe. Igasse maatriksi lahtrisse kantakse True (1) või False (0). Kaar on kahe tipu vahel sel juhul, kui<br />

maatriksisse on märgitud 1 (true) ning kaare puudumist tähistab 0 (false). Suunamata graafi puhul on tegemist<br />

peadiagonaali suhtes sümmeetrilise maatriksiga. Joonisel on sel juhul kaared ilma noolteta. Suunatud graafil võib olla<br />

kahe tipu vahel ka kaks kaart, kui seos mõlemas suunas on olemas.<br />

1<br />

3<br />

6<br />

9<br />

5<br />

2<br />

4<br />

7<br />

8<br />

10<br />

Joonis 1. Suunatud graaf<br />

2


<strong>Graafid</strong><br />

1 2 3 4 5 6 7 8 9 10<br />

1 0 1 1 0 0 0 0 0 0 0<br />

2 0 0 0 0 0 0 0 0 0 0<br />

3 0 0 0 1 1 1 0 0 0 0<br />

4 0 0 0 0 1 0 0 0 0 0<br />

5 0 0 0 0 0 1 0 0 0 0<br />

6 0 0 0 0 0 0 1 0 1 0<br />

7 0 0 0 0 0 0 0 0 0 0<br />

8 0 0 0 0 0 0 1 0 1 0<br />

9 0 0 0 0 0 0 0 0 0 1<br />

10 0 0 0 0 0 0 0 0 0 0<br />

Joonis 2. Graafi külgnevusmaatriks<br />

Selliselt on kujutatud nö puhas graaf, kus tippudega mingit olulist infot seotud ei ole, on vaid seosed.<br />

Tegelikult algab siiski kõik infoelemendist, sest ilma infota pole graafiga midagi pihta hakata. Kirjeldatakse kirje, kus on<br />

infoväljad ja nimeväli (tipu nimi või number). Kirjetest moodustatakse ühemõõtmeline massiiv, kus on kirjeid samapalju<br />

kui on graafis tippe (tegemist on tippude massiiviga). Eelpool kirjeldatud kahemõõtmeline massiiv on seoste e kaarte<br />

massiiv. Kaarte massiiv võib olla nii tõeväärtustüüpi kui ka täisarvutüüpi liikmetest. Boolean ja byte on<br />

mõistlikumad ruumi kokkuhoiu mõttes. <strong>Kui</strong> seostel on kaalud, on kindlasti vaja kasutada massiivi täis- või reaalarvudest,<br />

et kirja läheksid ka kaalud. Sel juhul kirjutatakse seoste massiivi 1 asemel seose kaal ja seose puudumist saab esitada<br />

mõne suurusega, mis kaaluks olla ei saa (0, -1 vms).<br />

Graafi tiputüübi kirjeldus Pascalis oleks järgmine:<br />

type<br />

tiputyyp=record<br />

nimi: string[20];<br />

tipuinfo: infotyyp; {mis iganes}<br />

end;<br />

kaaretyyp = record<br />

on: boolean; {või byte}<br />

kaal: integer {string, real, ...}<br />

end;<br />

{<strong>Kui</strong> seoste kohta on vaja meeles pidada vaid kaale, võib massiivi elemendiks olla lihtsalt arv}<br />

graafityyp = array[1..m] of tiputyyp;<br />

maatriksityyp = array[1..m,1..m] of kaaretyyp;<br />

var kylgnev: maatriksityyp;<br />

tipud: graafitüüp;<br />

Protseduurid<br />

Kahe tipu x ja y ühendamine (tipud on loomulikult teada ja programmis on mõistlik kasutada tippude nummerdamist).<br />

procedure Yhenda (x,y: byte);<br />

begin<br />

Kylgnev[x,y]:=true {või 1 vastavalt deklaratsioonile}<br />

end;<br />

Kontroll, kas kaks tippu x ja y külgnevad (on ühendatud):<br />

function Yhendatud(x, y: byte): boolean;<br />

begin<br />

Yhendatud:=Kylgnev[x,y];<br />

end;<br />

Leidmaks tipu x naabreid, on vaja läbi vaadata vastav rida massiivis.<br />

for i:=1 to m do<br />

if kylgnev[x,i]=1 then<br />

3


<strong>Graafid</strong><br />

writeln('Tipp ',i,' külgneb tipuga ',x);<br />

Näites on tipud välja trükitud, tegelikult tuleks neid protseduurist näiteks massiivi abil programmi tagasi tuua.<br />

Keerulisemad on algoritmid graafi läbimiseks ja teede leidmiseks. Näiteks selleks, et leida, kas tipust x läheb tee tippu y<br />

tuleb maatriksiga arvutusi teha.<br />

<strong>Graafid</strong>e töötlemisel kasutatakse laiuti või sügavuti otsimise tehnikat (kuna teid võib olla palju tuleb kõik võimalused<br />

ära proovida, sest tavaliselt ei aita ühe tee leidmisest, vaid see tee peab vastama mingitele tingimustele) ja sel juhul<br />

läheb sellise algoritmi keerukus O(N 3 )-ni. Reeglina tuleb siin kasutada ka rekursiooni. Aitab ka dünaamiline<br />

programmeerimine. Nimetatud erinevatest algoritmide koostamise strateegiatest tuleb juttu edaspidi.<br />

Dünaamiline realisatsioon<br />

Hõreda graafi ökonoomsemaks kujutamiseks võetakse kasutusele nimistud, nn külgnevusnimistu (adjacency list).<br />

Graafi tippudest moodustatakse massiiv, üks lahter iga tipu jaoks (võib ka lineaarnimistu) ning iga tipulahtri külge<br />

kinnitatakse lineaarnimistu nendest tippudest, mis külgnevad antud tipuga. Nimistu lõpus on nil.<br />

Selliselt saab mälu kokku hoida. Siit võite endale ise ette kujutada, mida sel juhul tähendaksid uue kaare lisamine<br />

(riputame nimistu lõppu uue elemendi), kaare kustutamine (kustutame elemendi) ja naabrite leidmine (läbime vastava<br />

nimistu).<br />

Kahe viidaga nimistu külgnevate tippude hoidmiseks on sobivam.<br />

1 ---> 2 ---> 3 nil<br />

2 nil<br />

3 ---> 4 ---> 5 ---> 6 nil<br />

4 ---> 5 nil<br />

5 ---> 6 nil<br />

6 ---> 7 ---> 9 nil<br />

7<br />

8 ---> 7 ---> 9 nil<br />

9 ---> 10 nil<br />

10 nil<br />

Joonis 3. Külgnevusnimistu joonisel 1 olevale graafile.<br />

Kõigi tegevuste puhul nii 1. kui 2. realisatsiooni korral tuleb arvestada, kas graaf on orienteeritud või mitte.<br />

Orienteerimata graafi korral tuleb kaare lisamisel tippude x ja y vahele kirjutada 1 nii lahtrisse Kylgnev[x,y] kui ka<br />

Kylgnev[y,x]. Dünaamilise realisatsiooni korral lisada kaks elementi - tipu x element y-i külge ning tipu y element<br />

x-i külge.<br />

Mida teha kaalutud graafiga Sel juhul tuleks Kylgnev-massiivi kirjutada ka vastavate kaarte kaalud (milleks<br />

massiivi kirjelduses on isegi väli olemas 'kaalu' näol).<br />

Mõned probleemid, millele on võimalik vastuseid leida kasutades graafide jaoks mõeldud algoritme:<br />

• <strong>Kui</strong>das jõuab kõige kiiremini Tallinnast Värskasse<br />

• <strong>Kui</strong>das saab kõige odavamalt Tallinnast Värskasse<br />

• <strong>Kui</strong>das transportida kaupa kõige odavamalt erinevatelt müüjatelt erinevatele ostjatele.<br />

• <strong>Kui</strong>das korraldada tööde järjekord, et saada maja valmis kõige lühema ajaga<br />

• Millises järjekorras valida õppeained, et võimalikult lühema ajaga ülikool lõpetada<br />

• Millises järjekorras käia ära kõigis linnades, et see toimuks võimalikult ruttu või lühemat teed mööda. Tegemist on<br />

klassikalise nn 'rändkaupmehe ülesandega'.<br />

Kõigi selliste probleemide lahendamiseks tuleks kõigepealt olukord kirjeldada graafina ja seejärel kasutades<br />

graafialgoritme, leida lahendused. Olles probleemi graafina kirja pannud pole enam vahet, kas uurime tööde tegemise<br />

4


<strong>Graafid</strong><br />

optimaalset järjestust või parimat õppeainete valimise järjekorda – tegevus taandub topoloogilise sorteerimise<br />

algoritmile.<br />

Tippude läbimine<br />

Graafi kõiki tippe võib vaja olla läbida mitmel erineval eesmärgil, kuid tavaliselt on oluline teha seda mingil lubatud<br />

viisil, st lähtudes kaartest ja nende suundadest. Selleks kasutatakse kahte erinevat strateegiat ja sõltub nö kaugemast<br />

eesmärgist, millist nendest valida. Need strateegiad on laiuti otsimine ja sügavuti otsimine. Mõlemal juhul lähtutakse<br />

ühest graafi tipust ja liikudes tipult tema naabrile läbitakse kõik tipud. Strateegia järgmise tipu valimisel on erinev.<br />

Laiuti otsimine (breadth-first search)<br />

Laiuti otsimine on teatud algoritmi tüüp, mida on sobiv kasutada ülesannete puhul, kus otsitakse parimat lahendust ja<br />

see tuleks välja sõeluda paljude võimaluste hulgast. Iseloomulikuks sellise lähenemise juures on, et kõiki<br />

lahendusvariante ei püüta kätte saada ükshaaval, et neid hiljem võrdlema hakata, vaid neid uuritakse paralleelselt. Laiuti<br />

otsimise põhimõtet ei kasutata ainult graafide juures.<br />

Laiuti otsimiseks ei esitata graafile mingeid kitsendusi, ta võib olla nii suunatud kui ka suunamata. <strong>Kui</strong> algustipust<br />

leidub tee igasse teise graafi tippu, siis see toodud algoritmi abil ka leitakse.<br />

Laiuti otsimine graafis ei ole niivõrd üksinda kasutatav, kui teiste algoritmide koosseisus (näiteks lühima tee leidmise<br />

juures).<br />

Algoritm<br />

Algoritmi alguses valitakse algustipp S ja sellest lähtudes uuritakse graafi.<br />

Algoritmi töö tulemuseks on loetelu tippudest, mis on kättesaadavad tipust S lähtudes, lisaks on teada tee pikkus tipust<br />

S antud tippu (mitu kaart kahe tipu vahele jääb). Tekib puu<strong>kujul</strong>ine struktuur (mida küll füüsiliselt üles ei ehitata), nn<br />

laiutiotsimispuu.<br />

Algoritmi täitmiseks “värvitakse “ tipud (color[u]), peetakse meeles iga tipu eellast (P[u]) ja sammude arvu<br />

esimeset tipust antud tipuni (d[u]).<br />

Tipud võivad olla valged, hallid või mustad (värvima kindlasti ei pea, kuid meeles peab pidama nende kolme olekut):<br />

• valge (white) - tipuni pole veel jõutud;<br />

• hall (grey) – tipuni on jõutud, tema eellane on fikseeritud, kuid temaga külgnevad tipud pole veel kõik läbi uuritud<br />

(tegutsemise front);<br />

• must (black) – tipu järglased on läbi uuritud ja rohkem selle tipu kallale minna ei tohi.<br />

Alguses on kõik tipud valged, ja esimesel sammul värvitakse halliks algustipp S. Edasi värvitakse halliks tema naabrid ja<br />

tipp ise mustaks. Iga halli tipuga tehakse järgmist:<br />

• kui mõni naaber on valge, värvitakse ta halliks, halli ja musta naabrit ei puudutata;<br />

• kui kõik naabertipud on hallid või mustad, värvitakse tipp ise mustaks.<br />

Selliselt laieneb läbiuuritud mustade tippude hulk ja hallid tipud on piiriks uuritud ja uurimata ala vahel. Samal ajal<br />

saadakse paralleelselt teada teede pikkused algustipust kõigisse teistesse graafi tippudesse.<br />

Realiseerimaks laiutiotsimise algoritmi jaoks võetakse lisaks graafile kasutusse järjekord Q hallide tippude ajutiseks<br />

hoidmiseks. Järgnevas algoritmis kasutatakse kahte järjekorra protseduuri Enqueue (järjekorda lisamiseks) ja<br />

Dequeue (järjekorrast eemaldamiseks), mida meil seni realiseeritud pole, kuid mis ei tohiks erilist peavalu valmistada.<br />

Lisaks on kasutatud keelekonstruktsiooni foreach, mille abil töödeldakse läbi <strong>elemendid</strong> mingist hulgast. Vastav<br />

tegevus on dünaamilise ja staatilise realisatsiooni puhul erinev, seetõttu pole teda täpsustatud.<br />

Breadth_first(G,s)<br />

{Algoritm graafis G laiutiotsimiseks lähtudes tipust s}<br />

Foreach u in G do {Graafi algväärtustamine, tehakse iga tipuga}<br />

color[u]


<strong>Graafid</strong><br />

Dequeue(Q,u) {Võtame järjekorrast halli tipu u}<br />

foreach v in Adj[u] do {Iga tipuga v, mis on tipu u naabriks}<br />

if color[v]=white then<br />

color[v]


<strong>Graafid</strong><br />

foreach v in Adj[u] do<br />

if color[v]=white then<br />

P[v]


<strong>Graafid</strong><br />

Variatsioonid lühima tee probleemist<br />

Vaatame probleeme, mis piirduvad ühest tipust lähtuvate teedega (single-source shortest-path problem). Lühima tee<br />

probleem sõnastati järgmiselt: on antud graaf G=(V,E) ja algtipp s (source vertex), tarvis on leida lühimad teed<br />

kõigisse teistesse graafi tippudesse hulgast V. Kirjeldatud laiutiotsimise algoritm sobib ka järgmiste ülesannete<br />

lahendamiseks:<br />

• Lühimad teed antud tippu: on antud lõpp-tipp t, tarvis on leida lühimad teed, mis ülejäänud tippudest antud tippu<br />

viivad (originaalülesanne tagurpidi)<br />

• Lühim tee kahe tipu u ja v vahel: kiireim meetod on leida kõik u-st lähtuvad teed ja vastuseks anda otsitav tee.<br />

• Lühimad teed erinevate (kõigi) tipupaaride vahel: laiuti otsimise algoritmi on vaja korrata erinevate tipupaaride<br />

jaoks.<br />

Lühim tee kaalutud graafis<br />

<strong>Kui</strong> iga sammu (kaare) kaal graafil on 1, on lühima tee probleem lahendatud laiuti otsimise algoritmi abi. <strong>Kui</strong> aga<br />

tahaksime teada saada, milline on lühim tee Pärnust Narva, siis kirjeldatud algoritm ei sobi, sest arvestada tuleks<br />

tegelikku teepikkust, milleks on vaja kasutada kaalutud graafi.<br />

Graafi Pärnust Narva sõidu optimiseerimiseks saab selliselt, et tuleb atlase järgi kõik teede ristid (või kui olete<br />

otsustanud vaid asfalti mööda sõita, siis asfaltteede ristid) märkida kui graafi tipud ja kaared tõmmata vaid nende<br />

tippude vahele, milliste ristmike vahel tegelikult teed on. Edasi märgitakse igale kaarele (teejupile) tema pikkus<br />

kilomeetrites, mis ka autoatlases olemas on ning kaalutud graaf ongi valmis. Kaaluks võib ka olla eeldatav aeg antud<br />

teelõigu läbimiseks.<br />

Tee kaaluks on kõigi teed moodustavate kaarte kaalude summa.<br />

Lühima tee kaal (shortest-path weight) on vähim kaal kõigi teede kaaludest. See ei pruugi olla sama tee, kus vähim arv<br />

samme tehakse.<br />

Lühima tee iga lõik on ise lühim tee.<br />

Dijkstra algoritm<br />

Algoritme kaalutud graafis lühima tee leidmiseks on mitmeid. Järgnevalt kirjeldatakse Dijkstra algoritmi. Nimetatud<br />

algoritm töötab orienteerimata kui ka orienteeritud graafis. Graafis ei tohi olla tsüklit, kus kaarte pikkuste summa tuleks<br />

negatiivne. Algoritm töötab ahne algoritmi põhimõttel, st igal sammul tehakse lokaalselt parim otsus ja need otsused<br />

viivad kogu probleemi lahenemiseni.<br />

Algoritm vajab tööks tippude tabelit, kuhu kirjutatakse iga tipu jaoks tema kaugus lähtetipust ja tipu number, kust antud<br />

tippu jõuti.<br />

Tippude tabel algväärtustatakse selliselt, et tippudel puuduvad eellased ja kõik kaugused on lõpmata suured.<br />

Alustatakse tipust s ja selle tipu kauguseks märgitakse 0.<br />

WHILE-tsükli töö on järgmine: kõigi nende tippude hulgast, mille naabrid on läbiuurimata, valitakse tipp u, millega<br />

seotud kaugus on minimaalne (esimesel kordusel on selleks lähtetipp). Seejärel vaadatakse üle kõik tipu u naabrid v ning<br />

kui kaugus tipus v on suurem kui kaugus, mis tekiks tippu v liikumisel üle tipu u, asendatakse nii tipu v kaugus d[v] kui<br />

ka eelmine tipp P[v].<br />

WHILE-tsükkel töötab seni, kuni kõigi graafi tippude naabrid on läbiuuritud.<br />

Ajaliselt kõige kriitilisem on läbiuurimata tippude hulgast kõige väiksema kaugusega tipu leidmine. Graafi tippude<br />

hoidmiseks soovitatakse kasutada prioriteetidega järjekorda Q, mille ülalpidamine peaks olema kiirem. Prioriteedi<br />

määrab kaugus.<br />

Väikese tippude hulga juures võib leida lihtsalt miinimumi läbiuurimata.tippude hulgast.<br />

Algoritmis kasutatakse ka hulka S, kuhu pannakse läbiuuritud tipud (sellele võib järjekorrata realisatsioonis vastata tipu<br />

märkimine läbiuurituks).<br />

Dijkstra algoritm<br />

Dijkstra(G,w,s) {G – graaf; w – kaarte kaalud; s – algustipp}<br />

foreach v in G do {teedepikkuse ja eellaste massiivid nullitakse}<br />

d[v]


<strong>Graafid</strong><br />

S d[u]+w(u,v) then {<strong>Kui</strong> läbi u minev tee mõne naabri juurde}<br />

d[v]


<strong>Graafid</strong><br />

1<br />

3<br />

6<br />

9<br />

5<br />

2<br />

4<br />

7<br />

8<br />

10<br />

Joonis 4 Orienteeritud atsükliline graaf, mida saab topoloogiliselt sorteerida<br />

{Selle programmifragmendiga loendatakse kokku eellaste arv iga tipujaoks e mitu kaart suubub antud tippu.}<br />

for j:= 1 to m do<br />

for i:= 1 to m do<br />

if kylgnev[i,j]=1 then<br />

loendur[j]:=loendur[j]+1;<br />

Nüüd on iga tipu kohta kirjas tema vahetute eellaste arv. Kanname jadasse need tipud, millel loendur[i]=0 e millel<br />

pole eellasi.<br />

Järgnevalt on toodud Pascalis realiseeritud topoloogilise sorteerimise algoritm, mis töötab külgnevusmaatriksi peal.<br />

VeelOli:=true;<br />

while VeelOli do<br />

begin<br />

VeelOli:=false;<br />

for i:=1 to m do<br />

if loendur[i]=0 then<br />

begin<br />

{Trükitakse välja need, millel eellased puuduvad ja pannakse kirja, et need tipud on juba jadas (-1).}<br />

writeln(i);<br />

VeelOli:=true;<br />

loendur[i]:=-1;<br />

for j:=1 to m do<br />

{Vähendame loenduris nende elementide kordajaid, millistele jadasse pandud elmendid eellaseks olid.}<br />

if kylgnev[i,j]=1 then {i-nda tipu kohta käiv rida, j-ga on side}<br />

loendur[j]:=loendur[j]-1;<br />

end;<br />

end;<br />

Näites trükiti jada välja, kuid selle võib ka massiivi panna. Kindlasti ei saa seda algoritmi rakendada, kui graafis on<br />

tsükkel, kuid siis ei saa nagunii topoloogiliselt sorteerida.<br />

Eespool joonisel 3 oleva graafi kohta oleks külgnevate tippude loendamise massiiv järgmine:<br />

1 2 3 4 5 6 7 8 9 10<br />

0 1 1 1 2 2 2 0 2 1<br />

Kaks võimalikku väljundit oleksid:<br />

1 2 3 4 5 6 8 9 10 7<br />

8 1 3 2 4 5 6 9 7 10<br />

Huvitavaks probleemiks on veel, millal tipp kõige varem ja kõige hiljem sorteeritud jadasse sattuda saab. Sellist<br />

teadmist võib vaja olla tööde planeerimise ülesande juures.<br />

10


<strong>Graafid</strong><br />

Kokkuvõte<br />

1. Graafe saab kasutada väga erinevate struktuuride ja seoste kujutamiseks<br />

2. Paljude ülesannete juures, kui probleem korralikult formuleerida, saab teda modelleerida graafi kasutades selliselt, et<br />

lahenduseks sobib mõne tuntud efektiivse algoritmi kasutamine. Tavaliselt graafi töötlemiseks ise algoritme leiutada<br />

on keeruline.<br />

3. Sügavuti ja laiuti otsimine on algoritmid, millega kõik tipud ja kaared läbitakse. Nad on aluseks mitmetele teistele<br />

algoritmidele<br />

4. Kuluta suurem aeg graafi mõistlikuks modelleerimiseks, pärast on algoritmi lihtne kirja panna.<br />

11

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!