PDF oblika učbenika "OSNOVNI ALGORITMI"

OSNOVNI ALGORITMI
Boˇstjan Vilfan
23. januar 2011
CIP - Kataloˇzni zapis o publikacijah
Narodna in univerzitetna knjiˇznica, Ljubljana
510.5:5:004.42(075.8)
VILFAN, Boˇstjan
Osnovni algoritmi / Boˇstjan Vilfan
- 2. izdaja. - Ljubljana : Fakulteta za raˇcunalniˇstvo in informatiko, 2002
ISBN 961-6209-13-2
116054784
c
Copyright 2002
Zaloˇzba FE in FRI. All rights reserved.
Razmnoˇzevanje (tudi fotokopiranje) dela v celoti ali po delih
brez predhodnega dovoljenja Zaloˇzbe FE in FRI prepovedano.
Recenzenta:
strokovni – dr. Borut Robiˇc, izr. prof.
jezikovni – Alma Korenini, prof.
Zaloˇzila: Fakulteta za raˇcunalniˇstvo in informatiko, 2002
ˇ
Urednik: mag. Peter Sega
Natisnil: FORMATISK, Ljubljana
Naklada: 200 izvodov
2. izdaja
Kazalo
PREDGOVOR
vii
1 ALGORITMI
1.1 Pojem algoritma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Preverjanje pravilnosti . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.1 Preverjanje pravilnosti s poskusi . . . . . . . . . . . . . . . . .
1.2.2 Logiˇcno dokazovanje pravilnosti . . . . . . . . . . . . . . . . . .
1.2.3 Dokazovanje pravilnosti programov, ki so predstavljeni z diagrami poteka . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2.4 Dokazovanje pravilnosti programov, ki so zapisani v programskem jeziku . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3 Preverjanje ustavljanja . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4 Poraba ˇcasa in prostora . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1 Zapis za asimptotiˇcno rast funkcij . . . . . . . . . . . . . . . .
ˇ
1.4.2 Cas
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.3 Prostor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5 Povzetek osnovnih pojmov . . . . . . . . . . . . . . . . . . . . . . . . .
1.6 Naloge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
15
16
18
19
22
22
23
2 UREJANJE
2.1 Naloga urejanja in klasifikacija metod urejanja . . . . .
2.2 Notranje urejanje . . . . . . . . . . . . . . . . . . . . . .
2.2.1 Navadno vstavljanje . . . . . . . . . . . . . . . .
2.2.2 Navadno izbiranje . . . . . . . . . . . . . . . . .
2.2.3 Navadne zamenjave . . . . . . . . . . . . . . . .
2.2.4 Spodnja meja za ˇcas urejanja tabel . . . . . . . .
2.2.5 Shellovo urejanje (izboljˇsano vstavljanje) . . . .
2.2.6 Urejanje s kopico (izboljˇsano izbiranje) . . . . . .
2.2.7 Urejanje s porazdelitvami (izboljˇsane zamenjave)
2.2.8 Primerjava razliˇcnih metod urejanja . . . . . . .
2.2.9 Iskanje k-tega elementa v tabeli . . . . . . . . . .
2.3 Zunanje urejanje . . . . . . . . . . . . . . . . . . . . . .
25
25
29
30
34
34
35
39
41
44
51
51
53
iii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
1
1
4
4
5
6
iv
KAZALO
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
53
57
59
62
69
75
76
3 ALGORITMI Z REKURZIVNIM RAZCEPOM
3.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Mnoˇzenje matrik . . . . . . . . . . . . . . . . . . . . .
3.2.1 Metoda S. Winograda . . . . . . . . . . . . . .
3.2.2 Metoda V. Strassena . . . . . . . . . . . . . . .
3.3 Diskretna Fourierjeva transformacija in algoritmi zanjo
3.3.1 Uvod . . . . . . . . . . . . . . . . . . . . . . .
3.3.2 Diskretna Fourierjeva transformacija . . . . . .
3.3.3 Interpretacija DFT s polinomi . . . . . . . . .
3.3.4 Konvolucija polinomov . . . . . . . . . . . . . .
3.3.5 Rekurzivni algoritem za DFT . . . . . . . . . .
3.3.6 Iterativni algoritem za DFT . . . . . . . . . . .
3.4 Povzetek osnovnih pojmov . . . . . . . . . . . . . . . .
3.5 Naloge . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
79
79
79
80
81
82
82
82
84
85
89
91
98
98
ˇ
ˇ
4 POZRE
SNI
ALGORITMI
4.1 Uvod . . . . . . . . . . . . . . . . . . . . . . .
4.2 Osnovna zgradba poˇzreˇsnega algoritma . . . .
4.3 Razvrˇsˇcanje zapisov na magnetnem traku . .
4.4 Razvrˇsˇcanje poslov v delavnici z enim strojem
4.5 Povzetek osnovnih pojmov . . . . . . . . . . .
4.6 Naloge . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
101
101
103
103
105
107
109
2.4
2.5
2.3.1 Navadno zlivanje . . . . . . . . . . . . . . .
2.3.2 Naravno, uravnoteˇzeno, dvosmerno zlivanje
2.3.3 Naravno, uravnoteˇzeno, veˇcsmerno zlivanje
2.3.4 Polifazno urejanje . . . . . . . . . . . . . .
2.3.5 Polifazno urejanje s predurejanjem . . . . .
Povzetek osnovnih pojmov . . . . . . . . . . . . . .
Naloge . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 PRETOKI IN LINEARNO PROGRAMIRANJE
5.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2 Problem maksimalnega pretoka skozi omreˇzje . . . . . . . . . . . . . .
5.2.1 Definicija problema . . . . . . . . . . . . . . . . . . . . . . . . .
5.2.2 Algoritem za maksimalni pretok . . . . . . . . . . . . . . . . .
5.3 Linearno programiranje . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.2 Konveksne poliedrske mnoˇzice . . . . . . . . . . . . . . . . . . .
5.3.3 Maksimum linearne funkcije na konveksni poliedrski
mnoˇzici . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.3.4 Lokalni pogoj za globalni maksimum linearne funkcije na konveksni poliedrski mnoˇzici . . . . . . . . . . . . . . . . . . . . .
5.3.5 Simpleksni algoritem . . . . . . . . . . . . . . . . . . . . . . . .
111
111
111
111
115
117
117
119
121
123
125
v
KAZALO
5.4
5.5
Povzetek osnovnih pojmov . . . . . . . . . . . . . . . . . . . . . . . . . 127
Naloge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
ˇ
ˇ POTI
6 DINAMICNO
PROGRAMIRANJE IN NAJCENEJSE
6.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2 Problem 0-1 nahrbtnika . . . . . . . . . . . . . . . . . . . . . . . .
6.3 Problem najcenejˇsih poti . . . . . . . . . . . . . . . . . . . . . . . .
6.3.1 Najcenejˇse poti med zaˇcetnim vozliˇsˇcem in vsemi ostalimi .
6.3.2 Najcenejˇse poti med vsemi pari vozliˇsˇc . . . . . . . . . . . .
6.4 Prevedba 0-1 nahrbtnika na najcenejˇse poti . . . . . . . . . . . . .
6.5 Povzetek osnovnih pojmov . . . . . . . . . . . . . . . . . . . . . . .
6.6 Naloge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
131
131
132
140
141
149
151
153
154
7 SESTOPANJE
7.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2 Problem skakaˇcevega obhoda . . . . . . . . . . . . . .
7.3 Problem osmih dam . . . . . . . . . . . . . . . . . . .
7.4 Problem trdnih zakonov . . . . . . . . . . . . . . . . .
7.5 Naˇcini za omejevanje pretiranega razraˇsˇcanja iskalnega
7.6 Povzetek osnovnih pojmov . . . . . . . . . . . . . . . .
7.7 Naloge . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
drevesa
. . . . .
. . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
157
157
158
161
164
166
173
174
8 ISKANJE PO ZNAKOVNIH ZAPOREDJIH
8.1 Navadni algoritem za iskanje po znakovnih zaporedjih
8.2 Knuth-Morris-Prattov algoritem . . . . . . . . . . . .
8.3 Boyer in Mooreov algoritem . . . . . . . . . . . . . . .
8.4 Povzetek osnovnih pojmov . . . . . . . . . . . . . . . .
8.5 Naloge . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
177
177
178
181
185
185
9 VZPOREDNI ALGORITMI
9.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . .
9.2 Metoda prestavljanja kazalcev . . . . . . . . . . .
9.3 Asociativni produkt zaˇcetnih elementov seznama
9.4 Izraˇcun globine vozliˇsˇc dvojiˇskega drevesa . . . .
9.5 Povzetek osnovnih pojmov . . . . . . . . . . . . .
9.6 Naloge . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
187
187
189
191
193
195
195
ˇ
A KRATEK PRIROCNIK
JEZIKA OBERON-2
A.1 Uvod . . . . . . . . . . . . . . . . . . . . . . . . .
A.2 Sintaksa . . . . . . . . . . . . . . . . . . . . . . .
A.3 Osnovni elementi jezika ter njihova predstavitev .
A.4 Deklaracije ter pravila o veljavnosti objektov . .
A.5 Deklaracije konstant . . . . . . . . . . . . . . . .
A.6 Deklaracije tipov . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
197
197
197
198
199
200
200
vi
KAZALO
A.6.1 Osnovni tipi . . . . . . . . . . . . . . . . . .
A.6.2 Tabelariˇcni tipi . . . . . . . . . . . . . . . .
A.6.3 Tipi zapisov . . . . . . . . . . . . . . . . . .
A.6.4 Tipi kazalcev . . . . . . . . . . . . . . . . .
A.6.5 Tipi procedur . . . . . . . . . . . . . . . . .
A.7 Deklaracije spremenljivk . . . . . . . . . . . . . . .
A.8 Izrazi . . . . . . . . . . . . . . . . . . . . . . . . . .
A.8.1 Operandi . . . . . . . . . . . . . . . . . . .
A.8.2 Operatorji . . . . . . . . . . . . . . . . . . .
A.9 Stavki . . . . . . . . . . . . . . . . . . . . . . . . .
A.9.1 Prirejanje . . . . . . . . . . . . . . . . . . .
A.9.2 Klici procedur . . . . . . . . . . . . . . . .
A.9.3 Stavˇcna zaporedja . . . . . . . . . . . . . .
A.9.4 Pogojni stavki . . . . . . . . . . . . . . . .
A.9.5 Izbirni stavek . . . . . . . . . . . . . . . . .
A.9.6 Stavek While . . . . . . . . . . . . . . . . .
A.9.7 Stavek Repeat . . . . . . . . . . . . . . . .
A.9.8 Stavek For . . . . . . . . . . . . . . . . . .
A.9.9 Stavek Loop . . . . . . . . . . . . . . . . . .
A.9.10 Stavka Return ter Exit . . . . . . . . . . . .
A.9.11 Stavek With . . . . . . . . . . . . . . . . .
A.10 Deklaracije procedur . . . . . . . . . . . . . . . . .
A.10.1 Formalni paramteri . . . . . . . . . . . . . .
A.10.2 Procedure, ki so pridruˇzene tipom . . . . .
A.10.3 Vnaprej deklarirane procedure . . . . . . .
A.11 Moduli . . . . . . . . . . . . . . . . . . . . . . . . .
A.12 Definicije pojmov . . . . . . . . . . . . . . . . . . .
A.12.1 Skladnost seznamov formalnih parametrov .
A.13 Sintaksa jezika Oberon-2 . . . . . . . . . . . . . . .
A.14 Modul SYSTEM . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
201
201
202
203
203
203
204
204
205
207
207
208
208
208
209
209
209
210
210
211
211
211
212
214
215
216
218
220
220
222
ˇ
B PREDIKATNI RACUN
PRVEGA REDA
225
B.1 Dodatni primeri uporabe predikatnega raˇcuna . . . . . . . . . . . . . . 229
Literatura
231
Stvarno kazalo
233
PREDGOVOR
Predgovor k prvi izdaji
Priˇcujoˇca knjiga vsebuje snov, ki je na dodiplomskem ˇstudiju raˇcunalniˇstva in informatike na Fakulteti za raˇcunalniˇstvo in informatiko Univerze v Ljubljani zajeta
v predmetu Algoritmi in podatkovne strukture II. Snov obsega nekatere standardne
algoritme, ki jih mora poznati vsak strokovnjak s podroˇcja raˇcunalniˇstva, kakor tudi
nekatere obiˇcajne metode in naˇcela zasnove algoritmov.
Knjiga se zaˇcne s poglavjem “Algoritmi”, ki je namenjeno osnovnim pojmom ter
kratkemu pregledu podroˇcij preverjanja pravilnosti in ustavljanja, kakor tudi ocenjevanja porabe ˇcasa in prostora. Sledi poglavje o urejanju, ki obravnava osnovne
metode urejanja tabel in datotek, od ostalih poglavij pa se razlikuje po tem, da
je prisoten nekoliko veˇcji poudarek na tehniki programiranja kot v drugih poglavjih. Naslednje poglavje je namenjeno metodi rekurzivnega razcepa, obravnava pa dva
tipiˇcna problema, ki ju reˇsujemo na ta naˇcin, in sicer mnoˇzenje matrik po Strassenu in
izraˇcun diskretne Fourierjeve transformacije. Posebnost tega poglavja je, da zahteva
doloˇceno matematiˇcno predizobrazbo (nekaj linearne algebre in nekaj elementarnih
dejstev o obiˇcajnih matematiˇcnih strukturah). 4. poglavje obravnava tim. “poˇzreˇsno
metodo” zasnove algoritmov za optimizacijske probleme na primeru dveh enostavnih
problemov. 5. poglavje je namenjeno problemu maksimalnega pretoka skozi omreˇzje
in linearnemu programiranju. Linearno programiranje obravnavamo na poenostavljen naˇcin z namenom, da prikaˇzemo osnovno idejo simpleksnega algoritma in brez
obravnave doloˇcenih zapletov, do katerih lahko pride v praktiˇcnih primerih (npr. degeneriranost matrike problema). Kljub temu pa se tudi v tem poglavju seveda nismo
mogli izogniti doloˇcenemu matematiˇcnemu predznanju iz linearne algebre. 6. poglavje
obravnava metodo dinamiˇcnega programiranja na primeru problema 0-1 nahrbtnika
in najcenejˇsih poti v grafu. 7. poglavje je namenjeno sestopanju in tehnikam omejevanja velikosti iskalnega drevesa. 8. poglavje obravnava dva uˇcinkovita algoritma
za iskanje po znakovnih zaporedjih, zadnje, 9. poglavje pa predstavlja kratek uvod
v vzporedno raˇcunanje na primeru nekaj tipiˇcnih problemov, ki jih je moˇzno na ta
naˇcin uˇcinkovito reˇsevati.
Priˇcujoˇca knjiga seveda ni nastala iz niˇc in se naslanja na izredno obseˇzno in
raznoliko literaturo, ki danes pokriva podroˇcje algoritmov in podatkovnih struktur.
Seveda sem nekatera dela veˇckrat uporabljal in med njimi bi na prvem mestu omenil
delo Cormen in dr. [5], ki je zelo izˇcrpno in pokriva tako rekoˇc vsa podroˇcja algoˇ
ritmov in podatkovnih struktur. Ceprav
je kot celota nekoliko prezahtevno za naˇse
vii
viii
PREDGOVOR
potrebe, sem se pri mnogih vpraˇsanjih zgledoval prav po njem. Nadalje bi omenil
danes ˇze klasiˇcno delo Aho in dr. [1], ki je prav tako zelo izˇcrpno, vendar podobno kot
predhodno delo nekoliko prezahtevno. V poglavju o urejanju kakor tudi pri obravnavi preverjanja pravilnosti sem se v mnogoˇcem zgledoval po delih Niklausa Wirtha
[16, 20], ki so pred ˇcasom izˇsla tudi v domaˇcem prevodu [17, 19]. Seveda se je do
danes nabralo tudi nekaj domaˇce literature in bi lahko omenil poleg ˇze omenjenih
prevodov Wirthovih del ˇse deli Kozak [10] in Kononenko [9].
Na koncu seveda gre zahvala vsem, ki so kakorkoli pripomogli temu, da je delo
nastalo. Najprej bi omenil vse sodelavce in kolege, ki so s pripombami in nasveti
izboljˇsali izbiro ali podajanje snovi. Po abecednem redu so to Tomaˇz Dobravec, Viljan
Mahniˇc, Igor Roˇzanc in Boˇstjan Slivnik. Nato bi omenil strokovnega in jezikovnega
recenzenta, ki sta s pozornim branjem odkrila marsikateri spodrsljaj in mi z nasveti
pomagala, da sem besedilo izboljˇsal. In konˇcno (vendar ne nazadnje) gre zahvala ˇzeni
Marjetki in najinim otrokom, ki so me podpirali in ustvarili vzduˇsje, v katerem je delo
nastajalo.
Ljubljana, januarja 1998
Boˇstjan Vilfan
Predgovor k drugi izdaji
V drugi izdaji so nastale naslednje spremembe in dopolnitve:
1. Odpravljene so bile tipkarske in druge manjˇse napake.
2. Odpravljene so bile vse odkrite napake v programih, ki se uporabljajo kot primeri.
3. Veˇc krajˇsih drugih dopolnitev in izboljˇsav.
4. V razdelku 2.2.7 je popravljen del, ki se nanaˇsa na spodnjo mejo za ˇcas urejanja.
5. Spremenjen je bil razdelek 3.3.6 o iterativnem algoritmu za diskretno Fourierjevo
transformacijo.
6. Pojavil se je nov Dodatek A, ki podaja kratko informacijo o jeziku Oberon-2.
Upam, da bodo naˇstete dopolnitve ali popravki prispevali k boljˇsi razumljivosti
besedila.
Ljubljana, januarja 2002
Boˇstjan Vilfan
Predgovor k spletni izdaji
Uˇcbenik ni veˇc v uporabi, objavljam pa ga za primer, da bi koga zanimal. Med
pripravo za objavo na spletu sem odpravil neke dodatne napake.
Ljubljana, januar 2011
Boˇstjan Vilfan
Poglavje 1
ALGORITMI
1.1
Pojem algoritma
Od bralca priˇcakujemo, da je seznanjen s pojmoma raˇcunalnik in raˇcunalniˇski program
ter da je morebiti ˇze napisal in preizkusil kakˇsen program.
Ne da bi se spuˇsˇcali v pretirane formalnosti, definiramo algoritem kot program,
ki teˇce na nekem raˇcunalniku (ki je bodisi resniˇcen ali namiˇsljen) in na zaˇcetku dobi
doloˇcene podatke, na koncu svojega delovanja pa sporoˇci rezultat. Podatkom algoritma
pravimo tudi vhod , rezultatu pa izhod . Pomembno je, da je rezultat pri vseh podatkih
natanˇcno doloˇcen. Po tem se algoritem razlikuje od sploˇsnejˇse definicije programa, oziroma recepta za izraˇcun, ki ima pri doloˇcenih vhodih lahko tudi nedefiniran rezultat.
Glede na to, da je raˇcunalniˇskih modelov izredno veliko (npr. Turingovi stroji, konˇcni avtomati, programi
Pomnilnik
v vseh mogoˇcih programskih jezikih . . . ) imamo tudi
najrazliˇcnejˇse predstavitve algoritmov.
n−1
Ker imamo za konˇcni cilj neka spoznanja o algon−2
ritmih, ki naj bi bila uporabna v praktiˇcnih primerih,
..
je primerno, da kot osnovo za predstavitev algorit.
mov vzamemo stroj, ki je sicer namiˇsljen (abstrakProcesor
2
ten) v pomenu, da predstavlja neko poenostavitev re1
sniˇcnih strojev, vendar kljub temu dovolj soroden resniˇcnim strojem, da omogoˇca stvarno razmiˇsljanje. V
0
teoretiˇcnih raziskavah se je kot takˇsen stroj uveljavil stroj z enakopravnim dosegom do pomnilnika, za Slika 1.1: Raˇcunalnik vrste
katerega uporabljamo angleˇsko kratico RAM1 . Stroj RAM
je prikazan na sliki 1.1 in je sestavljen iz procesorja,
ki je zmoˇzen izvajanja obiˇcajnih operacij (aritmetiˇcne
1 Kratica za angleˇ
ski izraz Random Access Machine, ki se veˇ
cinoma dobesedno prevaja kot stroj
z nakljuˇ
cnim dosegom do pomnilnika, vendar sem na podlagi opisa stroja raje izbral drug izraz.
1
2
POGLAVJE 1. ALGORITMI
operacije, operacije nad biti, operacije, ki preusmerjajo izraˇcun), in pomnilnika, ˇcigar
celice so vse enako dosegljive in lahko vsebujejo podatke poljubne velikosti. Procesor izvaja operacije eno za drugo (zaporedno), vsaka operacija pa traja eno ˇcasovno
enoto. Poenostavitev stvarnih strojev, ki je prisotna pri stroju RAM, je, da ne vsebuje
mnogih komponent stvarnih raˇcunalnikov (npr. vhodnih in izhodnih enot) in da ne
upoˇsteva omejene dolˇzine njihove pomnilniˇske besede. Na ta naˇcin se izogibamo podrobnostim programiranja vhodnih in izhodnih enot in zanemarjamo probleme, ki se
pojavljajo v zvezi z zaokroˇzitvami ˇstevilˇcnih koliˇcin. Ker pa ta vpraˇsanja niso predmet
ˇ pri opisovanju algoritmov
naˇsega zanimanja, s tem le pridobimo na preglednosti. Ce
uporabljamo stroj RAM, lahko precej natanˇcno in stvarno ocenjujemo porabo ˇcasa
(tako, da ˇstejemo izvrˇsene ukaze) in prostora za podatke (tako, da ocenjujemo ˇstevilo
uporabljenih celic pomnilnika), vendar postanejo za naˇse potrebe opisi algoritmov
razmeroma nepregledni. Zato ponavadi algoritme opisujemo v nekem viˇsjem jeziku in
si predstavljamo RAM le kot “ciljni stroj”, v katerega prevajamo opise, ki so zapisani
v viˇsjem jeziku. Torej je vloga stroja RAM le, da nam prikliˇce v spomin osnovne
lastnosti algoritmov, ki jih privzemamo pri naˇsih razmiˇsljanjih: zaporedno izvajanje
ukazov in enaka dosegljivost pomnilniˇskih celic.
V podobnih knjigah, kot je priˇcujoˇca, se zelo pogosto uporablja zapis za algoritme,
ki je nekoliko prirejen jezik algolskega tipa (npr. Algol, Pascal, Modula-2 ipd.) v
smislu, da se ne drˇzi strogo jezikovne sintakse, kajti namenjen je ˇcloveˇskemu bralcu in
ne izvajanju na raˇcunalniku. V tej knjigi pa bomo glede zapisa algoritmov nekoliko
neenotni: v poglavjih, ki so zanimiva s staliˇsˇca tehnike programiranja, bomo algoritme
predstavljali kot podrobno zapisane programe v jeziku Oberon-2 (gl. npr. Reiser in
Wirth [14] ali Mahniˇc [4]), v drugih pa bomo marsikatero podrobnost programiranja
zanemarili. Na sliki 1.2 je do zadnje podrobnosti zapisan algoritem dvojiˇskega iskanja,
ki ga bomo uporabili za prikazovanje nekaterih lastnosti algoritmov in ki vsebuje neko
posebnost glede na obiˇcajno obliko. Zanimiv je zato, ker uporablja pogojni stavek z
dvema izidoma primerjanja, ≤, >, namesto obiˇcajnih treh, <, =, >, (gl. tudi Wirth
[18, 1. del, 9, str. 38]). Res je, da pri taki obliki lahko pride do odveˇcnega raˇcunanja
v primeru, ko je a[mid] = x v vrstici 12 resniˇcno (ker se izvajanje zanke nadaljuje do
trenutka, ko vrednost l postane veˇcja od r, oziroma, ko se vrednost r spusti pod l).
Vendar je v povpreˇcju prikazana oblika le hitrejˇsa, ker veˇcinoma velja a[mid] 6= x in
prihranimo eno primerjanje.
Glede izbire jezika Oberon za predstavitev programov je potrebno priznati, da
je bila s staliˇsˇca kasnejˇsega razvoja morda manj utemeljena, kajti jezik se v praksi
ni ˇsirˇse uveljavil. Vendar, ker ima izredno preprosto zgradbo, menim, da bralcu
ne bo teˇzko razumeti programov, ki so zapisani z njim, v pomoˇc pa mu je tudi
kratek dodatek z opisom jezika (Dodatek A). Vsi programi so preizkuˇseni s prevajalnikom Native XDS-X86[6], na voljo pa so tudi v elektronski obliki na streˇzniku
zaphod.fri.uni-lj.si/~vilfan.
Priˇcujoˇca knjiga ima veˇc ciljev. Prvi je zbrati nekaj koristnih algoritmov, ki jih
vsak strokovnjak za raˇcunalniˇstvo mora poznati. Drugi je opisati najpogostejˇse prijeme, ki jih uporabljamo pri sestavljanju algoritmov. Tretji je seznaniti bralca z
osnovnimi pojmi o preverjanju pravilnosti algoritmov in ˇcetrti, ne najmanj pomem-
1.1. POJEM ALGORITMA
1
2
3
4
5
6
7
8
9
10
11
12
13
15
15
16
17
19
19
3
PROCEDURE BinSearch(VAR a:ARRAY OF INTEGER;
x ,n:INTEGER):INTEGER;
(∗ a je urejena tabela, kjer ima prvi element indeks 1 (element
a[0] ima nedefinirano vrednost), x je iskani element, n ≥ 0 pa
ˇstevilo elementov v tabeli; rezultat je indeks iskanega elementa,
ˇce je x prisoten v tabeli ali pa negativna vrednost indeksa v
tabeli, kamor bi x sodil, ˇce elementa v tabeli ni ∗)
VAR l ,mid ,r :INTEGER;
BEGIN l :=1; r :=n;
WHILE l <=r DO
mid :=(l +r )DIV 2;
IF a[mid ]>x THEN r :=mid −1
ELSE l :=mid +1
END
END ;
IF (r >0) & (a[r ]=x ) THEN RETURN r
ELSE RETURN −l
END
END BinSearch;
Slika 1.2: Algoritem dvojiˇskega iskanja
ben, je prikazati razliˇcne naˇcine za ocenjevanje porabe raˇcunskih virov, med katerimi
sta najvaˇznejˇsa ˇcas (ki ga nek algoritem porabi) in prostor (spomin, ki ga algoritem
skupaj s svojimi podatki zaseda medtem, ko se izvaja).
Preden pa se lotimo vpraˇsanj, ki smo jih pravkar naˇsteli, moramo opisati pojem,
ki nam bo omogoˇcil, da delovanje algoritma analiziramo. Rekli mu bomo sled programa. Le-ta je prirejena nekemu programu in konkretnim vhodnim podatkom, je pa
preprosto tabela z vrsticami, ki ustrezajo izbranim mestom v programu v ˇcasovnih
trenutkih, ki si sledijo, in stolpci, ki vsebujejo vrednosti izbranih spremenljivk. Na
primer sled algoritma s slike 1.2 pri vhodnih podatkih a = (9, 13, 27, 32, 41, 48) in
x = 18 je prikazana na sl. 1.3a. V vrsticah so prikazane vrednosti spremenljivk na
koncu vrstic 9, 12, 13 in 16 oziroma 17. Vˇcasih nas zanima le zaporedje stavkov, ki
se izvajajo (na primer zato, da preˇstejemo ˇstevilo stavkov med izraˇcunom). V takem
primeru ima sled eno samo vrednost v vrstici — ˇstevilko vrstice stavka. Vˇcasih je smiselno opazovati obnaˇsanje programa pri veˇc vhodih in namesto zaporedja vrednosti
v zaporednih ˇcasovnih trenutkih imamo opravka z drevesom sledi. Na primer drevo
sledi algoritma s slike 1.2 pri vhodnih podatkih a = (9, 13, 27, 32, 41, 48) in x = 18 ter
a = (9, 13, 27, 32, 41, 48) in x = 41, ko nas zanima le zaporedje stavkov, ki se izvaja,
ˇ sestavljamo drevo sledi in nas zanima veˇc podatkov
je prikazano na sliki 1.3b. Ce
(vrednost veˇc spremenljivk), vsebuje vsako vozliˇsˇce drevesa vse potrebne podatke.
4
POGLAVJE 1. ALGORITMI
9
vrstica
9
12
13
13
17
l mid r
1 ? 6
1 3 2
2 1 2
3 2 2
3 2 2
(a) Sled algoritma dvojiˇskega iskanja (konec
vrstic 9, 12, 13, 16 in 17) pri podatkih a =
(9, 13, 27, 32, 41, 48) in x = 18
12
13
13
13
13
12
17
16
(b) Drevo sledi algoritma dvojiˇskega iskanja pri
podatkih a = (9, 13, 27, 32, 41, 48) in x = 18
(leva veja) ter a = (9, 13, 27, 32, 41, 48) in x = 41
(desna veja)
Slika 1.3: Sled in drevo sledi.
1
2
3
4
5
6
7
8
PROCEDURE Multiply(x ,y:INTEGER):INTEGER;
(∗ x > 0; vrednost je produkt x in y ∗)
VAR u,z :INTEGER;
BEGIN z :=0; u:=x ;
REPEAT z :=z +y; u:=u−1;
UNTIL u=0;
RETURN z
END Multiply;
Slika 1.4: Mnoˇzenje dveh ˇstevil
1.2
Preverjanje pravilnosti
Ko smo sestavili algoritem, je naprej potrebno preveriti, ali ima vse ˇzelene lastnosti,
med katerimi je osnovna, da algoritem resniˇcno dela tisto, kar smo si zamislili, oziroma, da je pravilen. Za ugotavljanje tega sta se izoblikovala dva sploˇsna pristopa:
preverjanje pravilnosti s poskusi na konkretnih podatkih in preverjanje pravilnosti z
logiˇcno analizo.
1.2.1
Preverjanje pravilnosti s poskusi
Ponavadi opravljamo poskuse s programom tako, da sestavljamo sledi delovanja programa pri doloˇcenih vhodnih podatkih. V tem primeru privzemamo, da “vemo”,
kaj mora program poˇceti in lahko z analizo sledi pri posameznih vhodnih podatkih
ˇ sestavimo drevo sledi, lahko naenkrat preverimo
ugotovimo, ali deluje pravilno. Ce
algoritem pri veˇc vhodnih podatkih. Kot primer lahko rabi sl. 1.3b, kjer smo preverili
pravilno delovanje programa pri vhodnih podatkih a = (9, 13, 27, 32, 41, 48) in x = 18
5
1.2. PREVERJANJE PRAVILNOSTI
vrstica
4
5
5
5
5
7
u
4
3
2
1
0
0
z
0
7
14
21
28
28
Slika 1.5: Sled algoritma za mnoˇzenje pri podatkih x = 4, y = 7
ˇ pa ta metoda kot metoda preverjanja pravil(leva veja) ter x = 41 (desna veja). Zal
nosti programa pri vseh vhodih odpove, kadar je moˇznih izidov pri algoritmu toliko,
da njihovo sledenje presega praktiˇcne moˇznosti. Verjetno je algoritem na sl. 1.2 eden
od redkih, ki ga je ˇse moˇzno popolnoma preveriti (z nekoliko logiˇcnega sklepanja) pri
praktiˇcnih velikostih problema (gl. nalogo 1). Povsem drugaˇcen problem pa predstavlja preverjanje pravilnosti programa za mnoˇzenje dveh ˇstevil, ki je prikazan na sl.
1.4. Prikazani program bi bil koristen v primeru, ko imamo raˇcunalnik, ki pozna kot
elementarni operaciji samo seˇstevanje in odˇstevanje, ne pa mnoˇzenja. Sled algoritma,
na podlagi katere sklepamo o njegovi pravilnosti pri podatkih x = 4 in y = 7, je priˇ pa bi se hoteli prepriˇcati o njegovi pravilnosti pri vseh moˇznih
kazana na sl. 1.5. Ce
parih 16-bitnih ˇstevil x in y, bi morali sestaviti 232 sledi, kar je praktiˇcno nemogoˇce.
Zato je potrebno uporabiti popolnoma drugaˇcen pristop.
1.2.2
Logiˇ
cno dokazovanje pravilnosti
ˇ privzamemo, da ima vsak algoritem nek rezultat, lahko istovetimo nalogo alCe
goritma z neko ˇzeleno lastnostjo rezultata. Le-to pa lahko opiˇsemo z neko logiˇcno
trditvijo. Ker pa ima tudi sam algoritem (oziroma njegov opis) doloˇcene lastnosti,
lahko poskuˇsamo z logiˇcnim sklepanjem ugotoviti, ali iz lastnosti algoritma nujno
sledi ˇzelena lastnost rezultata. Vendar je to misel laˇze izreˇci, kot jo uresniˇciti! Ideja
logiˇcnega dokazovanja pravilnosti je, da lastnost rezultata in prav tako lastnosti samega algoritma izrazimo s trditvami (stavki) v nekem jeziku formalne logike in nato
dokaˇzemo, da iz lastnosti algoritma ter kot posledica ustavitve algoritma nujno sledi
lastnost rezultata. Ko se strogo drˇzimo opisane metodologije ali ko za njeno realizacijo uporabljamo nek programski pripomoˇcek, uporabljamo za zapisovanje trditev,
ki se nanaˇsajo na lastnosti algoritma, dobro znani predikatni raˇcun prvega reda ali
kakˇsen drug logiˇcni formalizem. V dodatku B je zbranih nekaj osnovnih dejstev v
zvezi s predikatnim raˇcunom prvega reda, ˇceprav v nadaljevanju uporabljamo le neˇ pa tehniko dokazovanja pravilnosti uporabljamo “roˇcno”,
kaj najelementarnejˇsih. Ce
ponavadi uporabljamo obiˇcajno neformalno sklepanje, ki ima prednost, da je preglednejˇse in bolj jedrnato, vendar je seveda podvrˇzeno napakam.
6
POGLAVJE 1. ALGORITMI
z := 0
u := x
Vhod
Vhod
vhodna
podatka:
vhodna
podatka:
x, y
z := z + y
u := u − 1
−
q := 0
r := x
r≥y
x, y
−
+
u=0
+
rezultat: z
q := q + 1
r := r − y
Izhod
(a) Mnoˇ
zenje dveh ˇstevil
Izhod
rezultat: q, r
(b) Celoˇstevilˇ
cno deljenje
Slika 1.6: Dva diagrama poteka
1.2.3
Dokazovanje pravilnosti programov, ki so predstavljeni
z diagrami poteka
Prvi primer programskega zapisa, za katerega bomo opisali postopek preverjanja pravilnosti, so diagrami poteka. Diagram poteka je usmerjen graf z enim vhodom in
morebiti veˇc izhodi, ki ima tri vrste vozliˇsˇc: ena so pravokotne ˇskatle, ki vsebujejo
prirejanja (x := f (. . .)), druga romboidne ˇskatle, ki vsebujejo preizkuse oz. predikate (P (x1 , x2 , . . .)), tretja pa so preprosto stekaliˇsˇca poti. Vhod v diagram poteka
nakaˇzemo s puˇsˇcico, ki nima izvora, izhod pa s puˇsˇcico, ki nima ponora. Na sliki 1.6
vidimo dva primera, ki vsebujeta vse tri vrste vozliˇsˇc. Vhodni podatki so vrednosti
spremenljivk, ki se ne pojavljajo na levih straneh prirejanj, izhodni podatki pa so
vrednosti nekaterih izbranih spremenljivk. Za vse spremenljivke privzemamo, da so
celoˇstevilˇcne.
Pri logiˇcnem dokazovanju pravilnosti programov izhajamo iz pogojev, ki jih morajo
izpolnjevati vhodni podatki, in lastnosti, ki doloˇca rezultat izraˇcuna. Na primer
program na sliki 1.6a je doloˇcen z vhodnim pogojem, x > 0 ter izhodno lastnostjo,
z = x ∗ y, ki sta pripisana toˇckama “Vhod” in “Izhod”, po vrsti. Podobno je vhodni
pogoj programa 1.6b x ≥ 0, y > 0, izhodna lastnost pa x = y · q + r ∧ 0 ≤ r < y.
Pri zapisovanju logiˇcnih trditev, ki ustrezajo tem in podobnim pogojem, se ne
bomo popolnoma drˇzali pravil o zapisu predikatnega raˇcuna ali drugih virih, ki so
opisana v dodatku B, saj si bralec vedno lahko predstavlja prevod iz nekoliko ohlapnejˇsega zapisa v povsem strogi zapis. Predvsem se ne bomo omejevali na logiˇcna
7
1.2. PREVERJANJE PRAVILNOSTI
S1
Q1
S2
Sn
S1
. . . Qn
Q2
0 ≤ x < 10
P
Q1 ⊃ P ∧
Q2 ⊃ P ∧
..
.
Qn ⊃ P
T
(a) Pravilo
S2
−10 < x < 10
−10 < x < 0
T
(b) Primer
Slika 1.8: Pravilo za stekaliˇsˇce poti in primer uporabe
operatorja ⊃ in ¬, temveˇc bomo uporabljali tiste logiˇcne operatorje, ki so najprimernejˇsi za zapis trditve, ki nas zanima (na primer konjunkcija ∧ in disjunkcija, ∨).
Nadalje bomo pogosto nadomestili kakˇsen simbol z bolj primernim (in morda manj
vsiljivim). Na primer znak za konjunkcijo bomo pogosto nadomestili z vejico. Primer:
namesto x > 0 ∧ y > 0 bomo pisali x > 0, y > 0. In konˇcno lahko omenimo, da bomo
pogosto za logiˇcno implikacijo namesto znaka ⊃ uporabili znak ⇒.
Postopek dokazovanja pravilnosti priˇcnemo tako,
da vsakemu vozliˇsˇcu pripiˇsemo nabor trditev, in sicer
P (antecedens)
po eno vsaki vhodni povezavi in eno izhodni povezavi. Trditvam, ki so pripisane vhodnim povezavam,
pravimo antecedensi stavka (oziroma ˇskatle), tistim,
S
ki so pripisane izhodnim povezavam, pa pravimo konsekvensi stavkov (gl. sliko 1.7). Antecedensi in konQ (konsekvens)
sekvens morajo biti v povsem doloˇceni medsebojni
zvezi, ki je predpisana z aksiomom, ki pripada vrsti Slika 1.7: Logiˇcne trditve privozliˇsˇca. Aksiomi za vse naˇstete vrste vozliˇsˇc, kakor rejene nekemu stavku
tudi primeri njihove uporabe, so prikazani na slikah
1.8, 1.9 in 1.10.
Aksiom za stekaliˇsˇce poti [slika 1.8a] zatrjuje, da mora v stekaliˇsˇcu poti vsak
antecedens imeti za posledico konsekvens, kar je tudi razumljivo. Namreˇc, ˇce pred
stekaliˇsˇcem velja neka trditev, mora veljati tudi po stekaliˇsˇcu.
Aksiom za pogojni stavek [slika 1.9a] pravi, ˇce je antecedens pogojnega stavka
trditev P , je konsekvens, ki je pripisan izpolnjenemu pogoju B, P ∧ B (razumljivo,
saj v primeru, ko B ne bi bilo resniˇcno, program ne bi priˇsel do te toˇcke), konsekvens,
ki je pripisan neizpolnjenemu pogoju B, pa je P ∧ ¬B.
Aksiom za prirejanje [slika 1.10a] predpisuje, da v primeru, ko je konsekvens prirejanja trditev P in ko le-ta vsebuje prosto spremenljivko2 x, prirejanje pa ima obliko
x := f (. . .), je antecedens prirejanja pridobljen iz konsekvensa tako, da zamenjamo
2 Spremenljivka
x je prosta v primeru, ko ni v obmoˇ
cju veljavnosti nekega kvantifikatorja, ∃ ali ∀.
8
POGLAVJE 1. ALGORITMI
−10 < x < 10
P
+
+
−
−
x<0
B
P ∧ ¬B
P ∧B
0 ≤ x < 10
−10 < x < 0
(a) Pravilo
(b) Primer
Slika 1.9: Pravilo za pogojni stavek in primer uporabe
Pwv
x + y = 10
z := x + y
v := w
P
(a) Pravilo
z = 10
(b) Primer
Slika 1.10: Pravilo za prirejanje s primerom
vse proste primerke spremenljivke x z desno stranjo prirejanja. Na ta naˇcin priˇ nekoliko pomislimo, izraˇza to pravilo
dobljeni antecedens oznaˇcujemo z Pfx(...) . Ce
natanko uˇcinek prirejanja, kajti po prirejanju je povsod moˇzno desno stran prirejanja
nadomestiti z levo stranjo.
Celotni postopek je prikazan na primeru programa za mnoˇzenje dveh ˇstevil (slika
1.11). Na tem mestu si bomo omenjeni program nekoliko bolj podrobno ogledali
ter izpostavili nekatere znaˇcilnosti. Vhodni pogoj x > 0 nastopa implicitno v vseh
trditvah, ne zapisujemo pa ga zato, ker se spremenljivki x in y med izraˇcunom ne
spreminjata. Prav tako ne zapisujemo doloˇcenih oˇcitnih tavtologij, ki predstavljajo
antecedense nekaterih prirejanj (gl. nalogo 2). V edinem stekaliˇsˇcu poti je eden od
antecedensov z = 0, u = x, medtem ko je konsekvens z + u ∗ y = x ∗ y, u > 0. Oˇcitno
je, da ima resniˇcnost prve trditve, v povezavi z implicitnim pogojem x > 0, posledico
resniˇcnost trditve z + u ∗ y = x ∗ y, u > 0, kar pa je v skladu z aksiomom za stekaliˇsˇca.
Nadalje, ˇce antecedens druge ˇskatle s prirejanji, z + u ∗ y = x ∗ y, u > 0, prepiˇsemo
v obliko z + y + (u − 1) ∗ y = x ∗ y, u − 1 ≥ 0, preverjanje aksioma za prirejanje
ne predstavlja posebnih teˇzav. In konˇcno je negativni izhod iz pogojnega stavka, na
podlagi aksioma za pogojni stavek opremljen s trditvijo z + u ∗ y = x ∗ y, u ≥ 0, u 6= 0,
kar ima zaradi u ≥ 0 na vhodu v pogojno ˇskatlo za posledico z + u ∗ y = x ∗ y, u > 0,
kar pa je enako konsekvensu stekaliˇsˇca. Ker pa vemo, da vedno velja P ⊃ P , smo
tako preverili, da so aksiomi za posamezne vrste vozliˇsˇc povsod veljavni in lahko
9
1.2. PREVERJANJE PRAVILNOSTI
x>0
z := 0
u := x
z = 0, u = x
z + u ∗ y = x ∗ y, u > 0
z := z + y
u := u − 1
z + u ∗ y = x ∗ y, u ≥ 0
−
u=0
+
z = x ∗ y, u = 0
Slika 1.11: Program za mnoˇzenje, opremljen s trditvami
zatrjujemo, da je pravilnost programa na sliki 1.11 dokazana.
Na podoben naˇcin je moˇzno analizirati program na sliki 1.12 za izraˇcun kvocienta
in ostanka po deljenju dveh pozitivnih celih ˇstevil.
Osnovni element, ki oteˇzuje doloˇcanje trditev prirejenih programu, so zanke. Ko
imamo opravka z linearnim zaporedjem vozliˇsˇc (ˇskatel), je obiˇcajno moˇzno na enostaven naˇcin uporabiti aksiome in doloˇciti manjkajoˇce trditve na podlagi bodisi zaˇcetne
(vhodne) trditve ali pa konˇcne (izhodne) trditve. V primeru pa, ko imamo opravka
z zanko, smo pri izbiri trditev omejeni s pogojem, da mora zadnja trditev imeti za
logiˇcno posledico prvo trditev (gl. sliko 1.13). V takem primeru postopamo tako, kot
da bi bila pred prvim vozliˇsˇcem zanka prerezana, in imamo nato opravka z linearnim
zaporedjem vozliˇsˇc. Ko izberemo trditve za vhode in izhode vseh vozliˇsˇc, preverimo,
ˇ to ne velja, postopek ponovimo. Pri zanki ni moˇzno dati preproali velja Cn ⊃ A1 . Ce
stega recepta za izbiro prve trditve, od katere je bistveno odvisna uspeˇsnost postopka
generiranja ostalih trditev v skladu z aksiomi. Prav zaradi potrebe po iznajdljivosti,
ki je tu prisotna, je zaˇcetna trditev pri zanki nujni del programove dokumentacije in
ponavadi bistveno pripomore k njegovi razumljivosti. Tej trditvi, ki je postavljena na
zaˇcetek zanke in ki je veljavna ne glede na to, kolikokrat ponovimo izvajanje zankinega
jedra, pravimo zanˇcna invarianta.
Na podoben naˇcin, kot lahko v predikatnem raˇcunu zdruˇzujemo veˇc aksiomov v
nove trditve s pravili sklepanja, lahko tudi pri preverjanju programov kombiniramo
ˇskatle s trditvami v veˇcje sklope. Primeren zgled so prav zanke. Prikazali bomo dve
pravili sklepanja, ki nam omogoˇcata, da pridobimo antecedensa in konsekvensa dveh
vrst zank. Prvo se nanaˇsa na zanko vrste WHILE in pravi, da ko je izpolnjen pogoj
na sliki 1.14a (torej, ko je podan S z antecedensom P ∧ B in konsekvensom P ), je
10
POGLAVJE 1. ALGORITMI
x ≥ 0, y > 0
q := 0
r := x
q = 0, r = x
x = y · q + r,
r≥0
−
r≥y
x = y · q + r,
0≤r<y
+
q := q + 1
r := r − y
x = y · (q + 1) + r − y,
r−y ≥0
Slika 1.12: Program za deljenje, opremljen s trditvami
S1
A1
Sn
C1
Cn
Ai
An
Ci
Cj
Si
Aj
Sj
Slika 1.13: Logiˇcne trditve v zanki
moˇzno sestaviti zanko na sliki 1.14b z zapisanima antecedensom in konsekvensom.
Znaˇcilno za zanko vrste REPEAT (slika 1.15) je, da zahteva dva predpogoja.
Namreˇc zanko REPEAT na sliki 1.15c si lahko predstavljamo, kot da je sestavljena iz
stavka S, ki mu sledi zanka WHILE (gl. sliko 1.15d). Prav zaradi dveh predpogojev,
ki morata biti izpolnjena za pravilno uporabo zanke, je ta zanka teˇzja za uporabo in
bolj podvrˇzena zlorabam kot zanka vrste WHILE. To trditev potrjujejo tudi empiriˇcne
izkuˇsnje.
11
1.2. PREVERJANJE PRAVILNOSTI
P
−
B
P ∧B
S
P ∧B
+
P ∧ ¬B
S
P
(a) Predpogoj
(b) Zanka
Slika 1.14: Zanka vrste WHILE
Q ∧ ¬B
P
S
S
Q
Q
(a) Predpogoj 1
(b) Predpogoj 2
P
P
S
Q
S
−
B
+
¬B
+
Q ∧ ¬B
−
Q∧B
S
Q∧B
(c) Zanka REPEAT
(d) Diagram poteka, ki je ekvivalenten diagramu na sliki (c)
Slika 1.15: Zanka vrste REPEAT
12
POGLAVJE 1. ALGORITMI
1.2.4
Dokazovanje pravilnosti programov, ki so zapisani v programskem jeziku
Tehniko iz prejˇsnjega odstavka je moˇzno brez teˇzav prirediti tudi za programe, ki
so napisani v linearnem zapisu, npr. v nekem algolskem jeziku. V tem primeru sta
antecedens in konsekvens zapisana pred in za vsakim stavkom. Najprimerneje je, da
logiˇcne trditve zapisujemo kot programske komentarje. Pravila, po katerih se morajo ravnati antecedensi in konsekvensi posameznih stavkov, so prikazana v naslednji
tabeli:
PRAVILA PREVERJANJA ZA PROGRAME, KI SO ZAPISANI V
PROGRAMSKEM JEZIKU
1. Prirejanje
(∗ Pwv ∗)v := w(∗ P ∗)
2. Sestavljeni stavek
Predpogoja:
(∗ P ∗)S1 (∗ Q ∗)
(∗ Q ∗)S2 (∗ R ∗)
Posledica:
(∗ P ∗)S1 ; S2 (∗ R ∗)
3. Pogojna stavka
Predpogoja:
(∗ P ∧ B ∗)S1 (∗ Q ∗)
(∗ P ∧ ¬B ∗)S2 (∗ Q ∗)
Posledica:
(∗ P ∗)IF B THEN S1 ELSE S2 END(∗ Q ∗)
Predpogoja:
(∗ P ∧ B ∗)S(∗ Q ∗)
(P ∧ ¬B) ⊃ Q
Posledica:
(∗ P ∗)IF B THEN S END(∗ Q ∗)
4. Zanke
Predpogoj:
(∗ P ∧ B ∗)S(∗ P ∗)
Posledica:
(∗ P ∗)WHILE B DO S END(∗ P ∧ ¬B ∗)
13
1.2. PREVERJANJE PRAVILNOSTI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PROCEDURE Multiply(x ,y:INTEGER):INTEGER;
VAR u,z :INTEGER;
BEGIN
(∗ x > 0 ∗)
z :=0; u:=x ;
(∗ z =0; u=x ∗)
(∗ z +u∗y=x ∗y, u>0 ∗)
REPEAT
z :=z +y;
u:=u−1;
UNTIL u=0;
(∗ z =x ∗y, u=0 ∗)
RETURN z
END Multiply;
Slika 1.16: Program za mnoˇzenje opremljen s trditvami
Predpogoj:
(∗ P ∗)S(∗ Q ∗)
(∗ Q ∧ ¬B ∗)S(∗ Q ∗)
Posledica:
(∗ P ∗)REPEAT S UNTIL B(∗ Q ∧ B ∗)
5. Izbirni stavek
Predpogoj:
(∗ P ∧ (i = Lk ) ∗)Sk (∗ Q ∗) pri vseh k
Posledica:
(∗ P ∗)
CASE i OF
L1 : S1 |
L2 : S2 |
..
.
Ln : Sn
END
(∗ Q ∗)
Kot primer je na sliki 1.16 prikazan program s slike 1.4, ki je popolnoma opremljen z
logiˇcnimi trditvami za preverjanje. Pri zanki vrste REPEAT sta v vlogi trditev P in
Q iz tabele na zaˇcetku tega odstavka trditvi
z + u ∗ y = x ∗ y, u > 0
ter
z + u ∗ y = x ∗ y, u ≥ 0
14
POGLAVJE 1. ALGORITMI
(po vrsti).
Za praktiˇcne potrebe so mnoge trditve, ki opisujejo lastnosti nekega programa,
odveˇcne, oziroma samoumevne. Najvaˇznejˇse trditve, brez katerih program pogosto
postane nerazumljiv, pa so pogoji, ki jih morajo izpolnjevati vhodne koliˇcine, izhodna
trditev, ki opisuje rezultat, ter zanˇcne invariante. Te trditve naj bi tudi predstavljale
ˇ se zateminimalno dokumentacijo, ki jo vsak algoritem ali program potrebuje. Ce
kamo k dokazovanju, pa veˇcinoma uporabljamo neformalno sklepanje. Kot primer
dokazovanja pravilnosti navajamo dokazovanje pravilnosti algoritma dvojiˇskega iskanja na sliki 1.2. Vhodne spremenljivke in rezultat so opisani v uvodnem komentarju
in se bomo na tem mestu predvsem ukvarjali z invarianto, ki pripada zanki v vrsticah
10–15.
Preden zanˇcno invarianto (ki je postavljena pred vrstico 10) zapiˇsemo, ugotovimo,
da za aritmetiˇcno srednjo vrednost mid velja l ≤ mid ≤ r. Zanˇcno invarianto razstavimo na 2 disjunktivna ˇclena, n = 0 in n > 0, od katerih slednji razpade na nadaljnjih
5 disjunktivnih ˇclenov:
(n = 0) ∧ (l = 1) ∧ (r = 0)∨
(n > 0) ∧ [ (l = 1) ∧ (x < a[l]) ∧ (0 ≤ r ≤ n) ∨
(r = n) ∧ (a[r] ≤ x) ∧ (1 ≤ l ≤ n + 1) ∨
(a[l] ≤ x < a[r]) ∨
(0 < r < n) ∧ (a[r] ≤ x < a[r + 1]) ∨
(1 < l < n + 1) ∧ (a[l − 1] ≤ x < a[l]) ]
(1.1)
Pred izvajanjem zanke je gotovo resniˇcen eden izmed 6 pogojev v vrsticah 1–6 v
(1.1)3 . Sedaj bomo loˇceno obravnavali vsakega izmed njih.
1. (n = 0) ∧ (l = 1) ∧ (r = 0). V tem primeru je izstopni pogoj iz zanke ¬l ≤ r
takoj resniˇcen in se jedro zanke ne izvaja, do izhoda iz procedure pa pride v
vrstici 17 z rezultatom −1, kar je pravilno.
2. (l = 1) ∧ (x < a[l]) ∧ (0 ≤ r ≤ n). V tem primeru je pogoj v 12. vrstici resniˇcen
in se vrednost r zmanjˇsa. Glede na to, da do izvajanja jedra zanke pride le
v primeru r ≥ l, l pa ima vrednost 1, je r vedno v mejah 0 ≤ r ≤ n. Pogoj
(n > 0) ∧ (l = 1) ∧ (x < a[l]) ∧ (0 ≤ r ≤ n) ostane v veljavi in s tem invarianta.
Zato tudi pri nadaljnjih izvajanjih jedra zanke ostane pogoj 2 resniˇcen in se r
zmanjˇsuje dokler ne doseˇze vrednosti 0. Takrat pride do izhoda iz zanke. Ker
je zato pogoj v vrstici 16 neresniˇcen, postane v vrstici 17 rezultat −1, kar je
pravilno.
3. (r = n) ∧ (a[r] ≤ x) ∧ (1 ≤ l ≤ n + 1). V tem primeru je pogoj v 12. vrstici
neresniˇcen in se vrednost l poveˇca. Ker do izvajanja jedra zanke pride le v
primeru l ≤ n, ostane l v mejah med 1 in n + 1. Torej ostane pogoj, ki doloˇca
ta primer, v veljavi in s tem tudi celotna invarianta. Do izhoda iz zanke pride
takrat, ko postane l = n + 1. Vrednost rezultata postane n (v vrstici 16) v
primeru a[n] = x, sicer pa −n − 1 (v vrstici 17), kar je v obeh primerih pravilno.
3 Pred
prvim izvajanjem celo samo eden od pogojev 1–4.
1.3. PREVERJANJE USTAVLJANJA
15
4. (n > 0) ∧ (a[l] ≤ x < a[r]). Primer razpade na nekaj podprimerov:
(a) pogoj iz 12. vrstice je resniˇcen. Tedaj se zmanjˇsa r in po tem velja bodisi
i. x < a[r] in imamo zopet opravka s 4. primerom, kar pomeni, da invarianta ostane v veljavi ali
ii. 0 < r < n ∧ a[r] ≤ x < a[r + 1], ko nastopi primer 5 (in tudi tedaj invarianta ostane v veljavi). Doloˇceno podrobnost v zvezi s tem primerom
obravnava tudi naloga 4a;
(b) pogoj iz vrstice 12 je neresniˇcen, tedaj se poveˇca l in velja bodisi
i. a[l] ≤ x ter zopet nastopi primer 4 in s tem invarianta ostane v veljavi
ali pa
ii. 1 < l < n + 1 ∧ a[l − 1] ≤ x < a[l]. V slednjem primeru nastopi 6.
primer in invarianta zopet ostane v veljavi (gl. tudi nalogo 4b).
5. 0 < r < n ∧ a[r] ≤ x < a[r + 1]. V tem primeru se vrednost l poveˇca in pogoj
ostane v veljavi do trenutka, ko postane l = r + 1. Po izhodu iz zanke je rezultat
r v primeru a[r] = x, sicer pa −r − 1, kar je pravilno.
6. 1 < l < n + 1 ∧ a[l − 1] ≤ x < a[l]. V tem primeru se r zmanjˇsa in imamo
opravka z istim primerom do trenutka, ko postane r = l − 1. Po izhodu iz zanke
je rezultat bodisi r ali −r − 1, podobno kot v predhodnem primeru.
Osnovni namen podane obravnave primera s slike 1.2 je prikazati, kako je analiza
pravilnosti tudi navidez zelo preprostega programa lahko razmeroma zapletena. Kljub
temu jo je v osnovnih potezah koristno izpeljati, kar se kasneje obrestuje z manjˇsim
ˇstevilom napak.
1.3
Preverjanje ustavljanja
Prva in pomembna ugotovitev je, da sta pravilnost in ustavljivost programa dva loˇcena
problema. Trditev o pravilnosti ima vedno obliko “ˇce program pride do izstopne toˇcke,
velja trditev P ”. Torej se lahko zgodi, da pravilnost dokaˇzemo, vendar program
nikdar ne pride do izstopne toˇcke. Preverjanje ustavljanja je potemtakem dokaz, da
program po konˇcnem ˇstevilu korakov dejansko pride do izstopne toˇcke. Glede razlike
med definicijo programa in algoritma na strani 1 naj poudarimo, da pri algoritmu ˇze
privzemamo, da pri vseh vhodih obstaja dokaz o ustavljanju ustreznega programa.
Za preverjanje ustavljanja nekega programa bomo opisali neko tehniko, ki naˇceloma
deluje vedno, ko se program dejansko ustavi.
Uporabljali bomo predstavitev v obliki diagrama poteka. V prvem koraku izberemo neko funkcijo f (. . .), ki je odvisna od spremenljivk programa in ki ima lastnost
f (. . .) ≥ lim v vsaki toˇcki programa, pri ˇcemer je lim neka spodnja meja. Nato v
drugem koraku razdelimo diagram na odseke, ki ne vsebujejo zank in imajo lastnosti,
1. da je vsaka pot skozi diagram sestavljena iz nekaterih izbranih odsekov (ki se na
16
POGLAVJE 1. ALGORITMI
poti lahko tudi ponavljajo) in 2. na vsakem odseku, ki se ne konˇca pri izhodu programa, se vrednost f (. . .) strogo zmanjˇsa. V primeru, ko smo opravili oba koraka,
sledi iz lastnosti f (. . .) ≥ lim in 2., da nobena pot po diagramu ne more vsebovati neomejenega ˇstevila odsekov (ki se ne konˇcajo pri izhodu programa) in se torej program
ustavi.
1.1 Primer Kot prvi primer obravnavamo diagram poteka na sliki 1.11. Kot funkcijo
f izberemo f (u) = u, za katero ugotovimo, da velja f (u) ≥ 0 v vseh toˇckah programa,
v katerih je funkcija definirana (in definirana postane po izvajanju drugega stavka).
Odseki, na katere razdelimo diagram, pa so
1. Od vhoda v program do vstopa v odloˇcitveno ˇskatlo;
2. od odloˇcitvene ˇskatle preko njenega negativnega izhoda nazaj do vstopa v odloˇcitveno
ˇskatlo;
3. od odloˇcitvene ˇskatle preko njenega pozitivnega izhoda do izhoda programa
Ni se teˇzko prepriˇcati, da funkcija f in razdelitev diagrama na odseke izpolnjujeta vse
zahtevane pogoje in zato sklepamo, da se program ustavi.
1.2 Primer Drugi primer je bolj zapleten in se nanaˇsa na diagram poteka na sliki
1.17 (gl. tudi Manna [11, str. 187]). Program raˇcuna najveˇcjo skupno mero ˇstevil x1
in x2 , ki sta obe veˇcji od niˇc. V diagramu predstavlja simbol / celoˇstevilˇcno deljenje
(div). Glede njegove pravilnosti naj si bralec ogleda nalogo 5, na tem mestu pa nas
bo zanimalo le dokazovanje ustavljanja. Za funkcijo f izberemo f = y1 · y2 , lim pa je
enako 1. Odseki, na katere razdelimo diagram, pa so:
1-2-4
4-2-4
5-7-5
1-3-4
4-3-4
5-6-7-5
1-5-7-5
4-5-7-5
5-6-8
1-5-6-7-5
4-5-6-7-5
1-5-6-8
4-5-6-8
Ni se teˇzko prepriˇcati, da so pri tako izbranih elementih izpolnjene vse zahteve, ki
smo jih postavili (gl. nalogo 2).
1.4
Poraba ˇ
casa in prostora
Pri ocenah porabe omenjenih virov izhajamo iz doloˇcenih osnovnih lastnosti raˇcunalnika,
ˇ sta S1 in S2 dve zaporedji stavkov v programu in
na katerem se algoritem izvaja. Ce
ˇce T (Si ) pri 1 ≤ i ≤ 2 oznaˇcuje ˇcas, ki ga program porabi na zaporedju Si , je osnovna
lastnost, iz katere izhajamo
T (S1 ; S2 ) = T (S1 ) + T (S2 ).
(1.2)
Pri tem se moramo zavedati, da je to s staliˇsˇca danaˇsnje tehnologije doloˇcena poenostavitev. V bistvu je to omejitev na raˇcunalniˇski model preprostega zaporednega
ˇ
1.4. PORABA CASA
IN PROSTORA
17
VHOD
1
y1 := x1
y2 := x2
y3 := 1
DA
sodo(y1 )
NE
5
DA
2
y2 := y2 /2
y3 := 2y3
sodo(y2 )
DA
NE
NE
sodo(y2 )
6
3
DA
y1 := y1 /2
z := y2 y3
4
8
y1 = y2
y2 := y2 /2
7
NE
y1 := y2
y2 := |y1 − y2 |
IZHOD
Slika 1.17: Algoritem za najveˇcjo skupno mero.
procesorja, ki ukaze svojega programa izvaja enega za drugim in vsak program izvaja
do konca, preden se loti naslednjega. Za stroj RAM, za katerega smo se domenili,
da predstavlja tisti model, na katerem se izvajajo naˇsi algoritmi, je ta omejitev veljavna. Danes pa seveda obstajajo raˇcunalniki, ki vsebujejo veˇc procesorjev, tako da
lahko izvajajo istoˇcasno veˇc ukazov nekega programa. Za tak raˇcunalnik relacija (1.2)
seveda ne velja. Prav tako obstajajo raˇcunalniki, ki delo na nekem programu pred
koncem prekinejo in zaˇcnejo, oziroma nadaljujejo z delom na drugem programu, ki je
do tedaj miroval. Pri takem raˇcunalniku prav tako ne moremo napovedati ˇcasa delovanja programa na podlagi (1.2). Vendar kljub temu, da lastnost (1.2) na danaˇsnjih
raˇcunalnikih ni vedno prisotna, ˇse vedno predstavlja osnovo za vsako analizo porabe
ˇcasa.
Tudi pri analizi porabe pomnilnega prostora izhajamo iz doloˇcene poenostavitve.
18
POGLAVJE 1. ALGORITMI
Pri porabi prostora se moramo najprej zavedati, da je pomnilni prostor razdeljen na
veˇc podroˇcij, na primer: prostor za program, prostor za spremenljivke, prostor za
ˇ se na tem mestu
sklad ter prostor, ki ga program dinamiˇcno zasega in sproˇsˇca. Ce
omejimo na prostor za spremenljivke in ˇce prostor za spremenljivko x oznaˇcujemo z
M (x), je najenostavnejˇse izhodiˇsˇce, da je velikost prostora za spremenljivki x1 in x2
enaka
M (x1 ∪ x2 ) = M (x1 ) + M (x2 ).
(1.3)
Tudi v tem primeru je na danaˇsnjih raˇcunalnikih to poenostavitev, kajti obstajajo
raˇcunalniki in ustrezna programska oprema, ki omogoˇcata prirejanje istega prostora
razliˇcnim spremenljivkam4 . Namreˇc, ˇce izraˇcun, ki ga program uresniˇcuje, ne potrebuje koliˇcin x1 in x2 istoˇcasno, je moˇzno za x1 in x2 uporabiti isti prostor. Vendar
tudi v primeru prostora velja, da omenjena poenostavitev predstavlja osnovo za ocene
porabe tega vira.
1.4.1
Zapis za asimptotiˇ
cno rast funkcij
cg(n)
f (n)
g(n)
n0
n
Preden predstavimo naˇcine ocenjevanja porabe
ˇcasa in prostora, bomo opisali nek zapis za
asimptotiˇcno rast funkcij. Pogosto ˇzelimo izraziti
misel, da je funkcija f (n), ko je n celoˇstevilˇcni argument, po velikostnem redu asimptotiˇcno omejena navzgor z g(n). Moˇzno je tudi zamenjati
besede “omejena navzgor z” z “omejena navzdol
z” ali “enaka”. Natanˇcna oblika (prve) trditve
je, da
∃c, n0 > 0 ∀n ≥ n0 [f (n) ≤ cg(n)]
(1.4)
Slika 1.18: Asimptotiˇcna zgornja (gl. sliko 1.18).
Za ta pojem obstaja
meja z natanˇcnostjo do multiplika- uveljavljen zapis.
Mnoˇzico funkcij f (n),
tivnega faktorja
ki zadoˇsˇcajo pogoju (1.4), oznaˇcujemo z
O(g(n)):
O(g(n)) = {f (n) | ∃c, n0 > 0 ∀n ≥ n0 [f (n) ≤ cg(n)]}
(1.5)
Torej je (1.4) enakovredno trditvi
f (n) ∈ O(g(n)).
Vendar se je pri tem zapisu uveljavila doloˇcena nedoslednost in namesto f (n) ∈
O(g(n)) dejansko piˇsemo f (n) = O(g(n)). Na to je potrebno biti pozoren.
Podobno, kot smo definirali asimptotiˇcno zgornjo mejo, lahko definiramo asimptotiˇcno spodnjo mejo:
∃c, n0 > 0 ∀n ≥ n0 [f (n) ≥ cg(n)]
4 Pravzaprav
taki raˇ
cunalniki danes v praktiˇ
cni uporabi prevladujejo.
(1.6)
ˇ
1.4. PORABA CASA
IN PROSTORA
19
Ustrezno mnoˇzico sedaj oznaˇcujemo z
Ω(g(n)) = {f (n) | ∃c, n0 > 0∀n ≥ n0 [f (n) ≥ cg(n)]}
(1.7)
in podobno kot prej imamo nekoliko zavajajoˇc zapis f (n) = Ω(g(n)).
V primeru, ko velja f (n) = O(g(n)) kakor tudi f (n) = Ω(g(n)), piˇsemo f (n) =
Θ(g(n)) (torej Θ(g(n)) = O(g(n)) ∩ Ω(g(n))) in pravimo, da je f (n) po velikostnem
redu enaka g(n).
1.4.2
ˇ
Cas
Kot smo nakazali z lastnostjo (1.2), je najpomembnejˇsa tehnika pri ocenjevanju ˇcasa,
ki ga porabijo programi, seˇstevanje ˇcasov za posamezne dele programa. Osnovni
deli programa so posamezni stavki. Za porabo ˇcasa posameznih stavkov ponavadi
vpeljemo doloˇcene poenostavitve: tipiˇcni sta privzetek, da vsi stavki porabijo enak
ˇcas, ali pa, da nekateri porabijo ˇcas 1, drugi pa 0, kar pomeni, da ˇstejemo le nekatere
stavke. Na primer v algoritmu na sliki 1.2 bi lahko kot merilo za porabo ˇcasa vzeli
ˇstevilo izvajanj pogojnega stavka v vrstici 12. Za ta stavek ugotovimo, da se izvaja,
dokler ni izpolnjen izstopni pogoj iz zanke. Ker se koliˇcina r − l pri vsakem izvajanju
ˇ
jedra zanke pribliˇzno prepolovi, se bo ta stavek izvajal pribliˇzno log2 n krat. Ce
oznaˇcujemo s T (n) ˇcas, ki ga porabi algoritem na sliki 1.2 pri vhodnem parametru n,
vsekakor velja T (n) = Θ(log2 n) (gl. nalogo 8).
Ker so zanke vrste FOR,
FOR i = 1 TO n DO Si ,
in drugaˇcne zanke med najpomembnejˇsimi elementi programov, ima pri ocenjevanju
ˇcasa pomembno vlogo izraˇcun vrednosti vrst:
n
X
Ti
(1.8)
i=1
Za ocenjevanje vrednosti vrst obstaja obseˇzna literatura (gl. npr. Bronstein in dr. [3,
poglavje 7]), vendar je nekaj vrst tako znaˇcilnih, da jih bomo na tem mestu omenili.
Aritmetiˇ
cna vrsta
n
X
i = 1 + 2 + . . . + n.
i=1
Za takˇsno vrsto ugotovimo, da velja
n
X
i=1
i=
1
n(n + 1) = Θ(n2 ),
2
kar je moˇzno na primer dokazati z indukcijo po n.
(1.9)
20
POGLAVJE 1. ALGORITMI
Geometriˇ
cna vrsta
n
X
xi = 1 + x + x2 + . . . + xn .
i=0
Vrednost te vrste dobimo kot
n
X
(
i
x =
i=0
n + 1,
pri x = 1
xn+1 −1
,
x−1
sicer.
(1.10)
V primeru, ko je x < 0, prvi ˇclen ˇstevca gre proti 0 in dobimo pri velikih vrednostih
n:
n
X
1
xi ≈
.
1
−
x
i=0
(1.10) lahko dokaˇzemo bodisi ponovno
z indukcijo po n ali pa na podlagi neposrednega
Pn
razcepa polinoma xn+1 − 1 na i=0 xi in x − 1.
Ocenjevanje vrst z doloˇ
cnimi integrali. Od sploˇsnih orodij za ocenjevanje
vrednosti (vsote) vrst bomo navedli le ocenjevanje z doloˇcnimi integrali. V primeru,
ko ˇzelimo izraˇcunati
n2
X
f (i),
(1.11)
i=n1
in ko je f (x) nepadajoˇca funkcija v intervalu
[n1 − 1, n2 + 1],
R n2 +1
n1
f (x)dx ter
R n2 +1
n1
Z
f (x − 1)dx pa sta definirana, velja
n2
X
n2 +1
f (x − 1)dx ≤
n1
Z
n2 +1
f (i) ≤
f (x)dx
(1.12)
n1
i=n1
(gl. sliko 1.19). V primeru nenaraˇsˇcajoˇce funkcije f (x) sta pa neenakosti v (1.12)
obrnjeni.
Pn
ˇ
Primer. Zelimo
izraˇcunati i=2 1i ; iz (1.12) in pripombe sledi,
Z
2
oziroma
Z
1
n
n+1
n
X1
1
dx ≥
≥
x−1
i
i=2
n
X1
1
dx = ln n ≥
≥
x
i
i=2
Z
2
n+1
Z
2
n+1
1
dx,
x
1
dx = ln(n + 1) − ln 2,
x
ˇ
1.4. PORABA CASA
IN PROSTORA
21
f (x − 1)
Pn2
Rekurenˇ
cne relacije. Drugo pomembno orodje za
n1 f (x)
ocenjevanje ˇcasa algoritmov so rekurenˇcne relacije, ki
se pojavljajo zlasti pri algoritmih, ki imajo rekurzivno
f (x)
definicijo.
V tipiˇcnem primeru imamo problem, katerega vhodne podatke je moˇzno opisati s parametrom n, ki
n
n1
n2
oznaˇcuje velikost problema. Algoritem zanj pa deluje tako, da vhodne podatke najprej transformira v c
manjˇsih naborov in pridobi c sorodnih podproblemov Slika 1.19: Ocenjevanje vrevelikosti nc . Nato reˇsuje a izmed teh podproblemov in dnosti vrst z integrali
ˇ
reˇsitev kombinira v reˇsitev prvotnega problema. Ce
je za postopek razcepa prvotnih podatkov na podprobleme in kasneje za zdruˇzevanje
delnih reˇsitev v reˇsitev prvotnega problema potreben ˇcas velikostnega reda nr , kjer
je r neka konstanta, dobimo za ˇcas, ki ga porabi algoritem, relacijo
b,
n=1
T (n) =
(1.13)
aT ( nc ) + bnr , n > 1,
pri ˇcemer je b veˇcji izmed ˇcasov, ki jih algoritem porabi za primer n = 1 ali za razcep
problem velikosti n > 1 na podprobleme in za kasnejˇso zdruˇzitev delnih rezultatov v
rezultat prvotnega problema. Oceno za T (n) podaja naslednji izrek:
1.3 Izrek Naj bodo a, b, c in r nenegativne konstante. Pri c > 0 in a ≤ c je reˇsitev
rekurzivne enaˇcbe (1.13) podana s

a < cr ,
 Θ(nr ),
Θ(nr log(n)), a = cr ,
T (n) =

Θ(nlogc a ),
a > cr .
Dokaz. Natanˇcno izpeljavo bomo podali za primer n = ck . Z indukcijo po k lahko
pokaˇzemo, da velja
k
X
T (n) = bckr
qi
(1.14)
i=0
pri q =
a
cr ,
nato pa trditev izreka sledi iz (1.10). 2
ˇ
Primer. Kot primer vzemimo rekurzivno obliko dvojiˇskega iskanja na sliki 1.20. Ce
zapiˇsemo n = r−l+2, lahko uporabimo relacijo (1.13). Potrebno je le izbrati primerne
vrednosti a, c in r. V tem primeru je c = 2, ker podatke razbijemo na spodnji in
22
POGLAVJE 1. ALGORITMI
1
2
3
4
5
6
7
8
10
10
11
12
13
15
15
16
18
18
PROCEDURE BinSearch(VAR a:ARRAY OF LONGINT ;
l ,r ,x :LONGINT );
(∗ Ko je a prazno, imata l in r vrednosti 1 in 0;
a[0] je vedno nedefinirano; rezultat je k,
ko velja a[k]=x in −k, ko velja a[l −1] < x < a[l ]
oziroma l = 1 in x < a[l ] oziroma l = n+1 in
a[n] < x pri n = LEN (a) − 1∗)
VAR mid :LONGINT ;
BEGIN
IF l <=r THEN
mid :=(l +r )DIV 2;
IF a[mid ] > x THEN RETURN BinSearch(a,l ,mid −1,x )
ELSE RETURN BinSearch(a,l ,mid +1,r ,x )
END
ELSIF (r > 0) & (a[r ]=x ) THEN RETURN r
ELSE RETURN −l
END
END BinSearch;
Slika 1.20: Rekurzivni algoritem dvojiˇskega iskanja
zgornji del tabele (pod indeksom mid in nad njim)5 , a = 1, ker v vsakem primeru
sproˇzimo le en nadaljnji rekurzivni klic in r = 0, kajti poraba ˇcasa do rekurzivnega
klica (in po vrnitvi iz njega) je neodvisna od n. Na podlagi izreka 1.3 sledi, da je v
tem primeru
T (n) = Θ(nr log(n)) = Θ(log(n)),
kar je v skladu z rezultatom, ki smo ga zapisali na zaˇcetku tega razdelka.
1.4.3
Prostor
V tem delu se bomo z ocenami porabe prostora sreˇcali le nekajkrat in ne bomo navajali
posebnih metod za take ocene.
1.5
Povzetek osnovnih pojmov
1. Osnovni pojmi. Razlika med algoritmom in programom
2. Pojem stroja RAM
3. Sled algoritma. Drevo sledi
4. Dvojiˇsko iskanje z dvema izidoma primerjave
5 Pravzaprav je c malenkostno manjˇ
si, kar pomeni, da pri privzetku, da T (n) naraˇsˇ
ca z n, dobimo
nekoliko precenjeno vrednost T (n).
23
1.6. NALOGE
5. Osnovne metode za preverjanje pravilnosti algoritmov
6. Preverjanje pravilnosti s poskusi
7. Preverjanje pravilnosti z logiˇcno analizo
8. Diagrami poteka
9. Antecedens, konsekvens ter aksiomi preverjanja pravilnosti
10. Preverjanje pravilnosti zank. Zanˇcna invarianta
11. Programa za mnoˇzenje in deljenje dveh ˇstevil
12. Preverjanje pravilnosti programov, ki so zapisani v programskem jeziku
13. Preverjanje ustavljanja
14. Izhodiˇsˇci za ocenjevanje porabe ˇcasa in prostora
15. Zapis O, Ω, Θ
16. Osnovne vrste in njihovo ocenjevanje
17. Ocenjevanje porabe ˇcasa rekurzivnih programov.
1.6
Naloge
1. Na sliki 1.3b sta prikazani dve sledi algoritma s slike 1.2, kjer nas zanima le zaporedje
doloˇcenih “kontrolnih toˇck” pri izvajanju algoritma. Koliko je moˇznih takih sledi
algoritma pri vseh moˇznih vhodih, ko ima vhodna tabela a dolˇzino n (in nas, denimo,
zanimajo iste kontrolne toˇcke)?
2. Naj ima prirejanje x := 0 konsekvens x = 0. Zapiˇsite njegov antecedens.
3. Zakaj je v programu na sliki 1.11 potreben pogoj x > 0?
4.
(a) Natanˇcno analizirajte, zakaj v primeru 4(a)ii na strani 15 ne more veljati r = 0
ali r = n;
(b) podobno v 4(b)ii, zakaj ne more veljati l = 1 ali l = n + 1.
5. Prepriˇcajte se o pravilnosti programa za najveˇcjo skupno mero na sliki 1.17. Program
je izboljˇsava klasiˇcnega algoritma
WHILE x1 # x2 DO
IF x1 > x2 THEN
x1 := x1 − x2
ELSE x2 := x2 − x1
END
END ;
RETURN x1
Prikazani algoritem vsebuje nekaj predikatov “x je sodo”, katerih vlogo je potrebno
razumeti in dokazati, da program deluje pravilno.
6. Za primer 1.2 sestavite podroben dokaz, da sta izpolnjena pogoja 1. in 2.
razdelka 1.3 za razdelitev diagrama na odseke ter, da velja f (. . .) ≥ 1.
za pogoj 1. (vsako pot je moˇzno sestaviti iz izbranih odsekov) sestavite
razˇclenitev na posamezne primere. Na primer, vse moˇzne primere lahko
iz zaˇcetka
Napotek:
podrobno
razdelimo
24
POGLAVJE 1. ALGORITMI
na tiste, kjer je y1 sodo in druge, kjer je liho. Slednjo skupino delimo naprej na
podlagi lihosti y2 itn. Pogoj f (. . .) ≥ 1 preverimo tako, da pokaˇzemo, da je argument
vsakega celoˇstevilˇcnega razpolavljanja sod. Pogoj 2. dokaˇzemo tako, da preverimo,
da vsak odsek, ki se ne konˇca pri izhodu programa, vsebuje vsaj eno celoˇstevilˇcno
razpolavljanje.
7. Pri naslednjih parih funkcij
h2n2 , n2 i
h5n, n2 i
h3n, 1i
hn3 , n3 i
velja x = y(z), kjer sta x in z levi in desni element para, y pa je O ali Ω ali Θ. Za vse
primere ugotovite, kaj je najprimernejˇsa vrednost za y.
ˇ primerjamo algoritem na sliki 1.2, ki uporablja primerjanje z dvema izidoma, z
8. Ce
algoritmom dvojiˇskega iskanja, ki uporablja tri izide primerjanja (<, =, >), kaj je
osnovna razlika med njima glede asimptotiˇcnega obnaˇsanja porabe ˇcasa?
9. Poiˇsˇcite reˇsitev rekurzivne enaˇcbe,
T (n) =
b,
aT ( nc ) + bn log n,
n=1
n > 1.
(1.15)
Napotek: izpeljite relacijo, podobno (1.14), ki smo jo uporabili za dokaz izreka 1.3.
Poglavje 2
UREJANJE
2.1
Naloga urejanja in klasifikacija metod
urejanja
Urejanje podatkov se nanaˇsa na prestavljanje podatkov v zaporedju,
a1 , a2 , . . . , an ,
(2.1)
na podlagi neke relacije popolne urejenosti ≺, tako da na koncu dobimo,
ai1 , ai2 , . . . , ain ,
in velja,
ai1 ai2 . . . ain .
(2.2)
Potrebno je poudariti, da znak ≺ ne predstavlja nujno obiˇcajne urejenosti ˇstevil.
Urejanje veˇcinoma uporabljamo zato, da podatke spravimo v nekakˇsen red, ki nam
kasneje olajˇsuje njihovo iskanje. Spomnimo se pri igrah s kartami, kaj storimo takoj,
ko karte dobimo v roke: uredimo jih po barvah in vrednosti, tako da lahko kasneje
z enim samim pogledom ugotovimo, ali imamo karto doloˇcene vrste. Zaradi tega je
urejanje tudi ena izmed najpogostejˇsih operacij, ki se izvajajo na raˇcunalnikih. Kot
t´
ako jo mora raˇcunalniˇski strokovnjak obvladati in biti dobro seznanjem z razliˇcnimi
naˇcini in pogoji za njeno izvajanje. Poleg tega je moˇzno na primeru urejanja prikazati
vrsto idej in osnovnih tehnik programiranja in naˇcrtovanja algoritmov.
Osnovni pogoj za to, da je naloga urejanja smiselna, je popolna urejenost mnoˇzice
elementov zaporedja (2.1), kar pomeni, da za razliˇcna elementa x in y velja bodisi
x ≺ y ali y ≺ x. S to pripombo zaˇcnemo kratek miselni pregled razliˇcnih nalog
urejanja in za vsako nalogo razliˇcnih algoritmov zanjo.
V tem poglavju bomo algoritme predstavljali z razmeroma podrobnimi programi
v jeziku Oberon-2 (gl. npr. Reiser in Wirth [14] ali Mahniˇc [4]), zgradba programov
25
26
POGLAVJE 2. UREJANJE
MODULE Sort;
CONST
eq∗=0; less∗=1; grt∗=2;
TYPE
PItem∗=POINTER TO Item;
Item∗=RECORD (∗ podatkovni elementi ∗) END;
(∗ tip procedure za primerjanje podatkovnih elementov ∗)
FCmpType∗=PROCEDURE(p,q:PItem;r :INTEGER):BOOLEAN ;
END Sort.
Slika 2.1: Osnovne deklaracije pri nalogi urejanja
Urejanje
nizov, ki so sestavljeni
iz posameznih crk
in so razlicno dolgi
Slika 2.2: Podatki razliˇcne velikosti
pa bo tudi ustrezala razˇclembi sploˇsnega problema urejanja, kot bo opisana v nadaljevanju. Najsploˇsnejˇsi nalogi urejanja priredimo nek izhodiˇsˇcni programski modul,
ki vsebuje osnovne elemente, ki so skupni vsem razliˇcicam problema urejanja, nato
pa s specializacijo in dedovanjem pridemo do posameznih konkretnih primerov. Neko
moˇzno obliko takega izhodiˇsˇcnega modula prikazuje slika 2.1: podan je osnovni tip
zaporedja ter kazalec nanj, tip procedure za primerjanje, kakor tudi tri konstante, ki
doloˇcajo za kakˇsno primerjanje gre. Naj opozorimo na to, da modul Sort ne vsebuje
nobenih operacij temveˇc le deklaracije.
Na tem mestu je primerno opozoriti ˇse na neko posebnost zapisa, ki smo ga uporabili na sliki 2.1: gre za dogovor, ki vnaˇsa doloˇceno pravilnost v poimenovanje razliˇcnih
ˇ imamo tip, ki nosi ime Nm, bomo
objektov in s tem olajˇsuje njihovo pomnenje. Ce
kazalec nanj poimenovali s PNm (“POINTER TO”), tabelo z osnovnim tipom Nm
pa z ANm (“ARRAY OF”). Na primer na sliki 2.1 pomeni ime PItem, “POINTER
TO Item”. Prav tako bomo vse tipe, ki opisujejo procedure, oziroma funkcije, zaˇceli
s ˇcrko F (npr. “FCmpType”).
Naloge urejanja se predvsem razlikujejo po vrsti podatkov, definiciji relacije ure-
2.1. NALOGA UREJANJA IN KLASIFIKACIJA METOD UREJANJA
27
MODULE IntSort;
IMPORT S :=Sort;
TYPE
PItem∗= POINTER TO Item;
Item∗ = RECORD(S .Item) k ∗:LONGINT
END;
END IntSort.
Slika 2.3: Dodatne deklaracije za primer celoˇstevilˇcnih kljuˇcev
jenosti ter po velikosti zbirke podatkov, posamezni algoritmi pa ˇse po pristopu, ki ga
uporabljajo in po svoji zapletenosti. Razlikovali bomo dve osnovni vrsti podatkov,
in sicer podatke iste dolˇzine ter razliˇcnih dolˇzin. Vendar to ni posebno pomembna
znaˇcilnost, kajti urejanje podatkov razliˇcnih dolˇzin je moˇzno prevesti na urejanje podatkov iste dolˇzine z uporabo kazalcev in dinamiˇcnega dodeljevanja pomnilnika (glej
sliko 2.2). Na ta naˇcin je osnovna predstavitev vseh podatkov (kazalec) enako dolga
in se razliˇcne dolˇzine dejanskih podatkov kaˇzejo edino v neenakem trajanju operacije
primerjanja podatkov. Dejansko ima dostop do podatkov s kazalci doloˇceno prednost
pred neposrednim dostopom, zaradi ˇcesar ga bomo v tem poglavju vseskozi uporabljali
in se pravzaprav z urejanjem podatkov razliˇcnih dolˇzin ne bomo ukvarjali. Seveda
pa ima uporaba kazalcev tudi nekatere pomanjkljivosti. Na kratko so prednosti in
pomanjkljivosti uporabe kazalcev naslednje:
Dobre strani
1. Neodvisnost veˇcine programa od oblike podatkov ter s tem povezana moˇznost
uporabe programskih sestavin v razliˇcnih aplikacijah.
2. Enostavnejˇsa oblika programa.
Slabe strani
1. Veˇcja poraba pomnilnega prostora (dodaten prostor za kazalce).
2. Nekoliko manjˇsa hitrost.
Relacijo urejenosti lahko definiramo na razliˇcne naˇcine in zato smo v osnovnem
modulu Sort deklarirali le tip procedure FCmpType, ki mu pripadajo procedure, ki
preverjajo relacijo ≺. Pravzaprav pa procedur omenjenega tipa niti ne bomo uporabljali, ker za naˇse potrebe zadostujejo obiˇcajne relacije, <,= in >, ki so (v jeziku
Oberon-2) definirane tako za ˇstevilske tipe kot za znakovna zaporedja. To pa sta tudi
najpogostejˇsa praktiˇcna primera pri urejanju. Torej v prvem primeru imamo primerjanje na podlagi neke ˇstevilˇcne komponente podatka, v drugem pa na podlagi nekega
28
POGLAVJE 2. UREJANJE
PROCEDURE CompareStr (VAR a,b: ARRAY OF CHAR):INTEGER;
(∗ Znakovni zaporedji a in b sta zakljuˇceni z niˇcelnim znakom ∗)
VAR i:INTEGER;
BEGIN
i:=0;
WHILE (a[i]=b[i])&(a[i]#0X)DO INC (i) END;
RETURN ORD(a[i])−ORD(b[i])
END CompareStr ;
Slika 2.4: Leksikografsko urejanje
znakovnega zaporedja. Delu podatka, na podlagi katerega izvajamo primerjanje, ponavadi pravimo kljuˇc in v prvem primeru se deklaracija tipa Item razˇsiri tako, kot je
prikazano na sliki 2.3, v drugem primeru pa takole:
RECORD(Sort.Item) k :ARRAY OF CHAR END.
(2.3)
Mimogrede, relacija ≺, =, ali na znakovnih zaporedjih se raˇcuna po algoritmu, ki je
ˇ
prikazan na sliki 2.4. (Ceprav
smo ugotovili, da so te relacije pri Oberonu-2 vgrajene
v sam jezik, program navajamo zaradi dodatne razjasnitve pojma.) Tako definirani
relaciji urejenosti pravimo leksikografska urejenost. Pomembna razlika med urejanjem
na podlagi celoˇstevilˇcnega kljuˇca in leksikografskim urejanjem je, da sama operacija
primerjanja v prvem primeru porabi konstanten ˇcas, v drugem pa spremenljiv ˇcas
(tudi ˇce imamo opravka z znakovnimi zaporedji iste dolˇzine).
Znaˇcilnost problema urejanja, ki nas bo v tem poglavju najbolj zanimala in
doloˇcala naˇcin reˇsevanja problema, pa je ˇstevilo podatkov. Razlikovali bomo primer,
ko je moˇzno hraniti vse podatke v notranjem pomnilniku raˇcunalnika, od primera,
ko moramo uporabljati zunanje pomnilnike. Zaradi tega prvemu postopku pravimo
notranje urejanje, drugemu pa zunanje urejanje. V prvem primeru za shranjevanje
podatkov uporabljamo tabelariˇcno podatkovno strukturo (angl. array), v drugem pa
uporabljamo datoteke (angl. file).
Ko uporabljamo datoteke, ponavadi privzamemo, da so to zaporedne datoteke,
katerih osnovna znaˇcilnost je, da elemente beremo enega za drugim od zaˇcetka proti
koncu. V tem primeru velja, da imamo med branjem datoteke v vsakem trenutku
dostop samo do omejenega ˇstevila sosednih elementov, ki so “vidni” skozi nekakˇsno
okno na datoteko. Podatki iz okna so shranjeni v notranjem pomnilniku raˇcunalnika.
Zaporednim datotekam bomo vˇcasih rekli kar trak , ker se dejansko obnaˇsajo kot
klasiˇcni magnetni trakovi, kjer je tudi dejansko dosegljiv le majhen del podatkov
razmeˇsˇcen blizu bralne glave traˇcnega mehanizma.
Ponavadi algoritme za posamezne naloge urejanja lahko razvrstimo v dve skupini.
Eni pripadajo algoritmi, ki so po svoji zasnovi preprosti, porabijo pa razmeroma veliko
ˇcasa, drugi skupini pa pripadajo algoritmi, ki so po svoji zgradbi bolj zapleteni, vendar
hitrejˇsi. Algoritmom prve vrste pravimo navadni algoritmi (za urejanje), algoritmom
druge vrste pa izboljˇsani algoritmi . Vsi opisani kriteriji za razvrˇsˇcanje metod za
2.2. NOTRANJE UREJANJE
29
ˇ
PODATKI STALNE DOLZINE
ˇ
PODATKI SPREMENLJIVE DOLZINE
ˇ
PRIMERJANJE PORABI KONSTANTEN CAS
ˇ
PRIMERJANJE PORABI SPREMENLJIV CAS
KRATKA ZAPOREDJA = UREJANJE TABEL
DOLGA ZAPOREDJA = UREJANJE DATOTEK
ˇ
ENOSTAVNI, A CASOVNO
POTRATNI ALGORITMI
ˇ
ˇ
ZAPLETENI, A CASOVNO
UCINKOVITI
ALGORITMI
Slika 2.5: Kriteriji za razvrˇsˇcanje metod za urejanje
urejanje so povzeti na sliki 2.5.
Na koncu tega kratkega uvoda v urejanje naj na sliki 2.6 predstavimo shemo dedovanja med programskimi moduli, ki uresniˇcujejo metode, o katerih bomo razpravljali.
Programska modula Sort in IntSort pravzaprav pri realizaciji urejanja niti ne bi bila
potrebna, saj bi njuno vsebino zlahka vkljuˇcili v druge module. Izpostavili pa smo ju
kot loˇcena modula prav zato, da nakaˇzemo miselno razˇclenitev problemov urejanja.
2.2
Notranje urejanje
V tem razdelku si bomo najprej ogledali razliˇcne navadne algoritme za urejanje tabel
in nato njihove izboljˇsave. Navadni algoritmi za notranje urejanje imajo znaˇcilnost,
da porabijo O(n2 ) operacij za urejanje tabele velikosti n, izboljˇsani algoritmi pa za
isto nalogo v veˇcini primerov O(n log n) operacij. Omejili se bomo na algoritme, ki
izpolnjujejo tudi nek dodaten pogoj, in sicer, da ne zahtevajo bistveno veˇc prostora
za podatke, kot jih zaseda vhodna tabela dolˇzine n. Algoritme za notranje urejanje
nato delimo v tri skupine, na podlagi osnovnega pristopa, ki ga uporabljajo.
Vse procedure za urejanje tabel bomo deklarirali znotraj modula ArrSort z zaˇcetnima
dvema vrsticama:
MODULE ArrSort;
IMPORT I :=IntSort,S :=Sort;
vsaka od procedur za urejanje, ki jih bomo predstavili, pa uporablja parameter a
tabelariˇcnega tipa:
APItem = ARRAY OF I .PItem.
(2.4)
30
POGLAVJE 2. UREJANJE
Osnovni podatek
ˇstevilskim kljuˇ
cem
Ostale metode urejanja
Sort
s
Metode urejanja tabel
IntSort
ArrSort
FileSort
Definicija
osnovnega
podatka. Tip procedure za primerjanje
podatkov
Metode urejanja datotek
Slika 2.6: Shema dedovanja med programskimi moduli za urejanje
Kasneje bomo potrebovali tudi kazalec na ta tip:
PAPItem = POINTER TO APItem.
(2.5)
Preden predstavimo tri navadne metode urejanja tabel, naj omenimo neko skupno
lastnost, ki nam olajˇsuje njihovo razumevanje:
v vsakem trenutku delovanja procedure je tabela a razdeljena na
dva dela, levega, ki ima dolˇzino i in je ˇze urejen, ter desnega, ki ima
dolˇzino LEN (a) − i in je ˇse neurejen.
(2.6)
Skupno vsem navadnim algoritmom notranjega urejanja je, da imajo zgradbo preproste zanke z invarianto, ki jo predstavlja trditev (2.6) in jedrom, ki ima pri vsakem
izvajanju uˇcinek, da poveˇca dolˇzino ˇze urejenega dela za 1.
2.2.1
Navadno vstavljanje
Algoritem ima naslednjo zgradbo:
FOR i:=1 TO n−1 DO
BEGIN
(∗ a[i] vstavimo na pravilno mesto v urejeni del tabele,
a0 , . . . , ai−1 ∗)
END
Podrobno je algoritem prikazan na sliki 2.7. Na sliki je tudi nakazano mesto, kjer
velja trditev (2.6) o delitvi tabele na zaˇcetni, urejeni del in neurejeni del.
Na tem mestu lahko prikaˇzemo neko podrobnost, ki spada med drobne zvijaˇce
programiranja, je pa koristna v vseh primerih, ko moramo neko tabelo preiskati od
zaˇcetka do konca, tako kot na sliki 2.7 tabelo a[0], . . . , a[i − 1] (vrstice 8 do 10).
2.2. NOTRANJE UREJANJE
1
2
3
4
5
6
7
8
9
10
11
13
13
PROCEDURE InsertionSort∗(VAR a:APItem);
VAR i,j ,n:LONGINT ;x :I .PItem;
BEGIN n:=LEN (a);
FOR i:=1 TO n−1 DO
(∗ zaporedje, a[0], a[1], ..., a[i − 1], je urejeno;
zaporedje, a[i], a[i+1], ... , a[n−1], neurejeno ∗)
j :=i; x :=a[j ];
WHILE (j >=1) & (x .k <a[j −1].k ) DO
a[j ]:=a[j −1]; DEC (j )
END;
a[j ]:=x
END
END InsertionSort;
Slika 2.7: Navadno vstavljanje
1
2
3
4
5
6
7
8
9
10
11
12
13
15
15
PROCEDURE SentinelSort∗(VAR a:APItem);
(∗ Urejanje s ˇcuvajem; tabela a ima dodaten element na
svojem zaˇcetku ∗)
VAR i,j ,n:LONGINT ;
BEGIN n:=LEN (a)−1; (∗ ˇstevilo elementov v tabeli ∗)
FOR i:=2 TO n DO
(∗ zaporedje, a[1], a[2], ..., a[i − 1], je urejeno;
zaporedje, a[i], a[i + 1], ..., a[n], neurejeno ∗)
j :=i; a[0]:=a[i];
WHILE a[0].k <a[j −1].k DO
a[j ]:=a[j −1]; DEC (j )
END;
a[j ]:=a[0]
END
END SentinelSort;
Slika 2.8: Vstavljanje s ˇcuvajem
31
32
POGLAVJE 2. UREJANJE
V spremenjenem algoritmu navadnega vstavljanja na sliki 2.8 poveˇcamo tabelo, za
en element, tako da komponente a[1], . . . , a[n] vsebujejo zaporedje, ki ga urejamo,
a[0] pa je dodaten element, ki mu v vrstici 9 priredimo vrednost a[i]. Na ta naˇcin
smo odpravili potrebo po preverjanju pogoja za izstop iz notranje zanke, j ≥ 1, v
algoritmu na sliki 2.7 in priˇsli do oblike, ki je prikazana na sliki 2.8. Seveda pa krajˇsi
zapis izstopnega pogoja veˇcinoma pomeni hitrejˇse izvajanje. Takemu dodatnemu
elementu na zaˇcetku ali koncu tabele, ki ima nalogo, da prepreˇci nekemu indeksu (v
naˇsem primeru j), da prekoraˇci mejo tabele, pravimo ˇcuvaj.
Analiza navadnega vstavljanja. Pri algoritmih nas zanima poraba razliˇcnih raˇcunskih
virov, predvsem pomnilnega prostora in ˇcasa. Glede pomnilnega prostora smo se pri
urejanju tabel ˇze omejili na algoritme, ki ne zahtevajo dodatnega prostora (poleg
tistega, ki ga zasedajo podatki), tako da je analiza porabe prostora brezpredmetna.
Pri porabi ˇcasa pa postopamo tako, da ˇcas ocenjujemo s ˇstevilom doloˇcenih znaˇcilnih
operacij. Najznaˇcilnejˇse v algoritmu na sliki 2.8 je primerjanje v izstopnem pogoju
notranje zanke. Poleg tega nas ponavadi zanima veˇc vrst ocen, na primer: najmanjˇsa
poraba na vseh moˇznih zaporedjih dolˇzine n, najveˇcja poraba ter povpreˇcna poraba.
Na podlagi zgradbe algoritma na sliki 2.8 lahko za vse vrste porabe zapiˇsemo relacijo,
C=
n
X
Ci ,
(2.7)
i=2
kjer je C ˇstevilo primerjanj, in to bodisi najmanjˇse, najveˇcje ali povpreˇcno, Ci pa je
isto ˇstevilo med izvajanjem jedra zanke pri vrednosti i. Na primer, do najmanjˇsega
ˇstevila primerjanj v algoritmu na sliki 2.8 pride, ko je vhodno zaporedje ˇze urejeno
in se jedro notranje zanke nikoli ne izvaja. V takem primeru je Cmin,i = 1 pri vseh
vrednostih i in je,
n
n
X
X
Cmin =
Cmin,i =
1 = n − 1.
i=2
i=2
Do najveˇcjega ˇstevila primerjanj pa pride, ko je vhodno zaporedje nasprotno urejeno
in moramo a[i] vedno postaviti na prvo mesto. V tem primeru je Cmax,i = i − 1 in
dobimo,
n
n
X
X
1
Cmax =
Cmax,i =
(i − 1) = (n − 1)n.
2
i=2
i=2
Za izraˇcun povpreˇcne vrednosti, Cave , bi bilo potrebno poznati porazdelitev verjetnosti posameznih vhodnih zaporedij (in na podlagi tega izraˇcunati porazdelitev verjetnosti Cave,i ), ˇce pa privzamemo, da so vse vrednosti Cave,i v intervalu [Cmin , Cmax ]
enakoverjetne, dobimo oceno,
Cave =
1
1
1
1
(Cmin + Cmax ) = (n − 1 + (n2 − n)) = (n − 1)(n + 2).
2
2
2
4
33
2.2. NOTRANJE UREJANJE
1
2
3
4
5
6
7
8
9
10
12
12
13
14
15
16
17
19
19
PROCEDURE BinaryIns∗(VAR a:APItem);
VAR i,j ,l ,r ,m,n:LONGINT ;x :I .PItem;
BEGIN n:=LEN (a);
FOR i:=1 TO n−1 DO
x :=a[i]; l :=1; r :=i; (∗ l − 1 in r − 1 predstavljata
mejne indekse urejenega dela ∗)
WHILE l <= r DO
m:=(l +r )DIV 2;
IF a[m−1].k > x .k THEN r :=m−1
ELSE l :=m+1
END
END ;
IF (r > 0) & (x .k =a[r −1].k ) THEN l :=r END;
FOR j :=i TO l BY −1 DO
a[j ]:=a[j −1]
END;
a[l −1]:=x
END
END BinaryIns;
Slika 2.9: Navadno vstavljanje z dvojiˇskim iskanjem
Poskus izboljˇ
save navadnega vstavljanja. Ko razmiˇsljamo o moˇznih izboljˇsavah
metode navadnega vstavljanja, ugotovimo, da bi to bilo moˇzno, ˇce bi osnovne operacije
realizirali uˇcinkoviteje. Ena izmed operacij, ki se pojavlja v tem algoritmu, je iskanje
pravega mesta v zaporedju a[1], . . . , a[i − 1] za element a[i]. Glede na to, da je slednje
zaporedje ˇze urejeno, se nam utrne misel, uporabiti za omenjeno operacijo dvojiˇsko
iskanje. Tako spremenjen algoritem navadnega vstavljanja je prikazan na sliki 2.9.
Ker dvojiˇsko iskanje v tabeli dolˇzine n zahteva O(dlog2 ne) operacij, zahteva iskanje
pravega mesta za a[i] pri vseh i, 2 ≤ i ≤ n, ˇstevilo operacij
C=
n−1
X
dlog2 ie.
i=1
To ˇstevilo pa je moˇzno oceniti z integralom,
Z n
1
1
log2 x dx = x(ln x − 1)|n1 = n(ln n − 1),
c
c
1
ˇ
kjer je c = 1/ ln 2 [gl. 1.12]. Zal,
ko nekoliko premislimo, ugotovimo, da s takˇsno
izboljˇsavo nismo veliko dosegli, kajti zanka v vrsticah od 14 do 16 pri vseh vrednostih
i ˇse vedno zahteva O(n2 ) operacij (gl. nalogo 1). V tem primeru bi lahko rekli, da
nas je zanaˇsanje na oceno ˇcasa z ˇstetjem primerjanj zavedlo in pripeljalo do napaˇcnih
sklepov, kajti zanemarili smo ˇcas, ki se porabi za prestavljanje elementov zaporedja.
Nauk je, da se moramo pri podobnih ocenah prepriˇcati, da smo resniˇcno upoˇstevali
vse pomembne operacije algoritma, ki ga analiziramo.
34
POGLAVJE 2. UREJANJE
1
2
3
4
5
6
8
9
9
PROCEDURE SelectionSort∗(VAR a:APItem);
VAR i,j ,n:LONGINT ;
BEGIN n:=LEN (a);
FOR i:=0 TO n−2 DO
FOR j :=i+1 TO n−1 DO
IF a[i].k > a[j ].k THEN Exch(a[i],a[j ]) END
END
END
END SelectionSort;
Slika 2.10: Navadno izbiranje
2.2.2
Navadno izbiranje
Navadno izbiranje ima naslednjo zgradbo:
FOR i :=0 TO n−2 DO
(∗ Najmanjˇsi element med a[i] . . . a[n − 1] priredimo spremenljivki a[i] ∗)
END ;
popoln algoritem pa je prikazan na sliki 2.10. Pri vsakem izvajanju jedra zunanje
zanke se notranja zanka sprehodi po vseh indeksih, ki so veˇcji od i in vsakiˇc, ko naleti
na element z manjˇsim kljuˇcem kot a[i].k, zamenja a[i] in tekoˇci element a[j]. Pri
analizi algoritma uporabljamo zopet relacijo (2.7) z nekoliko spremenjenima mejama
seˇstevanja in dobimo
1
C = (n2 − n),
2
pri ˇcemer ugotovimo, da je v tem primeru koliˇcina C neodvisna od vhodnega zaporedja.
V tem primeru uporabimo nauk iz razdelka 2.2.1 in se lotimo ˇse ocene ˇstevila
zamenjav oziroma premikov, M . Izhajamo iz podobne relacije, kot je (2.7):
M=
n−2
X
Mi .
(2.8)
i=0
Na podlagi podobnih premislekov kot prej, pridemo do rezultata, da je Mmin = 0
(v primeru ˇze urejene tabele) in Mmax = 12 n(n − 1) (v primeru nasprotno urejene
ˇ
tabele). Ceprav
bi ˇcas lahko nekoliko izboljˇsali, ˇce bi uporabili operacije z indeksi
(vaja!), pa to ne bi vplivalo na velikostni red ˇcasa.
2.2.3
Navadne zamenjave
ˇ
Ceprav
smo ˇze pri algoritmu navadnega vstavljanja uporabljali operacijo zamenjave
dveh elementov kot bistveno sestavino algoritma, pa pri algoritmu na sliki 2.11 igra
35
2.2. NOTRANJE UREJANJE
1
2
3
4
5
6
7
9
10
11
11
PROCEDURE BubbleSort∗(VAR a:APItem);
VAR i,j ,n:LONGINT ;
BEGIN n:=LEN (a);
FOR i:=1 TO n−1 DO
FOR j :=n−1 TO i BY −1 DO
IF a[j −1].k > a[j ].k THEN
Exch(a[j −1],a[j ])
END
END
END
END BubbleSort;
Slika 2.11: Navadne zamenjave
ˇse pomembnejˇso vlogo, zaradi ˇcesar algoritmu pravimo urejanje z navadnimi zamenjavami. Pri vsakem izvajanju notranje zanke zaˇcnemo pri koncu tabele in potujemo proti zaˇcetku ter primerjamo sosednje elemente. V primeru napaˇcne urejenosti,
opravimo zamenjavo. Glede ˇcasovne zahtevnosti ugotovimo, podobno kot v primeru
navadnega izbiranja, da ˇstevilo primerjanj ni odvisno od vhodnih podatkov in da velja
C=
n(n − 1)
.
2
Pri navadnih zamenjavah so seveda bistvena sestavina porabe ˇcasa operacije prirejanja
elementov tipa PItem (gl. sliko 2.3). Izkaˇze se, da je tudi to ˇstevilo O(n2 ) (gl. nalogo
2).
Algoritem navadnih zamenjav vsebuje neko zanimivost: medtem ko se najmanjˇsi
element v neurejenem delu tabele spusti na svoje pravo mesto med enim samim izvajanjem notranje zanke1 , porabi najveˇcji element za to, da se dvigne do svojega pravega
mesta, veˇckratno izvajanje notranje zanke. Na podlagi te ugotovitve pridemo do
razliˇcice navadnih zamenjav, kjer smer gibanja “mehurˇckov” po vsakem izvajanju notranje zanke zamenjamo. Taki razliˇcici pravimo “izmeniˇcne zamenjave”. Izmeniˇcne
zamenjave vsebujejo ˇse neko izboljˇsavo povpreˇcnega ˇcasa algoritma: ˇce se je med izvajanjem notranje zanke algoritma na sliki 2.11 zadnja zamenjava opravila pri indeksu
k, je oˇcitno, da je podtabela z indeksi od 1 do k ˇze urejena in lahko spodnjo mejo
notranje zanke, i, takoj poveˇcamo do k. Algoritem s temi izboljˇsavami je prikazan na
sliki 2.12
2.2.4
Spodnja meja za ˇ
cas urejanja tabel
Pri navadnih metodah urejanja (navadno vstavljanje, izbiranje in zamenjave) smo
ugotovili, da zahtevajo ˇstevilo operacij, ki je O(n2 ), ˇce je velikost tabele n. Do te
1 Elementi se spuˇ
sˇ
cajo na svoja prava mesta podobno, kot se dvigajo zraˇ
cni mehurˇ
cki v vodi. Od
tod angleˇsko ime bubblesort.
36
POGLAVJE 2. UREJANJE
1
2
3
4
5
6
7
8
9
11
11
12
13
14
15
16
18
18
19
20
21
PROCEDURE ShakerSort∗(VAR a:APItem);
VAR i,j ,l ,r ,n:LONGINT ;
BEGIN n:=LEN (a);
l :=1;r :=n−1;j :=n−1;
REPEAT
FOR i:=r TO l BY −1 DO
IF a[i−1].k > a[i].k THEN
Exch(a[i−1],a[i]);
j :=i
END
END;
l :=j +1;
FOR i:=l TO r DO
IF a[i−1].k > a[i].k THEN
Exch(a[i−1],a[i]);
j :=i
END
END;
r :=j −1
UNTIL l >r
END ShakerSort;
Slika 2.12: Izmeniˇcne zamenjave
vrednosti smo priˇsli tako, da smo ˇsteli operacije primerjanja dveh elementov vhodne
ˇ ˇzelimo navadne metode
tabele ter prirejanja elementov podatkovnega tipa PItem. Ce
izboljˇsati s staliˇsˇca porabe ˇcasa, je dobro najprej oceniti, do katere meje lahko porabo
ˇcasa izboljˇsujemo. Z drugimi besedami, ˇzelimo priti do neke spodnje meje za porabo
ˇcasa za urejanje tabel dolˇzine n. Kot merilo za porabo ˇcasa ponavadi jemljemo ˇstevilo
operacij doloˇcene vrste (prej smo omenili operaciji primerjanja in prirejanja).
Pri doloˇcanju spodnje meje postopamo tako, da pri vnaprej doloˇcenem n obravnavamo “vse” algoritme urejanja tabel dolˇzine n in vsakemu algoritmu P pripiˇsemo
nek ˇcas urejanja T (P, n). Seveda je pojem “vseh algoritmov” nekoliko nenatanˇcen in
zato pravzaprav vzamemo neko natanˇcno doloˇceno mnoˇzico algoritmov P. Torej je
spodnja meja za ˇcas urejanja tabele dolˇzine n,
T (n) = MINP ∈P T (P, n).
(2.9)
Seveda pa vsak algoritem urejanja deluje na celi mnoˇzici vhodnih tabel dolˇzine n,
ki se med seboj razlikujejo po urejenosti in vrednosti elementov. In zato se moramo
odloˇciti o tem, katero vhodno tabelo naj upoˇstevamo pri raˇcunanju vrednosti T (P, n).
Razumno je izbrati vhodno tabelo, ki pri danem algoritmu daje najslabˇsi (najveˇcji) ˇcas
tako, da na koncu dobimo ˇcasovno vrednost, ki dejansko zagotavlja urejanje poljubne
tabele dolˇzine n. Po tem premisleku dobimo,
T (n) = MINP ∈P MAXIn ∈In T (P, In ),
(2.10)
37
2.2. NOTRANJE UREJANJE
if a[i]Ra[j] then S
Z(i, j)
goto l
halt
R predstavlja eno od relacij ≤, ≥, < ali >, S pa
je eden od preostalih treh
ukazov.
Zamenjava a[i] in a[j].
l je ˇstevilka nekega stavka
pri pogoju, da velja l > k,
kjer je k ˇstevilka samega
stavka goto.
Ustavljanje.
Slika 2.13: Dovoljene operacije pri ocenjevanju spodnje meje za ˇcas urejanja
pri ˇcemer je In mnoˇzica vseh moˇznih tabel dolˇzine n, In je poljuben element slednje
mnoˇzice in T (P, In ) je ˇcas, ki ga porabi algoritem P na vhodnih podatkih In . Bodimo
pozorni na to, da uporabljamo isti funkcijski simbol T v razliˇcnih pomenih, odvisno
od parametrov funkcije, ki jo simbol predstavlja: T (n) predstavlja spodnjo mejo za
urejanje zaporedij dolˇzine n, ne glede na algoritem, ki ga uporabljamo; T (P, n) predstavlja najveˇcji ˇcas, ki ga algoritem P porabi na nekem vhodnem zaporedju dolˇzine
n, T (P, In ) pa predstavlja ˇcas, ki ga porabi algoritem P na konkretnem zaporedju In .
Sedaj moramo natanˇcneje doloˇciti mnoˇzici In ter P, kakor tudi koliˇcino T (P, In )
oziroma T (P, n).
Od mnoˇzice algoritmov, ki jo izberemo, je odvisno, ali je reˇsitev, ki jo dobimo,
ˇ algoritem uporablja neko zelo zapleteno in uˇcinkovito
zanimiva, oziroma smiselna. Ce
osnovno operacijo (“strojni ukaz”), potem je urejanje moˇzno opraviti zelo hitro. V
skrajnem primeru je lahko ˇze sama operacija urejanja tabele dolˇzine n osnovni ukaz.
Zato je potrebno algoritme, oziroma dovoljene osnovne operacije tako izbrati, da so
primerljive z operacijami na dejanskih raˇcunalnikih. To predvsem pomeni, da morajo
v enem koraku predelati omejeno koliˇcino informacije. Nabor operacij na sliki 2.13
gotovo zadoˇsˇca temu pogoju, ima pa tudi lastnost, da je z njim moˇzno realizirati
urejanje tabele dolˇzine n pri poljubnem n (gl. nalogo 3). Dodaten pogoj, ki velja
za stavek goto, je potreben za to, da prepovemo zanke in na ta naˇcin zagotovimo
ustavljanje programa. Potrebno pa je poudariti, da je opisana vrsta programov le
teoretiˇcni pripomoˇcek pri izpeljavi spodnje meje, saj nima posebne praktiˇcne vrednosti. Namreˇc, ne pozna cele vrste operacij, ki so potrebne in zaˇzelene pri praktiˇcnih
programih, npr. operacije z indeksi in zanke, ki omogoˇcajo, da napiˇsemo program, ki
zna urejati tabele poljubne dolˇzine in ne le neke konstantne, vnaprej doloˇcene dolˇzine.
Glede vhodnih podatkov izgleda na prvi pogled, da je moˇznih kombinacij vhodnih
podatkov zelo veliko — celo neskonˇcno, ˇce zanemarimo dejstvo, da so ˇstevila, ki jih
lahko raˇcunalnik obdeluje, omejena na neko konˇcno mnoˇzico. Vendar glede na to, da
smo izbrali mnoˇzico programov, ki razpoznavajo le medsebojno razmerje posameznih
elementov tabele (≤,≥,<,>), je oˇcitno, da konkretne vrednosti elementov tabele niso
38
POGLAVJE 2. UREJANJE
"
"
1
2
3
"
"
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
#"
,
#"
,
1
2
3
2
1
3
#"
1
3
2
2
1
3
,
2
1
3
ne
#"
,
3
1
2
a[1] > a[2]
ne
da
#"
# "
a[2] > a[3]
ne
"
#
1
2
3
1
3
2
2
1
3
2
1
3
1
2
3
,
#"
2
1
3
,
3
1
2
#
3
1
2
1
3
2
1
3
2
"
"
,
da
#"
1
3
2
# "
1
2
3
#"
2
3
1
a[2] > a[3]
a[2] > a[3]
ne
da
"
#
1
2
3
2
3
1
1
2
3
1
3
2
,
1
2
3
3
1
2
2
3
1
1
2
3
2
1
3
#"
,
#"
,
3
2
1
3
2
1
a[1] > a[2]
ne
da
"
#"
#
a[2] > a[3]
ne
"
#
1
3
2
3
1
2
2
3
1
2
3
1
1
2
3
,
3
2
1
#
3
1
2
3
2
1
#
1
3
2
a[2] > a[3]
ne
da
"
#
1
2
3
3
2
1
#
1
2
3
#
#
Slika 2.14: Drevo sledi navadnih zamenjav pri n = 3.
pomembne in da lahko vzamemo n konkretnih, razliˇcnih vrednosti, najenostavneje
kar 1, 2, . . . , n. Seveda so moˇzna tudi vhodna zaporedja z veˇc enakimi vrednostmi,
vendar se nam zdi, da je naloga urejanja zaporedja z veˇc razliˇcnimi vrednostmi teˇzja
od naloge urejanja zaporedja z manj razliˇcnimi vrednostmi in zato, ˇce hoˇcemo dobiti
zaporedje, na katerem se dani algoritem najslabˇse obnaˇsa, je smiselno vzeti kar n
razliˇcnih vrednosti. Iz tega pa neposredno sledi, da namesto vseh moˇznih vhodnih
zaporedij lahko obravnavamo le permutacije simbolov 1, 2, . . . , n, ki jih je skupno n!.
Sedaj se bomo poglobili v naravo ˇcasovne karakteristike, T (P, n), algoritma P pri
ˇ je P algoritem iz opisanega razreda, lahko zanj
nalogi urejanja tabele dolˇzine n. Ce
sestavimo drevo sledi za vhodne podatke dolˇzine n. To je dvojiˇsko drevo, ˇcigar vsaka
veja predstavlja zgodovino izraˇcuna P na neki vhodni permutaciji. Vsako vozliˇsˇce
drevesa je oznaˇceno z mnoˇzico permutacij, ki do njega pripelje. Na primer, koren
drevesa je zaznamovan z mnoˇzico vseh permutacij (Sn ), pri neposrednih naslednikih korena odpadejo vse permutacije, ki niso zdruˇzljive z rezultatom primerjanja, ki
pripelje do naslednika itn.
2.1 Primer Kot primer vzamemo metodo urejanja z navadnimi zamenjavami (angl.
bubblesort) pri n = 3. Metodo realizira naslednji program
39
2.2. NOTRANJE UREJANJE
1.
2.
3.
4.
if a[2] > a[3] then Z(2,3) ;
if a[1] > a[2] then Z(1,2) ;
if a[2] > a[3] then Z(2,3) ;
halt ;
Programu ustreza drevo sledi, ki je prikazano na sl. 2.14. Na sliki smo vsako permutacijo predstavili z dvema zaporedjema: na levi strani oklepaja je prvotna urejenost
simbolov, na desni pa trenutna urejenost (pri opazovanem vozliˇsˇcu). Pri konˇcnih vozliˇsˇcih vidimo, da so na desnih straneh oklepajev povsod simboli pravilno urejeni, kar
pomeni, da se je postopek urejanja pravilno konˇcal.
ˇ
Cas
programa pri neki vhodni permutaciji ocenimo s ˇstevilom primerjanj od
zaˇcetka programa do ustavitve. Na drevesu sledi je to enako ˇstevilu vozliˇsˇc na neki
veji. Torej: dolˇzina veje predstavlja koliˇcino T (P, In ), kjer je In vhodna permutacija, ki pripelje do konˇcnega vozliˇsˇca veje. Za koliˇcino T (P, n) nato vzamemo dolˇzino
najdaljˇse veje v drevesu sledi programa P .
Spodnjo mejo za ˇcas urejanja tabele dolˇzine n dobimo iz naslednjih premislekov:
1. Vsakemu konˇcnemu vozliˇsˇcu drevesa sledi je prirejena najveˇc ena vhodna permutacija (dve razliˇcni permutaciji peljeta do razliˇcnih konˇcnih vozliˇsˇc).
2. Upoˇstevamo le programe, ki pravilno delujejo na vseh vhodnih permutacijah, ki
jih je skupno n!.
ˇ je T (P, n) najveˇcja dolˇzina veje drevesa sledi in ˇce je N ˇstevilo konˇcnih vozliˇsˇc,
Ce
oˇcitno velja,
2T (P,n) ≥ N ≥ n!.
(2.11)
Prva od zapisanih relacij (2.11) je dobro znano razmerje med viˇsino dvojiˇskega drevesa
in ˇstevilom njegovih konˇcnih vozliˇsˇc, druga pa izhaja iz premislekov 1 in 2 zgoraj. Leva
od relacij (2.11) se najbolj pribliˇzuje enakosti, ko je drevo uravnoteˇzeno. Koliˇcino n!
predstavimo s pribliˇzkom, ki ga daje Stirlingova formula:
√
(2.12)
n! ≈ nn e−n 2πn
(relativna napaka te formule je manj kot 10% pri n = 1 in se zmanjˇsuje pri naraˇsˇcajoˇcem
n). Iz 2.11 in 2.12 pa dobimo,
T (P, n) ≥ cn log2 n,
(2.13)
pri neki konstanti c > 0. Na podlagi (2.9) sledi, da velja tudi
T (n) ≥ cn log2 n.
2.2.5
(2.14)
Shellovo urejanje (izboljˇ
sano vstavljanje)
Shellov algoritem za urejanje ima danes le zgodovinski pomen, ker predstavlja prvi
algoritem za urejanje tabel, ki je porabil manj ˇcasa kot Θ(n2 ), kjer je n dolˇzina tabele.
Zanimiv pa je tudi zaradi nekaterih svojih na videz protislovnih lastnosti.
40
POGLAVJE 2. UREJANJE
Program 2.1: Shellovo urejanje
1
2
4
4
5
6
7
9
9
10
11
13
14
14
15
16
17
19
19
20
21
22
23
24
25
27
27
28
29
30
31
32
33
34
35
36
37
38
39
40
42
42
PROCEDURE Lg∗(n:LONGINT ):LONGINT ;
VAR res:LONGINT ;
BEGIN
res:=0;
WHILE n#0 DO n:=n DIV 2 ; INC (res) END;
RETURN res
END Lg;
PROCEDURE ShellParams∗(n:LONGINT ;VAR h,t:LONGINT );
(∗ Zaˇcetno ˇstevilo podtabel, t v tabeli z n podatki ter ˇstevilo korakov h ∗)
VAR i:LONGINT ;
BEGIN
IF n>=4 THEN t:=Lg(n)−2 ELSE t:=1 END;
h:=1;
FOR i:=2 TO t DO h:=2∗h+1 END
END ShellParams;
PROCEDURE ShellSort∗(VAR a:APItem;h,t:LONGINT );
VAR i,j ,k ,s:LONGINT ; x :I .PItem;
(∗ Tabela a vsebuje na svojem zaˇcetku h
dodatnih elementov a[0], a[1], . . . , a[h−1],
ki imajo vlogo ˇcuvajev med vstavljanjem v
podtabele; zaporedje, ki ga urejamo, pa predstavljajo
komponente a[h], a[h+1], . . . , a[LEN(a)−1]∗)
BEGIN
k :=h;(∗ zaˇcetni korak ∗)
WHILE k >= 1 DO
s:=h−k ; (∗ zaˇcetni ˇcuvaj ∗)
FOR i:=h+k TO LEN (a)−1 DO
x :=a[i];j :=i−k ;
a[s]:=x ;
WHILE x .k < a[j ].k DO
a[j +k ]:=a[j ];j :=j −k
END;
a[j +k ]:=x ;
s:=s+1;
IF s=h THEN s:=h−k END
END;
k :=(k −1) DIV 2
END
END ShellSort;
Shellovo urejanje (konec)
41
2.2. NOTRANJE UREJANJE
1
2
3
1
2
3
1
2
3
1
2
3
0
1
2
3
4
5
6
7
8
9
10 11
Slika 2.15: Zaˇcetna razdelitev tabele na podtabele
Algoritem deluje tako, da tabelo razdeli na veˇc podtabel (slika 2.15, desno od
navpiˇcne ˇcrte), nato na vsaki podtabeli izvaja navadno vstavljanje. Na sliki 2.15
so podtabele zaznamovane z 1, 2, 3. Za poenostavitev izstopnega pogoja iz zanke
ima vsaka podtabela lastnega ˇcuvaja (levo od navpiˇcne ˇcrte). Ko opravimo to fazo
postopka, ga ponovimo z manjˇsim ˇstevilom podtabel in tako nadaljujemo do ˇstevila
podtabel, 1. V tem pa je tudi navidezna protislovnost postopka: ˇce postopek zakljuˇcimo z navadnim vstavljanjem na celotni vhodni tabeli, zakaj je hitrejˇsi od enega
samega navadnega vstavljanja? Odgovor je, da, medtem ko ima eno samo navadno
vstavljanje znaˇcilnost, da v povpreˇcju pri vstavljanju prestavlja razmeroma dolga
podzaporedja (program 2.1, zanka v vrsticah 33 do 35), se dolˇzina zaporedij, ki jih
prestavljamo pri veˇckratnem navadnem vstavljanju, zmanjˇsa.
ˇ
Stevilo
podtabel, na katere razdelimo vhodno tabelo v posamezni fazi, je podano
kot zaporedje
h1 , h2 , . . . , ht ,
za katerega pa velja, kot smo ˇze zapisali,
ht = 1, hi+1 < hi , 1 ≤ i ≤ t − 1
Matematiˇcna analiza postopka je razmeroma zapletena, tako da se zanaˇsamo preteˇzno
na empiriˇcne izkuˇsnje. Na primer, znano je, da ˇstevila hi ne smejo imeti skupnih
faktorjev. Knuth [8, razdelek 5.2.1] priporoˇca zaporedje
1, 4, 13, 40, 121, . . .
(v nasprotnem vrstnem redu), za katerega velja: hk−1 = 3hk + 1, ht = 1 in t =
blog3 nc − 1, ali pa
1, 3, 7, 15, 31, . . . ,
s pravilom: hk−1 = 2hk + 1, ht = 1 in t = blog2 nc − 1(2 ). Za slednje zaporedje lahko
z matematiˇcno analizo izraˇcunamo ˇcasovno zahtevnost O(n1.2 ), kar pa je ˇse vedno
precej slabˇse od najboljˇsih danes znanih metod.
2.2.6
Urejanje s kopico (izboljˇ
sano izbiranje)
Urejanje s kopico ali drevesno urejanje (slika 2.16) izhaja iz ugotovitve, da se pri
navadnem izbiranju ˇze opravljeno delo ponavlja. Namreˇc, potem ko med izvajanjem
2 Spomnimo se, da je bxc definirano kot najveˇ
cje celo ˇstevilo, ki ne presega x. Podobno je dxe
definirano kot najmanjˇse celo ˇstevilo, ki ni manjˇse od x.
42
POGLAVJE 2. UREJANJE
1
2
3
4
5
6
7
8
9
10
11
13
13
14
15
16
18
18
20
20
21
22
23
24
26
26
PROCEDURE HeapSort∗(VAR a:APItem);
(∗ Pozor! Indeksi v tabeli so 0, 1, . . . n − 1 ∗)
VAR l ,r : LONGINT ; x : I .PItem; (∗ 1 ≤ l, r ≤ n
leva in desna meja podkopice ∗)
PROCEDURE Sift;
VAR i,j :LONGINT ; x : I .PItem;
BEGIN i:=l ; j :=2∗i; x :=a[i−1];
WHILE j < r DO
IF a[j −1].k < a[j ].k THEN INC (j ) END;
IF x .k >= a[j −1].k THEN j :=r +1 (∗ izhod iz zanke ∗)
ELSE a[i−1]:=a[j −1]; i:=j ; j :=2∗i
END
END;
IF (j =r ) & (x .k < a[j −1].k ) THEN
a[i−1]:=a[j −1]; a[j −1]:=x
ELSE a[i−1]:=x
END
END Sift;
BEGIN l :=LEN (a) DIV 2; r :=LEN (a);
WHILE l >= 1 DO Sift ; DEC (l ) END; INC (l );
WHILE r > 1 DO
x :=a[0]; a[0]:=a[r −1]; a[r −1]:=x ;
DEC (r ); Sift
END
END HeapSort;
Slika 2.16: Urejanje s kopico
23
2
3
17
11
4
5
15
8
9
1
3
6
10
9
13
Slika 2.17: Kopica
7
5
43
2.2. NOTRANJE UREJANJE
14
23
1
2
3
17
11
4
5
15
8
9
3
6
10
7
5
9
13
Slika 2.18: Popravljanje pokvarjene kopice
jedra zunanje zanke algoritma na sliki 2.10 poiˇsˇcemo najmanjˇsi element, isti postopek ponovimo pri naslednjem izvajanju, ne glede na dejstvo, da bi bilo moˇzno del
informacije, ki smo jo nabrali med predhodnim izvajanjem, izkoristiti tudi kasneje.
Urejanje s kopico ohranja informacijo iz predhodnih iskanj najmanjˇsega elementa
v posebni podatkovni strukturi, ki ji pravimo kopica (angl. heap). Kopica je urejeno, levo uravnoteˇzeno dvojiˇsko drevo, katerega vozliˇsˇca hranijo informacijo o kljuˇcih.
Drevo je urejeno, ker velja, da je kljuˇc nekega vozliˇsˇca v ≥ od kljuˇcev vseh vozliˇsˇc w,
ki pripadajo poddrevesu s korenom v (namesto ≥ vˇcasih uporabljamo urejenost ≤).
Drevo je uravnoteˇzeno, ker se razliˇcne veje med seboj razlikujejo po dolˇzini kveˇcjemu
za 1 in je levo uravnoteˇzeno, ker so daljˇse veje zbrane na levi strani drevesa. Primer kopice je prikazan na sliki 2.17. Bistvenega pomena za uˇcinkovitost metode je
uˇcinkovita realizacija kopice s tabelariˇcno strukturo. Na sliki 2.17 so zraven vozliˇsˇc
zapisani njihovi indeksi v tabeli, ki kopico predstavlja. Pravilo za indekse je:
ˇ so indeksi tabele 1, 2, . . . , n, je indeks levega naslednika vozliˇsˇca z inCe
deksom i enak 2i, desnega naslednika pa 2i + 1. (V programski realizaciji
tabele so indeksi prestavljeni v 0, 1, . . . , n − 1.)
Nadalje je pomembno dejstvo, da je potem, ko v kopici zamenjamo koren (jo “pokvarimo”), potrebno popraviti le enega izmed dveh poddreves, ki izvirata pri korenu. Na
primer, na sliki 2.18 smo zamenjali vrednost 23 pri korenu z novo vrednostjo, 14. Po
tem pri korenu ni veˇc izpolnjen pogoj urejenosti in je zato potrebno element 14 prestaviti. Nalogo opravimo tako, da izberemo veˇcjega od dveh naslednikov (17,11), ga
dvignemo do korena, se spustimo do izpraznjenega vozliˇsˇca in operacijo ponavljamo
do vozliˇsˇca, ˇcigar oba naslednika sta manjˇsa ali enaka novemu elementu (14). Na
sliki je to vozliˇsˇce z elementom 15. Novi element postavimo na pravkar izpraznjeno
mesto. Na sliki 2.18 kaˇzejo prekinjene ˇcrte potrebne zamenjave. Algoritem, ki uresniˇcuje opisan postopek (“pogrezanja”), je na sliki 2.16 zapisan v vrsticah 5 do 18.
Je pa sestavljen tako, da ga lahko sproˇzimo tudi na poddrevesu (“podkopici”) celotne
44
POGLAVJE 2. UREJANJE
9
2
3
23
10
4
5
17
8
15
1
3
6
11
7
5
9
13
Slika 2.19: Sestavljanje kopice
kopice, pri ˇcemer je poddrevo doloˇceno z indeksoma l, ki predstavlja indeks korena,
in r, ki predstavlja zadnji element na skrajno desni veji poddrevesa. Zaradi dejstva,
da se pogrezanje pomika od korena po neki veji navzdol (v skrajnem primeru do lista
drevesa), zahteva ˇcas O(log2 n), kjer je n ˇstevilo elementov v kopici.
Do sedaj nismo obravnavali, kako iz nakljuˇcno urejene tabele pridobimo kopico.
Izkaˇze se, da tudi to nalogo lahko opravimo z operacijo pogrezanja. Primer je prikazan
na sliki 2.19: konˇcna vozliˇsˇca drevesa obravnavamo kot poddrevesa velikosti 1, ki so v
vsakem primeru ˇze kopice (oziroma “podkopice”). Zato postopek zaˇcnemo pri prvem
vozliˇsˇcu, ki predstavlja koren nekega poddrevesa, ki ima velikost veˇcjo kot 1. To je v
naˇsem primeru vozliˇsˇce z indeksom 4 (v sploˇsnem pa je to vozliˇsˇce z indeksom nDIV2).
V naˇsem konkretnem primeru je pogoj urejenosti izpolnjen, zato nadaljujemo v smeri
puˇsˇcic. Naslednje vozliˇsˇce je 10. V tem primeru algoritem za popravljanje kopice
zamenja 10 in 11. Pri vozliˇsˇcu 23 je pogoj urejenosti zopet izpolnjen. Konˇcno pri
vozliˇsˇcu 9 algoritem za popravljanje kopice postavi 9 v konˇcno vozliˇsˇce skrajno leve
veje, prejˇsnje vrednosti pa prestavi po veji za eno mesto viˇsje. Na ta naˇcin dobimo
kopico, ki je prikazana na sliki 2.17. Celoten postopek pa zaseda v algoritmu na sliki
2.16 le eno vrstico, 21.
Analiza ˇ
casovne zahtevnosti. Na podlagi pravkar podanega opisa in najveˇcje
porabe ˇcasa algoritma pogrezanja (O(log2 n)) ni teˇzko podati ocene porabe ˇcasa algoritma na sliki 2.16. Postopek sestavljanja kopice zahteva ˇcas ≤ c n2 log2 n (pri neki
konstanti c), medtem ko samo urejanje (vrstice 22 – 25) zahteva ≤ c0 n log2 n. Torej
je celotna poraba ˇcasa O(n log n).
2.2.7
Urejanje s porazdelitvami (izboljˇ
sane zamenjave)
Pri metodi navadnih zamenjav (slika 2.11) izvajamo zamenjave na izredno neuˇcinkovit
naˇcin, saj sprehod po vseh elementih tabele po vrsti in zamenjava nepravilno postavljenih sosednjih elementov le poˇcasi pripelje do ˇzelene urejenosti. Mnogo bolj
2.2. NOTRANJE UREJANJE
1
2
3
4
5
6
8
8
9
10
11
13
13
14
15
17
17
19
19
20
21
22
23
24
25
27
27
28
45
PROCEDURE Partition∗(VAR a:APItem;
VAR l ,r : LONGINT ;
m:LONGINT );
VAR i,j : LONGINT ;
BEGIN
i:=l ; j :=r ;
REPEAT
WHILE a[i−1].k < m DO INC (i) END;
WHILE a[j −1].k > m DO DEC (j ) END;
IF i <= j THEN Exch(a[i−1],a[j −1]);
INC (i);DEC (j )
END
UNTIL i > j ;
l :=i; r :=j
END Partition;
PROCEDURE QuickSort∗(VAR a:APItem);
PROCEDURE Sort(l ,r : LONGINT );
VAR i,j :LONGINT ;
BEGIN i:=l ; j :=r ;
Partition(a,i,j ,a[((l +r ) DIV 2)−1].k );
IF l < j THEN Sort(l ,j ) END;
IF i < r THEN Sort(i,r ) END
END Sort;
BEGIN Sort(1,LEN (a))
END QuickSort;
Slika 2.20: Urejanje z porazdelitvami
uˇcinkovito je zamenjave izvajati na elementih, ki so na veˇcjih medsebojnih razdaljah.
Opisano idejo realiziramo tako, da na vsakem koraku tabelo porazdelimo tako, da
so vsi elementi s kljuˇci, ki so enaki neki mejni vrednosti ali manjˇsi od nje, razmeˇsˇceni
v spodnjem delu tabele, oni, ki pa so enaki ali veˇcji, pa v zgornjem delu tabele. Na
ta naˇcin nalogo lahko reˇsimo z rekurzivnim razcepom. Opisano porazdelitev je moˇzno
doseˇci tako, da se z indeksom i sprehodimo od zaˇcetka tabele proti koncu, z drugim
indeksom, j, pa od konca proti zaˇcetku. Indeks i se ustavi pri prvem elementu, ki je ≥
od mejne vrednosti, indeks j pa pri prvem elementu, ki je ≤ od mejne vrednosti. Nato
se opravi zamenjava, postopek pa se nadaljuje do trenutka, ko se indeksa sreˇcata. Na
ta naˇcin dobimo v podtabeli, ki obsega indekse od zaˇcetka do mesta sreˇcanja i in j,
vrednosti, ki so enake mejni vrednosti ali manjˇse od nje, v komplementarni podtabeli
pa vrednosti, ki so enake mejni vrednosti ali veˇcje od nje. Posebno vpraˇsanje je, kako
izbrati mejno vrednost. Oˇcitno bi bilo zaˇzeleno, da postopek porazdelitve prvotno
tabelo razdeli na dva enaka dela, vendar, ˇzal, tega ne moremo zagotoviti, ker nimamo
46
POGLAVJE 2. UREJANJE
1.
3
2
5
2. !!
3
2
5
3.
3
2
4. !!
3
2
5
i
1
5.
2
6.
3
i
1
7.
1
2
i, j
2
1
j
3
3
7
i
4
6
1
8
6
4
6
8
i
8
7
4
j
4
6
i
6
1
j
1
j
5
7
8
4
5
4
j
7
5
6
4
Slika 2.21: Primer urejanja s porazdelitvami
nobene informacije o zaˇcetni urejenosti elementov. Zato so vse izbire mejne vrednosti
enakovredne. V algoritmu na sliki 2.20 uporabljamo za mejno vrednost kljuˇc elementa
a[(l + r)DIV 2 − 1] (bodimo pozorni, da so i, j, l in r v mejah [1, LEN (a)], medtem
ko so indeksi tabele v mejah [0, LEN (a) − 1]).
Primer. Na sliki 2.21 je prikazan konkreten primer urejanja s porazdelitvami. Pri
prvi porazdelitvi je mejna vrednost 7 in zato se indeksa i in j ustavita, kot je to
prikazano v prvi vrstici. Po opravljeni zamenjavi indeksa nadaljujeta svojo pot in se
ustavita, kot je to nakazano v drugi vrstici. Tu ugotovimo, da bi pri urejanju priˇslo do
napake, ˇce bi uporabili pravilo, da po ustavitvi indeksov obvezno pride do zamenjave,
saj bi se 1 in 8, ki sta v drugi vrstici pravilno urejena, postavila nepravilno. Zaradi
tega je pred zamenjavo potrebno preveriti pogoj i ≤ j (slika 2.20, vrstice 10 – 12)
Sedaj je prva porazdelitev opravljena (tretja vrstica) in lahko loˇceno nadaljujemo z
urejanjem podtabel od indeksa 1 to 6 ter od 7 do 8. Pri porazdelitvi prve podtabele je
sedaj mejna vrednost 5 in se indeksa ustavita, kot je to prikazano (tretja vrstica). Po
zamenjavi indeksa nadaljujeta svoji potovanji, dokler se ne ustavita, kot je to prikazano v ˇcetrti vrstici. V ˇcetrti vrstici pride do podobnega problema kot v drugi vrstici
(in potrebe po preverjanju, ali sta se pred zamenjavo indeksa sreˇcala). V peti vrstici
je prikazan rezultat druge porazdelitve, nato pa nadaljujemo s porazdeljevanjem leve
podtabele z mejno vrednostjo 2. Po zamenjavi dobimo urejeno zaporedje (vrstica 6),
vendar se postopek nadaljuje ˇse za en korak (vrstica 7). V tem primeru algoritem
opravi nepotrebno zamenjavo (element 2 zamenja s samim seboj), vendar je tak algoritem v povpreˇcju hitrejˇsi, kot ˇce bi preverjali, ali velja i = j. Ostale podtabele
se urejajo na podoben naˇcin, le da je za to potreben vedno samo en korak, ker so
velikosti 2.
2.2. NOTRANJE UREJANJE
47
Analiza ˇ
casovne zahtevnosti. Znaˇcilnost metode je, da je dobra (in to zelo dobra)
le v povpreˇcnem primeru, medtem ko je njeno obnaˇsanje v najslabˇsem primeru (ki
pa nastopi izredno redko) slabo. Izhodiˇsˇce za oceno ˇcasovne zahtevnosti je ˇcas, ki ga
porabi postopek porazdeljevanja. Ni se teˇzko prepriˇcati, da procedura Partition (slika
2.20, vrstice 1–15) za tabelo velikosti n porabi ˇcas Θ(n). Na podlagi tega podatka
ˇze vemo, da je ˇcas, ki bi ga porabilo urejanje s porazdelitvami, ˇce bi tabelo vedno
razdelili na dva enaka dela,
T= (n) = Θ(n log n)
(2.15)
(gl. nalogo 4) in glede na dejstvo, da je to po velikostnem redu enako spodnji meji za
ˇcas urejanja tabele dolˇzine n (2.11), domnevamo, da je to najboljˇsi ˇcas, ki ga metoda
zmore.
Sedaj bomo ocenili povpreˇcni ˇcas. Povpreˇcje je priˇcakovana vrednost neke sluˇcajne
spremenljivke, kjer vsaki moˇzni vrednosti pripiˇsemo neko verjetnost. V naˇsem primeru
je sluˇcajna spremenljivka, ki nas zanima, ˇcas, ki ga porabi urejanje s porazdelitvami na
tabeli dolˇzine n, razliˇcni moˇzni izidi pa ustrezajo razliˇcnim velikostim k leve podtabele,
ki nastane kot rezultat porazdelitve (k = j − l + 1 v vrstici 22 na sliki 2.20).
Najprej razmislimo, kolikˇsen je razpon vrednosti velikosti podtabel, na katere
razdelimo prvotno tabelo dolˇzine n. Oˇcitno je, da nobena od dveh podtabel ni veˇcja
od n − 1, kajti vsak od indeksov i in j se premakne vsaj enkrat. Druga skrajna
vrednost velikosti podtabele je 0, ki ustreza primeru, ko se na primer vrednost j
spusti pod vrednost l (bralec naj poskuˇsa poiskati pogoje, pod katerimi se to zgodi).
Po tem razmisleku lahko naˇsetejemo dva privzetka, na podlagi katerih bomo definirali
rekurenˇcno relacijo za izraˇcun ˇcasa:
1. pri vsaki porazdelitvi se tabela velikosti n razdeli na dva dela, od katerih ima
eden velikost k, drugi pa n − k − 1 pri 0 ≤ k ≤ n − 1;
2. vse vrednosti k so enakoverjetne, torej je verjetnost, da je leva podtabela velikosti k enaka n1 za vse 0 ≤ k ≤ n − 1.
Prvi privzetek pravzaprav ne ustreza resniˇcnosti, kajti tabela se porazdeli v privzetem
sorazmerju le takrat, ko sta indeksa i in j po izhodu iz dveh zank v vrsticah 8 in 9 na
sliki 2.20, enaka (iz tega sledi, da je element s tem indeksom enak mejnemu elementu).
V primeru, ko je indeks tega elementa k + 1, se opravi fiktivna zamenjava elementa
a[k + 1] s samim seboj in se vrednost j spusti na k, vrednost i pa dvigne na k + 2. Iz
tega sledi, da je velikost leve podtabele enaka k, desne pa n − k − 1. Bolj pogost pa je
izid porazdeljevanja, ko se tabela porazdeli v razmerju k : n − k. Vendar bomo kljub
malenkostni napaki zapisani privzetek uporabili, ker nam omogoˇca zapis preproste
rekurenˇcne relacije, ki povezuje povpreˇcni ˇcas za urejanje tabele dolˇzine n, Tave (n), z
vrednostmi iste koliˇcine pri manjˇsih vrednostih parametra n:
Tave (n) =
0
cn +
1
n
Pn−1
i=0
pri n = 0 ali n = 1
[Tave (i) + Tave (n − i − 1)] , pri n ≥ 2,
(2.16)
48
POGLAVJE 2. UREJANJE
pri ˇcemer je cn ˇcas potreben za porazdelitev na levi in desni del, vsota pa je priˇcakovani
ˇcas za urejanje obeh delov tabele. (gl. tudi nalogo 5.1). Drugo vrstico enaˇcbe (2.16)
lahko spremenimo v naslednjo obliko:
Tave (n) = cn +
n−1
2X
Tave (i).
n i=0
(2.17)
Sedaj dokaˇzemo z indukcijo po n, da pri n ≥ 2 velja
Tave (n) ≤ 2(c + δ)n ln n,
(2.18)
kjer je δ neka majhna konstanta, ki jo bomo ocenili naknadno. Pri n = 2 sledi
(2.18) neposredno iz (2.17) (2 ln 2 ≈ 1.38) za poljubno nenegativno vrednost δ. V
induktivnem koraku najprej prepiˇsemo (2.17) v obliko
Tave (n) ≤ cn +
n−1
4(c + δ) X
i ln i.
n
i=0
(2.19)
Funkcija x ln x ima pozitiven prvi odvod na intervalu [1, n], torej lahko zapiˇsemo na
podlagi (1.12),
Z n
n−1
X
x2
1 n
i ln i ≤
x ln xdx =
(ln x − ) 1
2
2
1
(2.20)
i=1
n2
1
1
=
(ln n − ) + ,
2
2
4
in ˇce vstavimo desno stran (2.20) v (2.19), konˇcno dobimo,
h 2
i
n
1
1
(ln
n
−
)
+
Tave (n) ≤ cn + 4(c+δ)
n
2
2
4
(2.21)
= 2(c + δ)n ln n − δn + (c+δ)
.
n
δ doloˇcimo iz pogoja (c+δ)
− δn ≤ 0 pri n ≥ 3, kar daje δ ≥ 8c .
n
Sedaj se lotimo ocene za najveˇcjo porabo ˇcasa. V tem primeru izhajamo iz najmanjˇsega ˇcasa urejanja s porazdelitvami, T= (n) [gl. (2.15)] in ˇzelimo raziskati odvisnost ˇcasa od razliˇcnih porazdelitev prvotne tabele na dve podtabeli. Vpeljemo
funkcijo dveh spremenljivk T2 (x, n), 1 ≤ x ≤ n − 1, z vrednostjo, enako porabi ˇcasa
pri urejanju s porazdelitvami, ˇce prvotno tabelo razdelimo v razmerju [x, n − x], podrejene tabele pa tako, da je poraba ˇcasa najmanjˇsa. Izraˇcun si bomo poenostavili
tako, da bomo obe spremenljivki, x in n obravnavali kot realni spremenljivki. Ker je
v tem primeru T= (x) zvezna in ima prvi odvod pri x ≥ 1, lahko zapiˇsemo,
T2 (x, n)
= cn + T= (x) + T= (n − x)
= cn + kx ln x + k(n − x) ln(n − x),
kjer je k neka konstanta in
dT2 (x, n)
x
= ln
.
dx
n−x
(2.22)
49
2.2. NOTRANJE UREJANJE
Pri x = n/2 ima odvod (2.22) vrednost 0, pri x < n/2 je negativen, pri x > n/2
ˇ
pa pozitiven. Torej T2 (x, n) monotono naraˇsˇca, ko se x pribliˇzuje 1 oziroma n. Ce
isti premislek uporabimo na dveh podtabelah, na katere smo razdelili prvotno tabelo,
dobimo ˇse bolj strmo narˇsˇcanje ˇcasa, ko se x pribliˇzuje 1 oziroma n. Torej sklepamo,
da urejanje s porazdelitvami porabi najveˇ
cˇ
casa v primeru, ko so vse podtabele, ki imajo velikost razliˇ
cno od 1, razdeljene v razmerju [1 : m − 1], ˇ
ce
je m velikost vsakokratne podtabele. V tem primeru dobimo vrednost porabe
ˇcasa tako, da seˇstejemo vse ˇcase, ki so potrebni za porazdeljevanje prvotne tabele in
podrejenih tabel:
n−1
X
Tmax (n) = c
i = Θ(n2 ).
i=1
Poraba pomnilnega prostora. Na zaˇcetku razdelka o urejanju tabel (2.2) smo
zapisali, da nas zanimajo le algoritmi, ki ne porabijo bistveno veˇc prostora, kot ga
zasedajo vhodni podatki. Sedaj bomo preverili, ali urejanje s porazdelitvami ta pogoj
izpolnjuje.
Najprej si zastavimo vpraˇsanje, kje lahko pride v algoritmu na sliki 2.20 do dodatne porabe prostora, saj na prvi pogled ne zasledimo drugih podatkovnih struktur
kot vhodne tabele a. Izkaˇze se, da je vir dodatne porabe mehanizem rekurzije, ki
ga uporabljamo za evidenco ˇse neopravljenih porazdelitev. Namreˇc, ko tabelo razdelimo na dva dela, lahko neposredno nadaljujemo delo le na enem delu, podatke
o drugem pa moramo shraniti. Za to sta primerna podatkovna struktura sklad in
mehanizem rekurzije. Ker je dandanes mehanizem rekurzije vgrajen v praktiˇcno vse
programske jezike, so njegove podrobnosti pred programerjem skrite. Vendar, ker
ˇzelimo analizirati prav lastnosti tega mehanizma, bomo zapisali program za urejanje
s porazdelitvami tako, da bo rekurzijo uporabljal izrecno, kar nam bo omogoˇcilo, da
preverimo njene lastnosti.
Program je prikazan na sliki 2.22 z nekoliko veˇc podrobnosti kot prejˇsnji programi.
V vrsticah 4–12 so najprej zapisani potrebni podatkovni tipi, med katerimi opozarjamo na osnovni tip sklada StackRec, ki rabi za shranjevanje podatkov o podtabelah
prvotne tabele, in sicer v obliki leve in desne meje ter na tip SortStruc, ki zdruˇzuje
vse podatke, ki so potrebni pri urejanju. Vse procedure, ki so deklarirane v modulu
NRQuickSort na sliki 2.22, so procedurne konstante, ki so prirejene prav tipu SortStruc. Primerek tipa dinamiˇcno zgeneriramo s klicem procedure Init (vrstice 14–17).
Procedure Push, Pop in Empty v vrsticah 19–31 predstavljajo dobro znane osnovne
operacije, ki pripadajo podatkovni strukturi sklada.
V proceduri Sort (vrstice 33–46), ki dejansko opravlja urejanje, na zaˇcetku (vrstica
37) vstavimo v sklad podatke o celotni tabeli (leva meja je 1, desna, LEN (a)), nato
vstopimo v zanko (vrstice 38–45), ki z vrha sklada jemlje podatke o podtabelah in
vsakiˇc sproˇzi porazdelitev.
V kakˇsnem primeru pride do najveˇcje porabe prostora za sklad? Oˇcitno takrat,
ko je po vsakem izvajanju porazdelitvene procedure v vrstici 41 indeks i enak r in je
50
POGLAVJE 2. UREJANJE
1
2
4
5
5
6
7
8
9
10
11
12
14
14
15
16
17
19
19
21
21
22
24
24
26
26
27
29
29
30
31
33
33
34
36
36
37
38
39
40
41
42
43
44
45
46
48
48
MODULE NRQuickSort;
IMPORT A:=ArrSort,I :=IntSort,S :=Sort;
TYPE
StackRec=RECORD
l ,r :LONGINT
END;
PStack =POINTER TO Stack ;
Stack =ARRAY OF StackRec;
SortStruc∗=RECORD
a∗:A.PAPItem; s∗:PStack ; t∗:LONGINT
END;
PROCEDURE (VAR o:SortStruc)Init∗(m,n:LONGINT );
BEGIN (∗ dinamiˇcno generiramo tabelo a in sklad ∗)
NEW (o.a,m); NEW (o.s,n); o.t:=0
END Init;
PROCEDURE (VAR o:SortStruc)Push∗(l ,r :LONGINT );
BEGIN
o.s[o.t].l :=l ; o.s[o.t].r :=r ; INC (o.t)
END Push;
PROCEDURE (VAR o:SortStruc)Pop∗(VAR l ,r :LONGINT );
BEGIN
DEC (o.t); l :=o.s[o.t].l ; r :=o.s[o.t].r
END Pop;
PROCEDURE (VAR o:SortStruc)Empty∗():BOOLEAN ;
BEGIN RETURN o.t=0
END Empty;
PROCEDURE (VAR o:SortStruc)Sort∗;
VAR i,j ,l ,r : LONGINT ;
BEGIN
o.Push(1,LEN (o.a↑));
REPEAT
o.Pop(l ,r );
REPEAT i:=l ;j :=r ;
A.Partition(o.a↑,i,j ,o.a[((l +r )DIV 2)−1].k );
IF i <= r THEN o.Push(i,r ) END;
r :=j
UNTIL l >= r
UNTIL o.Empty()
END Sort;
END NRQuickSort.
Slika 2.22: Uporaba samostojnega sklada pri urejanju s porazdelitvami
51
2.2. NOTRANJE UREJANJE
metoda
n. zamenjave
n. vstavljanje
kopica
porazdelitve
n =1024
22
8
0
0
ˇcas (v stot. sek)
2048 5000 10000
93
576
2636
39
243
1103
1
4
13
0
2
5
20000
13297
6677
35
15
Slika 2.23: Rezultati urejanja razliˇcno dolgih zaporedij ˇstevil
velikost tabele, na katero se nanaˇsa nov ukaz iz vrstic 42 in 43, enaka 1. V takem
primeru bi algoritem dodal n ukazov (za urejanje podtabel velikosti 1) na sklad in bi
torej za sklad potrebovali prostor Θ(n) (do enakega pojava pride v primeru, ko je na
koncu porazdelitve, j = 1). Glede velikostnega reda se seveda niˇc ne spremeni, ˇce bi
algoritem postopal nekoliko bolj pametno in ukazov za urejanje podtabel velikosti 1
ne bi zapisoval (temveˇc le take ukaze, ki se nanaˇsajo na veˇcje podtabele). Seveda je
takˇsno obnaˇsanje algoritma v nasprotju s pogojem, ki smo ga omenili na zaˇcetku razdelka. Vendar se izkaˇze, da je reˇsitev tega problema presenetljivo preprosta: potrebno
je le primerjati velikosti intervalov [l, j] in [i, r] ter v sklad zapisati veˇcji interval. Na
ta naˇcin se velikost intervala, ki ga trenutno obdelujemo v zanki v vrsticah 40–44,
najmanj prepolovi in med izvajanjem zanke ne moremo zapisati veˇc kot log2 n ukazov
v sklad. Torej je potrebno zamenjati vrstic 42 in 43 z naslednjim stavkom:
IF (l < j )&(j −l >=r −i) THEN o.Push(l ,j );l :=i
ELSIF i < r THEN o.Push(i,r );r :=j
END
V tem primeru je moˇzno za velikost sklada izbrati log2 n.
2.2.8
Primerjava razliˇ
cnih metod urejanja
ˇ
Stiri
metode urejanja tabel (dve navadni in dve izboljˇsani) smo tudi praktiˇcno preizkusili. Tabela na sliki 2.23 prikazuje rezultate urejanja razliˇcno dolgih zaporedij 32bitnih ˇstevil. Za vsako dolˇzino smo nekajkrat nakljuˇcno generirali opisano zaporedje,
opravili meritev dejanske porabe ˇcasa (v stotinkah sekunde) na osebnem raˇcunalniku
in nato izraˇcunali povpreˇcen rezultat. Slika 2.24 pa podatke iz tabele 2.23 prikazuje
grafiˇcno v dvojno logaritemskem merilu.
2.2.9
Iskanje k-tega elementa v tabeli
Tehniko porazdelitve iz razdelka 2.2.7 lahko uporabimo tudi za reˇsevanje nekega dodatnega problema: podana je neurejena tabela in ˇzelimo poiskati k-ti element po
velikosti. Seveda je moˇzno nalogo reˇsiti tako, da tabelo uredimo in nato vzamemo
element z indeksom k. Toda ta naˇcin zahteva, kot ˇze vemo, ˇcas Θ(n log n). Zastavlja
52
POGLAVJE 2. UREJANJE
19000
10000
5000
1000
500
100
50
sek−2
?
•
........
...........
............
............
...........
.
.
.
.
.
.
.
.
.
.
.
....
............
...........
...........
............
............
.
.
.
.
.
.
.
.
.
.
....
............
............
............
............
...........
.
.
.
.
.
.
.
.
.
.
...........
............
............
............
............
.
.
.
.
.
.
.
.
.
.
.
..
............
...........
............
............
...... .
....... .......
....... .......
....... .......
.
.
.
.
.
.
.
.
......
....... .......
....... .......
....... .......
....... .......
.
.
.
.
.
.
.
.
.
.
....... ....
....... .......
....... .......
....... .......
?
•
?
•
?
10 •
◦
◦
2048
1
1024
5000
?
•
◦
10000
4.0683 · 10−4 n log10 n
....... .......
....................
3.324 · 10−5 n2
◦
urejanje s kopico
?
navadne zamenjave
urejanje s porazdelitvami
•
navadno vstavljanje
Slika 2.24: Grafiˇcna primerjava razliˇcnih metod urejanja
1
2
3
4
5
6
7
8
9
11
12
12
PROCEDURE Find ∗(VAR a:APItem;k : LONGINT );
VAR i,j ,l ,r : LONGINT ;
BEGIN
l :=1; r :=LEN (a);
WHILE l <r DO
i:=l ; j :=r ;
Partition(a,i,j ,a[k −1].k );
IF j <k THEN l :=i
ELSIF k <i THEN r :=j
END
END
END Find ;
Slika 2.25: Iskanje k-tega elementa po velikosti
◦
n
20000
2.3. ZUNANJE UREJANJE
53
se nam torej vpraˇsanje, ali je moˇzno na raˇcun bolj enostavne naloge zmanjˇsati ˇcas,
ki je potreben za njeno reˇsitev. Izkaˇze se, da je nalogo moˇzno reˇsiti z algoritmom, ki
je praktiˇcno istoveten algoritmu urejanja s porazdelitvami, le da moramo vzeti mejo
x = a[k] ter spremeniti postopek, ki sledi porazdelitvi. Pri porazdelitvi so moˇzni trije
izidi: element a[k] je bodisi manjˇsi od k-tega po velikosti, enak ali veˇcji. V prvem
primeru je meja med podtabelama, ki sta rezultat porazdelitve, manjˇsa od k, v drugem je meja toˇcno pri k-tem elementu in v tretjem primeru je meja veˇcja od k. V
prvem primeru nadaljujemo z reˇsevanjem iste naloge na podtabeli [j, r] (pri ˇcemer v
tej tabeli iˇsˇcemo k − j + 1 element); v drugem primeru smo reˇsitev naˇsli in v tretjem
primeru nadaljujemo z reˇsevanjem iste naloge na podtabeli [l, i].
Analiza porabe ˇ
casa. Glede na to, da je algoritem le nekoliko predelan algoritem
urejanja s porazdelitvami, je priˇcakovati, da ima podobne znaˇcilnosti. Tudi v tem
primeru je najslabˇsi ˇcas Θ(n2 ), kajti, ˇce je izid porazdelitve na vsakem koraku [1, m−1]
(m je velikost vsakokratne podtabele), je potrebno opraviti porazdelitev zaporedja
podtabel velikosti n, n − 1, . . . , 1, za kar je potreben kvadratiˇcen ˇcas. Ko pa imamo
m
sreˇco, je rezultat porazdelitve na vsakem koraku pribliˇzno [ m
2 , 2 ] in moramo opraviti
n n
porazdelitev na zaporedju podtabel velikosti n, 2 , 4 , . . . , 1, kar zahteva ˇcas Θ(n).
2.3
Zunanje urejanje
Pri razvijanju algoritmov za zunanje urejanje izhajamo iz osnovnih deklaracij, ki so
prikazane na sliki 2.26. V priˇcujoˇci knjigi se nimamo namena spuˇsˇcati v podrobnosti
operacij z datotekami, oziroma trakovi, zato bomo uporabljali doloˇcene procedure, ki
so deklarirane drugje, jih pa uporabnik modula za sortiranje lahko priredi spremenljivkam InitRd, InitWr, Rd in Wr (vrstice 23–25). Prvi dve proceduri pripravita trak
za branje ali pisanje, preostali dve pa nanj bereta ali piˇseta.
2.3.1
Navadno zlivanje
Navadno zlivanje predstavlja osnovo, oziroma izhodiˇsˇce za vse algoritme zunanjega
urejanja. Metoda deluje tako, da z vhodnega zaporedja bere podzaporedja dolˇzine
k, za katera privzemamo, da so ˇze urejena, in jih izmeniˇcno zapisuje na dva izhodna
trakova, nato pa s teh dveh trakov podzaporedja dolˇzine k zliva nazaj na vhodni
trak v podzaporedja dolˇzine 2k. Zlivanje dveh (urejenih) podzaporedij pomeni sestavljanje novega urejenega podzaporedja iz elementov prvotnih podzaporedij. Na
zaˇcetku je k = 1, opisani postopek pa se ponavlja, dokler ne preostane eno samo
dolgo (pod)zaporedje (gl. sliko 2.27). Opisana struktura algoritma je jasno razvidna
iz osnovnega bloka programa 2.2 (vrstice 53-60). Pri notranjih procedurah procedure
navadnega zlivanja naj opozorimo na znaˇcilno zgradbo procedure, ki zliva dve podzaporedji v novo podzaporedje dvakratne dolˇzine (MergeRun, ki zaseda vrstice 29–44):
sestavljena iz treh zank, od katerih se prva izvaja v primeru, ko sta oba trakova neprazna, oziroma ko ustrezni podzaporedji nista zakljuˇceni; druga (oziroma tretja) pa,
54
POGLAVJE 2. UREJANJE
1
2
4
5
5
6
7
8
10
10
11
12
13
14
15
16
17
18
19
20
22
23
23
24
25
26
27
MODULE FileSort;
IMPORT I :=IntSort;
TYPE
PAL=POINTER TO AL;
AL=ARRAY OF LONGINT ;
PAPItem∗=POINTER TO APItem;
APItem=ARRAY OF I .PItem;
PSeq∗=POINTER TO Seq;
Seq∗=RECORD
END ;
FSeqInit∗ =PROCEDURE(p:PSeq);
FRdItem∗ =PROCEDURE(p:PSeq):I .PItem;
FWrItem∗ =PROCEDURE(p:I .PItem;q:PSeq);
FCpyRun∗ =PROCEDURE(
inf ,outf :PSeq;
VAR pI :I .PItem;
VAR lastK :LONGINT );
FPPSort∗ =PROCEDURE(in:PSeq;VAR f :ARRAY OF PSeq):PSeq;
FNoParam∗=PROCEDURE;
VAR
InitRd ∗,InitWr ∗:FSeqInit;
Rd ∗:FRdItem;
Wr ∗:FWrItem;
CopyRun∗:FCpyRun;
SpecInit∗:FNoParam;
Slika 2.26: Osnovne deklaracije pri zunanjem urejanju
vhod:
3; 7; 1; 2; 8; 6; 5; 4
po prvi porazdelitvi: po prvem zlivanju: po drugi porazdelitvi: po drugem zlivanju:
3; 1; 8; 5
3, 7; 1, 2; 6, 8; 4, 5 3, 7; 6, 8
1, 2, 3, 7; 4, 5, 6, 8
7; 2; 6; 4
1, 2; 4, 5
po tretji porazdelitvi: po tretjem zlivanju:
1, 2, 3, 7
1, 2, 3, 4, 5, 6, 7, 8
4, 5, 6, 8
(Meje med podzaporedji so nakazane s podpiˇ
cji, ki pa rabijo le kot pomoˇ
c bralcu; sicer pa vhodni
podatki ne vsebujejo nobenega posebnega znaka, ki bi podzaporedja loˇ
ceval med seboj.)
Slika 2.27: Primer navadnega zlivanja
55
2.3. ZUNANJE UREJANJE
ko je prvi (oziroma drugi) trak neprazen, oziroma nima zakljuˇcenega podzaporedja.
Pri tem programu ni teˇzko oceniti njegovega ˇcasa delovanja: ocenimo ga s ˇcasom,
ki je potreben za branje trakov, saj je to najbolj potratna operacija. Naj bo ˇstevilo
podatkovnih zapisov N . Glede na to, da se dolˇzina urejenih podzaporedij po vsakem
zlivanju podvoji, je oˇcitno potrebnih log2 (N ) korakov porazdelitve in zlivanja, pri
ˇcemer na vsakem takem koraku trak s podatki preberemo dvakrat. Torej je ˇcas
operacije navadnega zlivanja Θ(N log2 (N )). Ker smo na ta naˇcin ˇze takoj dosegli
“magiˇcno” mejo Θ(N log(N )), so naprej moˇzne le ˇse izboljˇsave za konstanten faktor.
Vendar pa imamo glede tega ˇse znatne zaloge, kot bomo videli kasneje.
Ko razmiˇsljamo o moˇznih izboljˇsavah navadnega zlivanja, nam pride na misel nekaj
idej:
1. odpraviti posebna koraka porazdelitve in zlivanja ter porazdelitev na dva trakova izvajati istoˇcasno z zlivanjem. Ker v tem primeru potrebujemo dva vhodna
in dva izhodna trakova, pravimo tej metodi uravnoteˇzeno zlivanje. Uˇcinek izboljˇsave je, da ˇcas operacije prepolovimo;
2. poveˇcati hitrost z uporabo veˇc vhodnih trakov. Takemu zlivanju pravimo veˇcsmerno
zlivanje. Ni se teˇzko prepriˇcati, da veˇcsmerno zlivanje z n vhodnimi trakovi
zmanjˇsa ˇcas z N log2 (N ) (kar velja za dva trakova) na N logn (N );
3. v primeru, ko znotraj vhodnega zaporedja ˇze obstajajo urejena podzaporedja,
zlivati taka podzaporedja in ne podzaporedja vnaprej doloˇcene dolˇzine. Takemu
zlivanju pravimo naravno zlivanje, ker izkoriˇsˇca ˇze obstojeˇco urejenost vhodnega
traku. Najveˇcje urejeno podzaporedje v zaporedju, ki ga urejamo, poimenujemo
ˇceta. Bodimo pozorni, da ima “najveˇcje” pomen, da zaporedja ni moˇzno podaljˇsati s prikljuˇcitvijo sosednih elementov in ne, da je tako zaporedje po dolˇzini
najdaljˇse (glej sliko 2.28). Izboljˇsava, ki jo vnaˇsa naravno zlivanje, pa je odvisna od stopnje predhodne urejenosti vhodnih podatkov, oziroma od zaˇcetnega
ˇstevila ˇcet.
Program 2.2: Navadno zlivanje
1
2
4
4
6
6
7
9
PROCEDURE MergeSort∗(io,aux1 ,aux2 :PSeq);
VAR k ,l :LONGINT ;
PROCEDURE InitLoop;
BEGIN
InitRd (io); InitWr (aux1 ); InitWr (aux2 )
END InitLoop;
se nadaljuje
56
POGLAVJE 2. UREJANJE
Navadno zlivanje (nadaljevanje)
9
10
12
12
13
14
15
16
17
18
19
21
22
22
23
24
26
26
27
29
29
30
31
32
33
34
35
37
37
38
39
40
41
42
44
44
46
47
47
48
49
50
51
53
PROCEDURE Distribute;
VAR p:I .PItem;
PROCEDURE CopyKseq(in,out:PSeq;VAR p:I .PItem):BOOLEAN ;
VAR i:LONGINT ;
BEGIN i:=0;
WHILE (p#NIL) & (i<k ) DO
Wr (p,out); INC (i); p:=Rd (in)
END;
RETURN i=k
END CopyKseq;
BEGIN
p:=Rd (io);
WHILE CopyKseq(io,aux1 ,p) & CopyKseq(io,aux2 ,p) DO END
END Distribute;
PROCEDURE Merge(in1 ,in2 ,out:PSeq);
VAR p1 ,p2 :I .PItem;
PROCEDURE MergeRun ;
VAR i1 ,i2 :LONGINT ;
BEGIN i1 :=0;i2 :=0;
WHILE (p1 #NIL)&(i1 <k )&(p2 #NIL)&(i2 <k ) DO
IF p1 .k <p2 .k THEN
Wr (p1 ,out);INC (i1 );p1 :=Rd (in1 )
ELSE Wr (p2 ,out);INC (i2 );p2 :=Rd (in2 )
END
END;
WHILE (p1 #NIL)&(i1 <k ) DO
Wr (p1 ,out);INC (i1 );p1 :=Rd (in1 )
END;
WHILE (p2 #NIL)&(i2 <k ) DO
Wr (p2 ,out);INC (i2 );p2 :=Rd (in2 )
END
END MergeRun;
BEGIN
InitWr (out);InitRd (in1 );InitRd (in2 );
p1 :=Rd (in1 ); p2 :=Rd (in2 );
REPEAT MergeRun; INC (l )
UNTIL (p1 = NIL) & (p2 = NIL)
END Merge;
se nadaljuje
57
2.3. ZUNANJE UREJANJE
vhod:
7 ; 3, 6, 11; 8, 13; 9, 12; 1, 16; 10; 4, 15; 5; 2, 14;
po porazdelitvi:
7, 8, 13; 1, 16; 4, 15; 2, 14;
3, 6, 11; 9, 12; 10; 5;
po prvem zlivanju (in porazdelitvi):
3, 6, 7, 8, 11, 13; 4, 10, 15;
1, 9, 12, 16; 2, 5, 14;
po drugem zlivanju (in porazdelitvi):
1, 3, 6, 7, 8, 9, 11, 12, 13, 16;
2, 4, 5, 10, 14, 15;
po tretjem zlivanju:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16;
(Meje med ˇ
cetami so nakazane s podpiˇ
cji, ki pa rabijo le kot pomoˇ
c bralcu; sicer pa vhodni podatki
ne vsebujejo nobenega posebnega znaka, ki bi loˇ
ceval ˇ
cete med seboj.)
Slika 2.28: Primer naravnega, uravnoteˇzenega, dvosmernega zlivanja
Navadno zlivanje (nadaljevanje)
53
54
55
56
57
58
59
60
BEGIN k :=1;
REPEAT InitLoop;
Distribute; (∗ porazdelitev ∗)
l :=0;
Merge(aux1 ,aux2 ,io) ; (∗ zlivanje ∗)
k :=2∗k
UNTIL l =1;
END MergeSort;
Navadno zlivanje (konec)
2.3.2
Naravno, uravnoteˇ
zeno, dvosmerno zlivanje
V tem razdelku bomo opisali proceduro, ki vsebuje dve od prej omenjenih treh moˇznih
izboljˇsav navadnega zlivanja: odpravili bomo poseben korak porazdelitve in namesto
podzaporedij dolˇzine k, zlivali ˇcete. Zlivanje ˇcet pomeni, da moramo namesto procedure CopyKseq (vrstice 12-19 v programu 2.2) uporabljati proceduro SimpleCopyRun:
PROCEDURE SimpleCopyRun(
inf ,outf :PSeq;
VAR pI :I .PItem;
VAR lastK :LONGINT );
(∗ Prepis ene ˇcete; privzetek: na zaˇcetku p # NIL ∗)
BEGIN
REPEAT Wr (pI ,outf ); lastK :=pI .k ; pI :=Rd (inf )
UNTIL (pI =NIL) OR (lastK >pI .k )
END SimpleCopyRun;
(2.23)
58
POGLAVJE 2. UREJANJE
ki pa jo uporabljamo tako, da pred uporabo programa priredimo procedurni spremenljivki CopyRun (na sliki 2.26) proceduro SimpleCopyRun (posreden doseg do procedure SimpleCopyRun uporabljamo zato, ker bomo kasneje potrebovali dve razliˇcici
procedure CopyRun in jih bo primerno izbirati tako, da enkrat spremenljivki CopyRun priredimo eno proceduro, drugiˇc pa drugo).
Program za naravno, uravnoteˇzeno, dvosmerno zlivanje je prikazan kot program
2.3, pri ˇcemer podrejena procedura Distribute(t1, t2, t3, t4) (vrstice 32-47) zlije in
porazdeli ˇcete s trakov t1 in t2 na t3 in t4, kot rezultat pa vrne ˇstevilo zapisanih ˇcet.
Program 2.3: Naravno, uravnoteˇ
zeno, dvosmerno zlivanje
1
3
3
4
6
6
7
8
9
10
11
12
14
14
15
16
17
18
19
20
22
22
23
24
25
26
27
28
29
30
32
32
33
35
35
PROCEDURE NatBal2MergeSort∗(io,aux1 ,aux2 ,aux3 ,aux4 :PSeq):PSeq;
PROCEDURE InitProg;
VAR p:I .PItem;last:LONGINT ;
BEGIN
InitRd (io); p:=Rd (io);
InitWr (aux1 ); InitWr (aux2 );
(∗ zaˇcetna porazdelitev ∗)
REPEAT CopyRun(io,aux1 ,p,last) ;
IF p#NIL THEN CopyRun(io,aux2 ,p,last) END
UNTIL p=NIL
END InitProg;
PROCEDURE MergeRun(in1 ,in2 ,out:PSeq;VAR p1 ,p2 :I .PItem):BOOLEAN ;
(∗ Zlivanje po ene ˇcete z in1 in in2 na out ∗)
VAR last1 ,last2 :LONGINT ;
BEGIN last1 :=MIN (LONGINT );last2 :=last1 ;
WHILE (p1 #NIL)&(last1 <=p1 .k )&(p2 #NIL)&(last2 <=p2 .k ) DO
IF p1 .k <p2 .k THEN Wr (p1 ,out);last1 :=p1 .k ;p1 :=Rd (in1 )
ELSE Wr (p2 ,out);last2 :=p2 .k ;p2 :=Rd (in2 )
END
END;
IF (p1 #NIL)&(last1 <=p1 .k ) THEN
CopyRun(in1 ,out,p1 ,last1 )
END;
IF (p2 #NIL)&(last2 <=p2 .k ) THEN
CopyRun(in2 ,out,p2 ,last2 )
END;
RETURN (p1 #NIL) OR (p2 #NIL)
END MergeRun;
PROCEDURE Distribute(aux1 ,aux2 ,aux3 ,aux4 :PSeq):LONGINT ;
VAR l :LONGINT ; p1 ,p2 :I .PItem;
BEGIN
l :=0;
se nadaljuje
2.3. ZUNANJE UREJANJE
59
Naravno, uravnoteˇ
zeno, dvosmerno zlivanje (nadaljevanje)
36
37
38
39
40
41
42
43
45
45
46
47
49
49
51
51
52
54
54
55
InitRd (aux1 );InitRd (aux2 );
InitWr (aux3 ); InitWr (aux4 );
p1 :=Rd (aux1 ); p2 :=Rd (aux2 );
LOOP INC (l );
IF MergeRun(aux1 ,aux2 ,aux3 ,p1 ,p2 ) THEN
INC (l );
IF ∼MergeRun(aux1 ,aux2 ,aux4 ,p1 ,p2 ) THEN EXIT END
ELSE EXIT
END
END;
RETURN l
END Distribute;
BEGIN InitProg;
LOOP
IF Distribute(aux1 ,aux2 ,aux3 ,aux4 )=1 THEN RETURN aux3
ELSIF Distribute(aux3 ,aux4 ,aux1 ,aux2 )=1 THEN RETURN aux1
END
END
END NatBal2MergeSort;
Naravno, uravnoteˇ
zeno, dvosmerno zlivanje (konec)
Znaˇcilnosti prikazanih procedur so naslednje:
1. pri naravnem zlivanju je potrebno uporabljati spremenljivko last oziroma last1
in last2 (vrstice 4, 16) za to, da doloˇcimo konec ˇcete;
2. procedura MergeRun (vrstice 14–30) ima ˇse vedno znaˇcilno zgradbo sestavljeno
iz treh zank (ˇceprav sta dve zanki pravzaprav klica posebne procedure CopyRun);
3. preusmerjanje izhoda med dvema trakovoma opravljamo z loˇcenima klicema
procedure MergeRun znotraj procedure Distribute (vrstici 40, 42).
2.3.3
Naravno, uravnoteˇ
zeno, veˇ
csmerno zlivanje
Program je prikazan kot program 2.4. Njegova poglavitna zanimivost pa je procedura,
ki usteza proceduri MergeRun iz programa 2.2. Slednja namreˇc vsebuje po eno zanko
za vsako neprazno mnoˇzico vhodnih trakov. V primeru, ko je ˇstevilo vhodnih trakov
enako 2, je takih podmnoˇzic 3, v sploˇsnem pa 2n − 1, kjer je n ˇstevilo vhodnih trakov.
Oˇcitno je torej, da moramo poiskati drugaˇcno obliko procedure MergeRun za primer,
ko je n veˇcje od 2. Reˇsitev je prikazana na sliki 2.29: trakovi (oziroma kazalci nanje)
so urejeni v tabelo f , ki sta ji pridruˇzeni dve spremenljivki, ner, ki je enaka ˇstevilu
trakov, na katerih trenutna ˇceta ˇse ni zakljuˇcena, in nes, ki je enaka ˇstevilu trakov, ki
60
POGLAVJE 2. UREJANJE
ner
(a) f
nes
f [x]
ner
nes
(b) f
Slika 2.29: Postopek ob zakljuˇcku ˇcete oziroma traku
ˇ se tabela zaˇcne z indeksom 1, sta to obenem indeksa
ˇse niso do konca prebrani. Ce
zadnjega traku, ki ima ˇse nedokonˇcano ˇceto, ter zadnjega neprebranega traku. Denimo
sedaj, da se je na nekem traku ˇceta konˇcala (na sliki 2.29 je to trak z indeksom x).
V takem primeru zamenjamo f [x] in f [ner] ter zmanjˇsamo ner za 1. Na ta naˇcin se
med zlivanjem ene ˇcete vrednost ner postopno zmanjˇsuje, dokler ne postane enaka
0. Takrat je postopek zlivanja ene ˇcete konˇcan. Podobno ravnamo s spremenljivko
nes. Proceduri Distribute v programu 2.3 sedaj ustreza zanka vrste REPEAT v
proceduri MergeRun, ki se konˇca, ko postane spremenljivka ner enaka 0 (vrstice 49–
77 v programu 2.4).
Program 2.4: Naravno, uravnoteˇ
zeno, veˇ
csmerno zlivanje
1
3
3
4
5
6
7
8
9
10
11
12
14
14
15
16
17
18
19
PROCEDURE NatBalMultiMergeSort∗(in:PSeq;VAR f :ARRAY OF PSeq):PSeq;
VAR
h, (∗ ˇstevilo vhodov in izhodov ∗)
dest, (∗ indeks izhoda, na katerega piˇsemo ∗)
nes, (∗ ˇstevilo nepraznih vhodov ∗)
l :LONGINT ; (∗ ˇstevilo ˇcet, zapisanih v tekoˇci
iteraciji ∗)
pa:PAPItem;(∗ tabela kazalcev na vhodne elemente ∗)
pl :PAL; (∗ tabela vrednosti kljuˇcev, ki so bili
nazadnje zapisani na izhode ∗)
ppa:I .PItem;
ppl :LONGINT ;
PROCEDURE InitProg;
VAR i:LONGINT ;p:I .PItem;last:LONGINT ;
BEGIN
InitRd (in); p:=Rd (in);
h:=LEN (f ) DIV 2;
NEW (pa,h);NEW (pl ,h);
se nadaljuje
61
2.3. ZUNANJE UREJANJE
Naravno, uravnoteˇ
zeno, veˇ
csmerno zlivanje (nadaljevanje)
20
21
22
23
24
25
26
27
29
30
30
32
32
33
34
35
36
37
38
39
40
41
42
43
45
46
46
48
48
49
50
51
52
53
54
55
56
58
58
59
60
61
62
63
64
(∗ zaˇcetna porazdelitev ∗)
FOR i:=1 TO h DO InitWr (f [i−1]) END;
i:=h;
REPEAT
IF i=h THEN i:=1 ELSE INC (i) END;
CopyRun(in,f [i−1],p,last)
UNTIL p=NIL
END InitProg;
PROCEDURE InitLoop;
VAR i:LONGINT ;p:PSeq;
BEGIN l :=0;
FOR i:=1 TO h DO
InitRd (f [i−1]); InitWr (f [h+i−1])
END;
i:=1;nes:=h;
(∗ toˇcno ˇstevilo nepraznih trakov ∗)
WHILE i<=nes DO
pa[i−1]:=Rd (f [i−1]);
IF pa[i−1]#NIL THEN INC (i)
ELSE p:=f [i−1]; f [i−1]:=f [nes−1];
f [nes−1]:=p; DEC (nes)
END
END
END InitLoop;
PROCEDURE MergeRun ;
VAR i,
minx ,
ner (∗ ˇstevilo nedokonˇcanih vhodnih ˇcet ∗)
:LONGINT ;
p:PSeq;
BEGIN ner :=nes;
IF dest=2∗h THEN dest:=h+1 ELSE INC (dest) END;
(∗ zapiˇsemo eno ˇceto ∗)
REPEAT
minx :=1;
FOR i:=2 TO ner DO
IF pa[i−1].k <pa[minx −1].k THEN minx :=i END
END;
Wr (pa[minx −1],f [dest−1]);
pl [minx −1]:=pa[minx −1].k ;
pa[minx −1]:=Rd (f [minx −1]);
se nadaljuje
62
POGLAVJE 2. UREJANJE
Naravno, uravnoteˇ
zeno, veˇ
csmerno zlivanje (nadaljevanje)
65
66
67
68
69
70
71
72
73
74
75
76
77
79
79
80
82
82
83
85
85
86
88
88
90
90
91
92
94
94
95
97
97
98
99
IF (pa[minx −1]=NIL)
OR (pl [minx −1]>pa[minx −1].k )
THEN (∗ konec ˇcete ∗)
p:=f [minx −1]; f [minx −1]:=f [ner −1]; f [ner −1]:=p;
ppa:=pa[minx −1];pa[minx −1]:=pa[ner −1];pa[ner −1]:=ppa;
ppl :=pl [minx −1];pl [minx −1]:=pl [ner −1];pl [ner −1]:=ppl ;
DEC (ner );
IF pa[ner ]=NIL THEN(∗ konec traku ∗)
p:=f [ner ]; f [ner ]:=f [nes−1]; f [nes−1]:=p;
ppa:=pa[ner ]; pa[ner ]:=pa[nes−1];pa[nes−1]:=ppa;
ppl :=pl [ner ]; pl [ner ]:=pl [nes−1];pl [nes−1]:=ppl ;
DEC (nes)
END
END
UNTIL ner =0
END MergeRun;
PROCEDURE SwitchTapes;
VAR i:LONGINT ;p:PSeq;
BEGIN
FOR i:=1 TO h DO
p:=f [i−1]; f [i−1]:=f [h+i−1]; f [h+i−1]:=p
END
END SwitchTapes;
BEGIN InitProg;
dest:=h;
REPEAT InitLoop;
REPEAT
INC (l ); MergeRun
UNTIL nes=0;
SwitchTapes
UNTIL l =1 ;
RETURN f [h]
END NatBalMultiMergeSort;
Naravno, uravnoteˇ
zeno, veˇ
csmerno zlivanje (konec)
2.3.4
Polifazno urejanje
Do sedaj smo prvotni postopek navadnega zlivanja izboljˇsali na tri naˇcine: odpravili
smo poseben korak porazdelitve, upoˇstevali obstojeˇco urejenost v vhodnem zaporedju
in omogoˇcili uporabo veˇc vhodnih trakov. Ali je mogoˇce postopek ˇse izboljˇsati? Pri
uravnoteˇzenem, naravnem veˇcsmernem zlivanju opazimo, da je izkoriˇsˇcenost izhodnih
trakov nizka. Namreˇc, od n izhodnih trakov je naenkrat aktiven le eden, ostali miru-
63
2.3. ZUNANJE UREJANJE
l\i
1
1
7
2
3
4
5
3
1
0
1
2
6
3
4
4
0
b
0
2
1
0
c
a
2
0
1
0
l\i
0
1
2
3
4
4
2
1
0
ˇ
(a) Stevilo
ˇ
cet na posameznih
trakovih (i) v trenutkih (l), ko
se eden od trakov izprazni
1
1
1
2
4
7
2
0
1
2
3
6
3
0
1
1
2
4
4
0
0
0
0
0
(b) Isti primer potem, ko smo vrstice zasukali tako, da je trak z
najveˇ
cˇ
cetami na prvem mestu in
jih uredili nasprotno kot v 2.30a
Slika 2.30: Primer polifaznega urejanja s ˇstirimi trakovi
jejo in ˇcakajo, da na njih pride vrsta. Zdi se nam, da bi bil postopek najhitrejˇsi, ˇce bi
lahko od celotnega ˇstevila n trakov uporabljali n − 1 kot vhodne trakove in le enega
kot izhodnega.
Tako zasnovano urejanje, ki mu pravimo polifazno urejanje, bomo prikazali na
primeru na sliki 2.30a, kjer uporabljamo ˇstiri trakove. Pri trakovih prikazujemo le
ˇstevilo ˇcet na posameznem traku, ker identiteta posameznega zapisa v tem primeru
ni pomembna. Osnovna ideja je, da vedno uporabljamo tri trakove kot vhodne in
enega kot izhodnega. Ko se neki vhodni trak izprazni, postane takoj izhodni trak in
dotedanji izhodni trak postane vhodni. V prvi vrstici na sliki 2.30a smo trakove uredili
po padajoˇcem ˇstevilu ˇcet. Oˇcitno lahko zlivamo na trak ˇstevilka 4 do trenutka, ko se
trak ˇstevilka 3 izprazni (ko ˇstevilo ˇcet na njem doseˇze vrednost 0). Do tega trenutka
smo s trakov 1-3 prebrali po 4 ˇcete in prav toliko zapisali na trak ˇstevilka 4. V vrstici
2 se to vidi po tem, da smo od vrednosti v stolpcih 1-3 odˇsteli 4 in prav toliko dodali
stolpcu 4. Sedaj postane trak 3 izhodni trak in postopek nadaljujemo. V naslednji
fazi na trak 3 zapiˇsemo 2 ˇceti, po ˇcemer se izprazni trak 2 in takoj postane izhodni.
V naslednji fazi zapiˇsemo na trak 2 1 ˇceto, kar ima za posledico, da se trak 1 izprazni,
na vseh ostalih trakovih pa je prisotna ena sama ˇceta. Konˇcno zlijemo s trakov 2–4
na trak 1 po eno ˇceto in na traku 1 dobimo eno samo ˇceto. Iz opisanega sledi, da je
osnovna relacija med ˇstevili ˇcet na posameznih vhodnih trakovih in izhodnem traku,
a=b+c
(2.24)
[gl. sliko 2.30a].
Ko analiziramo polifazno urejanje, ugotovimo, da je bistveno odvisno od konkreˇ bi
tnih ˇstevil, ki jih izberemo kot zaˇcetna ˇstevila ˇcet na posameznih trakovih. Ce
ta ˇstevila izbrali nakljuˇcno, postopka nikakor ne bi uspeˇsno konˇcali. Kot primer je
potrebno le pomisliti na izbiro, ko je na vseh trakovih enako ˇstevilo ˇcet. V takem
primeru bi po zlivanju dobili en trak z nekim ˇstevilom (daljˇsih) ˇcet in n − 1 trakov
ˇ bi hoteli postopek nadaljevati, bi morali ponoviti zaˇcetno pos ˇstevilom ˇcet, 0. Ce
ˇ hoˇcemo izpeljati pravilo,
razdeljevanje ˇcet, kar pa je seveda ˇcasovno potratno. Ce
64
POGLAVJE 2. UREJANJE
po katerem se ravnajo ˇstevila ˇcet na posameznih trakovih, zato da postopek poteka
najuˇcinkoviteje, moramo tabelo na sliki 2.30a nekoliko preurediti: vsako naslednjo
vrstico kroˇzno zasukamo za eno mesto v desno in na ta naˇcin vse niˇcelne elemente
poravnamo v en stolpec, nato pa ˇse vrstice preuredimo v nasprotnem vrstnem redu
ˇ ˇstevilo ˇcet na traku i v vrstici
kot na sliki 2.30a. Na ta naˇcin dobimo sliko 2.30b. Ce
l
l na sliki 2.30b zaznamujemo z ai , se relacija (2.24) spremeni v
al+1
= ali+1 + al1 = al1 + ali+1 .
i
(2.25)
Na podlagi pravkar zapisane rekurenˇcne relacije in zaˇcetnega podatka a01 = 1, a0i = 0
pri i > 1 je moˇzno za poljubno ˇstevilo trakov n sestaviti tabelo, ki je podobna tabeli
na sliki 2.30b.
Shema celotnega postopka polifaznega urejanja je, da nek vhodni trak z elementi,
ki jih ˇzelimo urediti, porazdelimo na n−1 trakov (kjer je n ˇstevilo trakov), in sicer tako
kot narekuje vrstica l tabele (ki je podobna tabeli 2.30b pri izbranem n), pri ˇcemer l
izberemo kot indeks prve vrstice, v kateri je vsota elementov veˇcja ali enaka ˇstevilu
vhodnih ˇcet. Preden pa se zaˇcnemo ukvarjati s podrobnostmi realizacije algoritma je
ˇ relacijo (2.25) uporabimo veˇckrat, dobimo
dobro, da dobimo obˇcutek za ˇstevila ali . Ce
za al1 naslednjo relacijo:
al1 = al−1
+ al−2
+ . . . + al−n+1
,
1
1
1
(2.26)
ki pa moˇcno spominja na definicijo dobro znanih Fibonaccijevih ˇstevil
fl = fl−1 + fl−2
(2.27)
(koliˇcina fl ustreza al1 ). Zato bomo ˇstevilom al1 v enaˇcbi (2.26) rekli Fibonaccijeva
ˇstevila reda n − 2 [red Fibonaccijevega ˇstevila je za ena manjˇsi kot ˇstevilo ˇclenov na
desni strani (2.26)]. Glede na to, da navadna Fibonaccijeva ˇstevila (reda 1) naraˇsˇcajo
“pribliˇzno kot” 2l (gl. nalogo 10), lahko sklepamo, da Fibonaccijeva ˇstevila reda n
naraˇsˇcajo “pribliˇzno kot” (n + 1)l .
Preden pa pravkar opisano idejo o zgradbi programa za polifazno urejanje spremenimo v delujoˇci program, je potrebno razreˇsiti dva drobna problema: 1. kako doloˇciti
indeks vrstice l v tabeli 2.30b, ki ga je potrebno uporabiti in 2. glede na to, da smo
pravkar ugotovili, da je postopek polifaznega urejanja kritiˇcno odvisen od ˇstevila ˇcet
na posameznih trakovih, kaj storiti, ko vsota ˇstevil v vrstici l ni enaka ˇstevilu vhodnih
ˇcet.
Na prvi pogled bi kazalo, da je za reˇsitev problema 1. zgoraj potrebno prebrati
ves vhod in preˇsteti ˇcete. Vendar se izkaˇze, da se temu lahko izognemo. Zaˇcnemo s
privzetkom, da je ˇzelena vrednost l enaka 1, nato preberemo ˇstevilo ˇcet, ki je enako
vsoti ˇstevil v vrstici l = 1 (na primer, v tabeli na sliki 2.30b je vsota ˇstevil v vrstici
ˇ je po koncu te faze vhodni trak
l = 1 enaka 3) in jih porazdelimo po trakovih. Ce
prazen, smo postopek konˇcali, sicer spremenimo privzetek tako, da poveˇcamo l za 1
in v novi fazi postopka preberemo ˇstevilo ˇcet, ki je enako razliki med vsotama ˇstevil v
vrsticah l+1 in l, ter te ˇcete porazdelimo skladno z vrednostmi v posameznih stolpcih.
Tako nadaljujemo, dokler na koncu neke faze trak ni prazen.
2.3. ZUNANJE UREJANJE
65
Reˇsitev problema 2. zgoraj je tudi razmeroma preprosta: ko se vhodni trak izprazni
preden smo prebrali ˇstevilo ˇcet, ki je enako vsoti ˇstevil v neki vrstici, zapiˇsemo mankajoˇce ˇcete v obliki “navideznih” ˇcet, ki so prisotne samo zato, da se postopek izide.
Takoj pa, ko smo sprejeli odloˇcitev o navideznih
ˇcetah, se postavi vpraˇsanje, kako jih porazdeliti in
8
seveda, kako jih predstavljati. Zadevo bomo prika7
6
zali na primeru s slike 2.30b, ko je ˇstevilo trakov 4.
5
Denimo, da izvajamo postopek porazdeljevanja in
4
smo konˇcali porazdeljevanje ˇcet, ki ustrezajo l = 3,
3
ne da bi vhodni trak izpraznili. Nato poveˇcamo l
2
1
na 4 in nadaljujemo z branjem. Po treh ˇcetah ugo0
tovimo, da je vhodni trak prazen. Kako porazdeliti
0 1 2 3 4 5
prebrane tri ˇcete in preostalih 5 navideznih ˇcet? Ali
je primerno vse tri resniˇcne ˇcete zapisati na trak 1 Slika 2.31: Porazdelitev praznih
ali pa kako drugaˇce? Izkaˇze se, da je koristen nasle- ˇcet
dnji premislek: postopek je najuˇcinkovitejˇsi takrat,
ko se dolˇzina ˇcet pri zlivanju najhitreje poveˇcuje.
To pa doseˇzemo takrat, ko pri zlivanju ne zlivamo navideznih in resniˇcnih ˇcet. Zato
navidezne ˇcete ˇcimbolj enakomerno porazdelimo po trakovih in jih kasneje zlivamo
med seboj, preostale, resniˇcne ˇcete pa porazdelimo tako, kot predpisuje tabela na sliki
2.30b. Postopek enakomernega porazdeljevanja navideznih ˇcet prikazuje slika 2.31:
viˇsina grafa pri traku i je ˇstevilo ˇcet, ki bi jih morali zapisati na trak i, da doseˇzemo
ˇstevilo ali (pri izbranem l). Enakomerno porazdeljenost doseˇzemo, ˇce navidezne ˇcete
(belo obarvano) pustimo “na dnu” grafa, medtem ko resniˇcne ˇcete (sivo) pustimo na
vrhu. V programu postopamo tako, da zaˇcnemo s celotno povrˇsino grafa pobarvano
belo, nato pa se sprehajamo po vodoravnih trakovih povrˇsine in vsakiˇc, ko preberemo
neko ˇceto, spremenimo eno enoto povrˇsine v sivo (zaradi tega se opisan naˇcin porazˇ se sredi postopka
deljevanja ˇcet imenuje “vodoravna strategija porazdeljevanja”). Ce
vhodni trak izprazni, predstavlja preostala bela povrˇsina navidezne ˇcete. Iz opisa
postopka sledi, da so navidezne ˇcete porazdeljene po trakovih pribliˇzno enakomerno,
kar pomeni, da v postopku zlivanja lahko zlivamo bodisi samo navidezne ˇcete ali pa
samo resniˇcne ˇcete. Obenem se tudi ponuja enostavna reˇsitev problema predstavitve
navideznih ˇcet. Namreˇc pri porazdeljevanju potrebujemo ˇstevec, katerega vrednost je
ˇstevilo manjkajoˇcih ˇcet do ˇstevila ali . Ko se vhodni trak izprazni, pa je prav to ˇstevilo
potrebno ˇstevilo navideznih ˇcet. Torej: navidezne ˇcete predstavljamo z vrednostjo
nekega ˇstevca, ki je prirejen traku.
66
POGLAVJE 2. UREJANJE
Program 2.5: Polifazno urejanje
1
2
3
4
5
6
7
8
9
10
11
13
13
14
16
16
18
18
19
20
21
22
23
24
25
26
28
28
29
30
31
32
33
34
35
36
37
38
40
40
41
43
43
44
PROCEDURE PolyphaseSort∗(in:PSeq;VAR f :ARRAY OF PSeq):PSeq;
VAR j , (∗ indeks tekoˇcega traku pri porazdeljevanju ∗)
k , (∗ ˇstevilo nepraznih ˇcet ∗)
l , (∗ raven (nivo) porazdeljevanja ∗)
n, (∗ ˇstevilo trakov ∗)
z :LONGINT ;(∗ ˇstevilo ˇcet, ki jih zlivamo na tekoˇci ravni ∗)
pa:PAPItem; (∗ “okno” na vhod ∗)
a, (∗ ˇstevila ˇcet na trakovih na ravni l ∗)
d , (∗ ˇstevila praznih ˇcet na trakovih na ravni l ∗)
last, (∗ zadnji kljuˇc, ki je bil zapisan na posamezen trak ∗)
t:PAL; (∗ indeksi trakov z nepraznimi ˇcetami ∗)
PROCEDURE Select;
VAR i,z :LONGINT ;
BEGIN
IF d [j ] < d [j +1] THEN INC (j )
ELSE
IF d [j ]=0 THEN INC (l );z :=a[1];
FOR i:=1 TO n−1 DO d [i]:=z +a[i+1]−a[i];
a[i]:=z +a[i+1]
END;
END;
j :=1
END;
DEC (d [j ])
END Select;
PROCEDURE InitProg;
VAR i:LONGINT ;
BEGIN
n:=LEN (f );
NEW (a,n+1);NEW (d ,n+1);NEW (last,n+1);
NEW (pa,n+1);NEW (t,n+1);
FOR i:=1 TO n−1 DO
a[i]:=1;d [i]:=1;InitWr (f [i−1])
END ;
l :=1;j :=1;a[n]:=0;d [n]:=0
END InitProg;
PROCEDURE Distribute;
VAR p:I .PItem;i:LONGINT ;
BEGIN
SpecInit; (∗ pri navadnem polifaznem urejanju, brez uˇcinka ∗)
InitRd (in);p:=Rd (in);
se nadaljuje
67
2.3. ZUNANJE UREJANJE
Polifazno urejanje (nadaljevanje)
45
46
47
48
49
50
51
53
54
54
55
56
58
58
59
61
61
62
63
64
66
67
67
69
69
70
72
72
73
74
75
76
77
78
79
80
81
82
83
85
85
86
88
REPEAT Select; CopyRun(in,f [j −1],p,last[j ])
UNTIL (p=NIL) OR (j =n−1);
WHILE p#NIL DO Select;
IF last[j ]>p.k THEN CopyRun(in,f [j −1],p,last[j ])
ELSE CopyRun(in,f [j −1],p,last[j ]);
IF p#NIL THEN CopyRun(in,f [j −1],p,last[j ])
ELSE INC (d [j ])
END
END
END;
FOR i:=1 TO n−1 DO InitRd (f [i−1]); pa[i]:=Rd (f [i−1]) END
END Distribute;
PROCEDURE InitInnerLoop;
VAR i:LONGINT ;
BEGIN
k :=0;
FOR i:=1 TO n−1 DO
IF d [i]>0 THEN DEC (d [i])
ELSE INC (k ); t[k ]:=i
END
END
END InitInnerLoop;
PROCEDURE MergeNonEmptyRuns;
VAR i,mx :LONGINT ;
BEGIN
REPEAT i:=1; mx :=1 ;
WHILE i < k DO
INC (i);
IF pa[t[i]].k < pa[t[mx ]].k THEN mx :=i END
END;
(∗ t[mx ] vsebuje najmanjˇsi element;
zapiˇsemo ga na f [n−1] ∗)
Wr (pa[t[mx ]],f [n−1]);last[t[mx ]]:=pa[t[mx ]].k ;
pa[t[mx ]]:=Rd (f [t[mx ]−1]);
IF (pa[t[mx ]]=NIL) OR ( last[t[mx ]] > pa[t[mx ]].k ) THEN
(∗ konec ˇcete na tem traku ∗)
t[mx ]:=t[k ]; DEC (k )
END
UNTIL k =0
END MergeNonEmptyRuns;
se nadaljuje
68
POGLAVJE 2. UREJANJE
Polifazno urejanje (nadaljevanje)
88
89
91
91
92
93
94
95
96
97
98
99
100
101
102
104
104
105
106
107
108
109
110
111
112
113
115
115
116
117
118
119
PROCEDURE TermLoop;
VAR i,dn:LONGINT ;ff :PSeq;p:I .PItem;
BEGIN
(∗ Zasuk trakov ∗)
InitRd (f [t[n−1]]);pa[n]:=Rd (f [n−1]);
ff :=f [n−1]; dn:=d [n]; z :=a[n−1];p:=pa[n];
FOR i:=n TO 2 BY −1 DO
f [i−1]:=f [i−2];
d [i]:=d [i−1];
a[i]:=a[i−1]−z ;
pa[i]:=pa[i−1]
END;
f [0]:=ff ; d [1]:=dn; a[1]:=z ; pa[1]:=p;
DEC (l )
END TermLoop;
BEGIN InitProg;
IF p # NIL THEN
Distribute;
REPEAT (∗ f [0]. . . f [n−2] zlivamo na f [n−1] ∗)
z :=a[n−1]; d [n]:=0; InitWr (f [n−1]);
REPEAT (∗ z ˇcet zapiˇsemo na trak f [n−1] ∗)
InitInnerLoop;
IF k =0 THEN INC (d [n]) ELSE MergeNonEmptyRuns END;
z :=z −1
UNTIL z =0;
TermLoop
UNTIL l =0;
END;
(∗ Izhodno zaporedje je na f [0] ∗)
RETURN f [0]
END PolyphaseSort;
Polifazno urejanje (konec)
Celotni program polifaznega urejanja je prikazan kot program 2.5, opisani postopek zaˇcetnega porazdeljevanja ˇcet realizira procedura Distribute (vrstice 40–56),
“vodoravno strategijo” pa procedura Select, ki izbira naslednji izhodni trak j (vrstice
13–26). Slednjo proceduro aktiviramo pred vsakim prepisovanjem ˇcete z vhodnega
traku na izhodni trak. Koliˇcina d[j] je preostalo ˇstevilo navideznih ˇcet na traku j in ji
ob spremembi vrednosti l priredimo zaˇcetno vrednost alj − ajl−1 . Pri porazdeljevanju
ˇcet opazimo ˇse neko zanimivost: kadarkoli porazdeljujemo ˇcete na veˇc izhodnih trakov, obstaja moˇznost, da se zadnja ˇceta na nekem izhodnem traku zlije s tekoˇco ˇceto v
eno samo ˇceto. Pri dvo in veˇcsmernem zlivanju nas to ne skrbi preveˇc, ker je postopek
tako zasnovan, da ni obˇcutljiv na razlike v ˇstevilu ˇcet na posameznih trakovih. Pri
2.3. ZUNANJE UREJANJE
69
polifaznem urejanju pa je postopek kritiˇcno odvisen od ˇstevila ˇcet na nekem traku
in zato si ne moremo privoˇsˇciti razlike med dejanskim ˇstevilom in ali . Zato v zanki
v vrsticah 39–46procedure Distribute, programa 2.5 vedno preverimo, ali se je stara
ˇceta na izhodu zlila s trenutno ˇceto in v tem primeru z vhoda prepiˇsemo dodatno ˇceto.
Pred to zanko opazimo posebno zanko v vrsticah 45–46, ki opravi zaˇcetno prirejanje
spremenljivki last, katere vrednost je nazadnje zapisani kljuˇc na nekem traku.
Sicer pa ima osnovni blok programa 2.5 dokaj preprosto zgradbo: po zaˇcetnih
prirejanjih in porazdeljevanju ˇcet se izvajata vgnezdeni zanki v vrsticah 107–115.
Zunanja pravzaprav “odvije” postopek porazdeljevanja in pri vsakem izvajanju jedra
zanke zmanjˇsa l za ena, notranja pa pri vsakem izvajanju jedra zanke na izhodni trak
zapiˇse eno ˇceto. Procedura TermLoop natanˇcno izvaja postopek, ki smo ga opisali v
zvezi s tabelo na sliki 2.30b: stolpce tabel d, a in f zasuka za eno mesto v desno ter
zmanjˇsa l.
2.3.5
Polifazno urejanje s predurejanjem
Pri polifaznem urejanju imamo ˇse eno moˇznost za pohitritev postopka: trajanje postopka je odvisno od potrebnega ˇstevila l, ki pa je odvisno od zaˇcetnega ˇstevila ˇcet.
ˇ to ˇstevilo zmanjˇsamo, je moˇzno postopek pohitriti. Ena moˇznost za to se nam
Ce
ponuja, ˇce ima raˇcunalnik neizkoriˇsˇcen notranji pomnilnik. V tem primeru lahko uporabimo neko metodo notranjega urejanja (tabel) za to, da poveˇcamo dolˇzino ˇcet (in
na ta naˇcin zmanjˇsamo njihovo ˇstevilo).
Postopek bomo izpeljali med zaˇcetnim porazdeljevanjem ˇcet preprosto tako, da
bomo spremenljivki CopyRun priredili novo proceduro, ki podaljˇsa ˇcete tako, da jih
nekoliko preuredi, uporabljajoˇc v ta namen kopico, pri ˇcemer je urejenost kopice sedaj nasprotna od urejenosti kopice iz razdelka 2.2.6: sedaj je element pri korenu
drevesa manjˇsi ali enak od elementov v poddrevesih. Delovanje procedure prikaˇzemo
na primeru, ko imamo na voljo kopico velikosti 12. Denimo, da imamo na vhodnem
ˇ nato 12 vhodnih podatkov
traku zaporedje kljuˇcev, ki so prikazani na sliki 2.32a. Ce
preberemo v prazna mesta tabele, ki predstavlja kopico, in nato tabelo uredimo v kopico (pozor na spremenjeno urejenost kopice), dobimo kopico, ki je prikazana na sliki
2.32b. Nato zapiˇsemo koren kopice na izhodni trak (ˇcigar indeks dobimo s klicem procedure Select), preberemo naslednji element z vhoda in nadaljujemo v odvisnosti od
razmerja med kljuˇcem naslednjega vhodnega elementa in kljuˇcem pravkar zapisanega
elementa:
ˇ je kljuˇc zapisanega elementa manjˇsi ali enak od kljuˇca naslednjega elementa
1. Ce
na vhodu, slednji element pripada isti ˇceti kot pravkar zapisani element in ga
zapiˇsemo v koren kopice ter sproˇzimo proceduro Sift (kopico popravimo);
ˇ je kljuˇc zapisanega elementa veˇcji od kljuˇca naslednjega elementa, pripada
2. Ce
naslednji element naslednji ˇceti. V tem primeru kopico zmanjˇsamo za en element
tako, da zadnji element zapiˇsemo v koren ter sproˇzimo Sift, naslednji element
na vhodu pa zapiˇsemo v prejˇsnji konec kopice;
70
POGLAVJE 2. UREJANJE
55,87,93; 17,21; 4,37,44,45; 19,100; 7,13,22; 2,57,88,101; 11,19,27; 9; 3;
1,25,58,80; 70,110; 29
(meje med ˇcetami so nakazane z znakom ;)
(a) Vhodni podatki
17
4
22
19
17
44
87
7
55
19
45
44
37
87
21 100 93
21
45
(b) Kopica pred prvim izpisom na izhod
93
100
55
37
2
(c) Kopica se prviˇ
c zmanjˇsa
29
70
58
9
80
25
27
19
1
11
3
2
(d) Kopica v celoti izpisana; druga pripravljena na urejanje
Slika 2.32: Polifazno urejanje s predurejanjem
3. Zapisovanje in branje ponovimo.
Na sliki 2.32c je prikazano stanje, ko nastopi prvo zmanjˇsanje kopice (po branju
elementa 2), na sliki 2.32d pa trenutek, ko smo prvotno kopico izpraznili in je druga
kopica pripravljena za urejanje in kasnejˇse izpise.
Celotni postopek se nekoliko zaplete, ker je sestavljen iz nekaj faz, med katerimi
je obnaˇsanje algoritma razliˇcno. Prvo fazo predstavlja branje elementov iz vhoda
v tabelo ter sestavljanje kopice. Nato sledi faza, ko je vhodni trak neprazen. Med
to fazo elemente prepisujemo na izhod do trenutka, ko se tekoˇca kopica izprazni,
oziroma tekoˇca ˇceta konˇca (ta faza se lahko ponovi veˇckrat). Vsakiˇc, ko se kopica
izprazni, moramo ˇse sproˇziti urejanje elementov naslednje ˇcete v kopico. Naslednja
faza nastopi, ko se vhod izprazni in na izhodni trak prepiˇsemo ostanek tekoˇce ˇcete,
nato pa ˇse elemente zadnje ˇcete prestavimo na zaˇcetek tabele ter jih uredimo v kopico.
Zadnjo fazo predstavlja izpis zadnje ˇcete.
Teˇzava pri realizaciji opisanega postopka je v tem, da moramo v proceduro CopyRun vgraditi spomin o tem, v kateri fazi je postopek. Najprimerneje je, da novo
71
2.3. ZUNANJE UREJANJE
proceduro realiziramo kot tim. samostojno proceduro (angl. coroutine), ki se razlikuje
od navadne procedure po tem, da si zapomni svoje stanje in ko se program vanjo
vrne, se izvajanje nadaljuje od mesta, kjer jo je program nazadnje zapustil. Program
je prikazan kot progam 2.6, sledi pa nekaj pripomb o njegovem delovanju.
Program 2.6: Polifazno urejanje s predurejanjem
1
2
4
5
5
7
8
8
10
10
11
12
13
14
15
16
17
18
19
20
22
22
23
24
26
26
27
28
30
30
31
32
33
34
35
36
38
38
39
MODULE HeapPS ;
IMPORT I :=IntSort,F :=FileSort;
CONST
N =8192;
TYPE
FCrCoroutine∗=PROCEDURE(P :PROCEDURE);
VAR
Rd ∗:F .FRdItem;
Wr ∗:F .FWrItem;
InitRd ∗,InitWr ∗:F .FSeqInit;
FinalSwitch∗,SwitchCoroutine∗:F .FNoParam;
CrCoroutine∗:FCrCoroutine;
in,out:F .PSeq;
dummy:I .Item;
p:I .PItem;
last: LONGINT ;
Sort:F .FPPSort;
PROCEDURE CopyRunCoroutine;
(∗ Prepisovanje ˇcet, ki smo jih predhodno podaljˇsali
tako, da smo jih spustili skozi kopico; privzetek: vhod je neprazen ∗)
VAR m, (∗ velikost ostanka kopice, ko se vhod izprazni ∗)
n: LONGINT ;(∗ zaˇcetna velikost kopice ∗)
a:F .PAPItem;
PROCEDURE Sift(l ,r : LONGINT );
VAR i,j :LONGINT ; x : I .PItem;
BEGIN i:=l ; j :=2∗i+1; x :=a[i];
WHILE j < r DO
IF a[j ].k > a[j +1].k THEN INC (j ) END;
IF x .k <= a[j ].k THEN j :=r +1 (∗ Izhod iz zanke ∗)
ELSE a[i]:=a[j ]; i:=j ; j :=2∗i+1
END
END;
IF (j =r ) & (x .k > a[j ].k ) THEN
se nadaljuje
72
POGLAVJE 2. UREJANJE
Polifazno urejanje s predurejanjem (nadaljevanje)
40
41
43
43
45
45
46
48
48
49
50
52
52
53
55
55
56
57
58
59
60
61
62
64
64
66
66
67
68
69
70
71
72
73
75
75
76
78
79
79
80
81
82
83
84
a[i]:=a[j ]; a[j ]:=x
ELSE a[i]:=x
END
END Sift;
PROCEDURE HeapOrder (n:LONGINT );
VAR l : LONGINT ;
BEGIN
l :=m DIV 2;
WHILE l >= 1 DO DEC (l ) ; Sift(l ,m−1) END; (∗ Kopico uredimo ∗)
END HeapOrder ;
PROCEDURE MoveAndOrder ;
VAR i,lim: LONGINT ;
BEGIN
(∗ Neurejene elemente prestavimo ∗)
IF m>0 THEN
IF m > n−m THEN lim:=n−m ELSE lim:=m END;
FOR i:=0 TO lim−1 DO a[i]:=a[n−i−1] END
END;
n:=n−m (∗ velikost zadnje ˇcete ∗)
HeapOrder (n)
END MoveAndOrder ;
PROCEDURE Init;
BEGIN
NEW (a,N );
n:=0;InitRd (in);p:=Rd (in);
REPEAT (∗ Kopico napolnimo ∗)
a[n]:=p;INC (n);p:=Rd (in)
UNTIL (p=NIL) OR (n=N );
m:=n;
HeapOrder (m)
END Init;
PROCEDURE NonEmptyInput;
VAR l : LONGINT ; pitem:I .PItem;
BEGIN
REPEAT
(∗ Zaˇcetek naslednje ˇcete ∗)
WHILE (p # NIL) & (m>0) DO
Wr (a[0],out);last:=a[0].k ;
IF p.k >=last THEN a[0]↑:=p↑; Sift(0,m−1)
ELSE DEC (m); a[0]:=a[m]; a[m]:=p
END;
se nadaljuje
73
2.3. ZUNANJE UREJANJE
Polifazno urejanje s predurejanjem (nadaljevanje)
85
86
87
88
89
90
91
92
94
94
95
97
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
113
113
115
115
117
117
118
119
120
121
122
124
124
125
126
127
128
129
p:=Rd (in)
END;
IF m=0 THEN
m:=n;
HeapOrder (m);
pitem:=p;p:=a[0];
SwitchCoroutine;
p:=pitem
END
UNTIL p=NIL
END NonEmptyInput;
PROCEDURE NextToLastRun;
VAR rm: LONGINT ; pitem:I .PItem;
BEGIN rm:=m;
(∗ Konec vhoda, pri ˇcemer je morebiti ena ˇceta
ostala nedokonˇcana ∗)
IF rm > 0 THEN
REPEAT (∗ Ostanek ˇcete zapiˇsemo ∗)
Wr (a[0],out);last:=a[0].k ;
DEC (rm);a[0]:=a[rm];Sift(0,rm−1)
UNTIL rm = 0;
MoveAndOrder ;
pitem:=p;p:=a[0];
SwitchCoroutine;
p:=pitem
ELSE MoveAndOrder
END
END NextToLastRun;
PROCEDURE LastRun;
BEGIN
WHILE n > 0 DO
Wr (a[0],out);last:=a[0].k ;
DEC (n);a[0]:=a[n];Sift(0,n−1)
END;
p:=NIL
END LastRun;
BEGIN SwitchCoroutine;
Init;
NonEmptyInput;
NextToLastRun;
LastRun;
FinalSwitch
se nadaljuje
74
POGLAVJE 2. UREJANJE
Polifazno urejanje s predurejanjem (nadaljevanje)
130
132
132
133
134
136
136
137
138
139
141
141
142
143
145
145
146
147
148
END CopyRunCoroutine;
PROCEDURE CopyRun(inf ,outf :F .PSeq;VAR pI :I .PItem;
VAR lastK :LONGINT );
(∗ Prepis ene ˇcete; privzetek: na zaˇcetku p # NIL ∗)
BEGIN
in:=inf ;out:=outf ;p:=pI ;last:=lastK ;
SwitchCoroutine;
pI :=p;lastK :=last
END CopyRun;
PROCEDURE MakeCoroutine;
BEGIN CrCoroutine(CopyRunCoroutine)
END MakeCoroutine;
BEGIN F .CopyRun:=CopyRun;
F .SpecInit:=MakeCoroutine;
Sort:=F .PolyphaseSort
END HeapPS .
Polifazno urejanje s predurejanjem (konec)
Mehanizem samostojnih procedur smo vgradili v program v obliki procedurne
spremenljivke CrCoroutine, ki samostojno proceduro pripravi za izvajanje, ter dveh
procedurnih spremenljivk, SwitchCoroutine ter FinalSwitch, ki program prestavita iz
ene samostojne procedure v drugo (vrstici 14-15). V naravo procedur, ki so prirejene
tem spremenljivkam, se niti ne spuˇsˇcamo, ker to presega okvir dela. Program, ki
ga gradimo, je sestavljen iz dveh samostojnih procedur, iz glavnega programa in iz
samostojne procedure, ki realizira prepisovanje ˇcet (CopyRunCoroutine).
1. Modul HeapPS inicializiramo tako, da procedurnim spremenljivkam CopyRun
in SpecInit iz modula FileSort (slika 2.26) ter Sort is modula HeapPS priredimo
vrednosti (vrstice 145–147). Nato je moˇzno polifazno urejanje s predurejanjem
sproˇziti s klicem procedurne spremenljvike Sort, ki pripada tipu FPPSort iz
modula FileSort (slika 2.26). V tem sestavku se ne spuˇsˇcamo v naravo procedur,
ki so prirejene procedurnim spremenljivkam CrCoroutine, SwitchCoroutine ter
FinalSwitch;
2. Ob klicu procedurne spremenljvike Sort se najprej izvaja procedura SpecInit
(program 2.5, vrstica 35), ki ima za posledico izvajanje procedure MakeCoroutine iz programa 2.6 (vrstice 141–143). Slednja procedura poˇzene samostojno
proceduro, tako da pripravi proceduro CopyRunCoroutine za izvajanje in se
nato takoj vrne v glavni program;
3. glavni program nadaljuje z izvajanjem, kot smo to opisali v razdelku o polifaznem urejanju, v samostojno proceduro, ki jo sedaj opisujemo, pa se vrne ob
2.4. POVZETEK OSNOVNIH POJMOV
75
klicu CopyRun (vrstice 132–139). Ko pride do tega klica, se opravijo prirejanja spremenljivkam in, out, p in last (vhodni trak, izhodni trak, kazalec na
element, ki ga preberemo, in kljuˇc nazadnje prebanega elementa), nato pa se
pokliˇce SwitchCoroutine, ki prestavi program iz samostojne procedure, ki jo
predstavlja glavni program, v tisto, ki opravi prepisovanje ˇcet;
4. Procedura CopyRunCoroutine se priˇcne s klicem Init (vrstice 64–73), ki dinamiˇcno generira tabelo a za kopico, jo napolni z elementi, ki jih prebere z
vhoda (moramo upoˇstevati tudi moˇznost, da se vhod konˇca, preden je cela tabela popisana) ter na koncu sestavi kopico (vrstica 72);
5. Sledi klic procedure NonEmptyInput (vrstice 75–95), katere jedro je zanka, ki
se izvaja do trenutka, ko se vhod izprazni (mora pa biti tako zasnovana, da
deluje pravilno tudi, ko je vhod ˇze prazen ob vstopu). Zanka v vrsticah 80–86,
v svojem jedru zapiˇse koren kopice na izhodni trak, prebere naslednji element z
vhoda ter njegov kljuˇc primerja s kljuˇcem pravkar zapisanega elementa (vrstica
ˇ se
82). Zanka se zakljuˇci, ko se bodisi vhod ali trenutna kopica izprazni. Ce
kopica izprazni, je to znak, da se je trenutna ˇceta konˇcala in je potrebno sestaviti
novo kopico in zamenjati samostojno proceduro (vrstica 91);
6. Sledi klic procedure NextToLastRun, ki zapiˇse preostale elemente trenutne kopice na izhod, nato prestavi elemente zadnje ˇcete na zaˇcetek tabele, jih preuredi
v kopico ter opravi zamenjavo samostojne procedure (vrstice 107–109);
7. Elemente zadnje ˇcete nato izpiˇse procedura LastRun;
8. Konˇcno se pokliˇce procedure FinalSwitch, ki program dokonˇcno prestavi v
osnovno samostojno proceduro.
2.4
Povzetek osnovnih pojmov
1. Naloga urejanja
2. Kriteriji za razvrˇsˇcanje nalog urejanja
3. Operacije, s katerimi ocenjujemo porabo ˇcasa pri urejanju
4. Urejanje tabel in osnovni privzetek glede porabe prostora
5. Navadne metode urejanja. Znaˇcilna zanˇcna invarianta. Ocena porabe ˇcasa
6. Spodnja meja za ˇcas urejanja tabel dolˇzine n. Uporabljeni raˇcunalniˇski model. Mnoˇzica
vhodnih podatkov. Drevo sledi
7. Shellovo urejanje
8. Urejanje s kopico in ocenjevanje porabe ˇcasa
9. Urejanje s porazdelitvami. Ocena povpreˇcne in najveˇcje porabe ˇcasa. Ocena porabe
prostora
10. Iskanje k-tega elementa ter ocena povpreˇcne in najveˇcje porabe ˇcasa
76
POGLAVJE 2. UREJANJE
11. Navadno zlivanje datotek. Ocena porabe ˇcasa. Moˇzne poti izboljˇsave navadnega zlivanja
12. Naravno zlivanje
13. Osnovni problem veˇcsmernega zlivanja in njegova reˇsitev
14. Polifazno zlivanje; osnovna rekurenˇcna relacija za potrebno zaˇcetno ˇstevilo ˇcet na
posameznih takovih; problem, ko celotno ˇstevilo ˇcet ni enako vsoti potrebnih zaˇcetnih
ˇstevil ˇcet na posameznih trakovih; problem zlivanja dveh ˇcet v eno; “vodoravna”
strategija porazdeljevanja ˇcet;
15. Polifazno zlivanje s predurejanjem. Zakaj predurejanje. Programska reˇsitev, ki uporablja samostojne procedure.
2.5
Naloge
1. Izpeljite oceno za ˇcas, ki ga porabi algoritem na sliki 2.9 pri izvajanju zanke v vrsticah
od 14 do 16.
2. Izpeljite oceno za ˇstevilo zamenjav, ki jih opravi algoritem navadnih zamenjav na sliki
2.11. Ocenite najmanjˇse, najveˇcje in povpreˇcno ˇstevilo zamenjav.
3. Dokaˇzite, da je z naborom operacij na sliki 2.13 moˇzno realizirati urejanje poljubne
tabele dolˇzine n. (Napotek: izhajajte iz ugotovitve, da je naloga urejanja enakovredna
sestavljanju neke permutacije vhodnih podatkov.)
4. Izraˇcunajte porabo ˇcasa pri urejanju s porazdelitvami, ˇce privzamemo, da je poraba
ˇcasa za porazdelitev enaka cn in da vsaka porazdelitev tabelo razdeli toˇcno na dve
tabeli enakih velikosti (napotek: uporabite izrek 1.3).
5. V razdelku o ˇcasu, ki ga porabi urejanje s porazdelitvami, smo dokazali relacijo (2.18),
vendar le za ceno sorazmerno visokega poveˇcanja konstante c. Poiˇsˇcite tak nastavek
za vrednost Tave (n), ki ohrani vrednost konstantnega faktorja c pri n ln n (napotek:
ˇclenu cn log n priˇstejte nek ˇclen, ki se po integraciji v (6) uniˇci z 41 ).
6. Izpeljava relacije (2.16) ni povsem prepriˇcljiva, ker smo izhajali iz nekoliko nenatanˇcnega privzetka, da se tabela velikosti n vedno razdeli v razmerju k : n − k − 1 pri
0 ≤ k ≤ n − 1. Do iste relacije pridemo z nekoliko spremenjenim opisom porazdeljevanja, ko tabelo razdelimo na tri dele, in sicer na levi del, ki vsebuje i elementov, ki so
manjˇsi ali enaki mejnemu elementu, na element, ki je enak mejnemu elementu in na
n − i − 1 elementov, ki so veˇcji ali enaki mejnemu elementu. Naloga: sestavite algoritem, ki realizira takˇsno porazdelitev. Kaj menite o njegovi uˇcinkovitosti v primerjavi
s porazdelitvenim algoritmom na sliki 2.19?
7. Obravnavali smo vpraˇsanje zmanjˇsevanja porabe prostora pri urejanju s porazdelitvami. Prikazali smo reˇsitev, ki uporablja poseben sklad za shranjevanje novih zahtev
po porazdelitvi. Pokaˇzite, da je moˇzno tudi prvotno proceduro Sort na sliki 2.20
spremeniti v obliko, ko ne pride do pretirane porabe prostora.
8. Za neko metodo urejanja pravimo, da je stabilna, v primeru, ko ne more priti do zamenjave medsebojnega poloˇzaja dveh zapisov z istim kljuˇcem. Za vse metode notranjega
urejanja, ki smo jih predstavili (navadno vstavljanje, dvojiˇsko vstavljanje, navadno izbiranje, navadne zamenjave, izmeniˇcne zamenjave, Shellovo urejanje, urejanje s kopico
77
2.5. NALOGE
i1
j1
i2
j2
Slika 2.33: Urejanje tabel z uravnoteˇzenim zlivanjem
in urejanje s porazdelitvami), ugotovite, katere so stabilne in podajte utemeljitev vaˇse
sodbe.
9. Shemo naravnega, uravnoteˇzenega zlivanja lahko uporabimo tudi za urejanje tabel,
kot to prikazuje sl. 2.33: dve vhodni tabeli sta prikazani na levi, pri ˇcemer sta i1 in j1
indeksa trenutnih elementov vhodnih ˇcet, i2 in j2 pa indeksa elementov izhodnih ˇcet.
i1 in j1 zlivamo v i2 , naslednjo ˇceto pa na j2 .
(a) Sestavite podroben program za opisani postopek;
(b) zakaj se ta postopek ni uveljavil v praksi, ˇceprav je izredno hiter?
10. Na podlagi rekurenˇcne relacije 2.27 izpeljite velikost Fibonaccijevih stevil prvega reda
(napotek: uporabite nastavek fi = cxi ).
78
POGLAVJE 2. UREJANJE
Poglavje 3
ALGORITMI Z
REKURZIVNIM
RAZCEPOM
3.1
Uvod
Algoritme, ki uporabljajo rekurzivni razcep prvotnega problema na manjˇse podprobleme, smo omenili ˇze v uvodnem poglavju (gl. razdelek 1.4.2), kasneje pa smo se
z njimi sreˇcali tudi pri urejanju tabel (metoda urejanja s porazdelitvami, razdelek
2.2.7). Sedaj bomo prikazali ˇse dva dodatna primera: nek algoritem za mnoˇzenje matrik in dva za raˇcunanje diskretne Fourierjeve transformacije, pri ˇcemer slednji gotovo
spada med najkoristnejˇse algoritme, kar jih poznamo. V tem poglavju uporabljamo
doloˇcene pojme iz linearne in sploˇsne algebre in v kolikor pojasnila v tem besedilu ne
zadostujejo, lahko bralec poiˇsˇce dodatne informacije v delu Vidav [15, poglavje 1].
3.2
Mnoˇ
zenje matrik
Podani sta dve matriki, A in B, s komponentami Aij in Bij pri
Pn1 ≤ i, j ≤ n. Njun
produkt, C = A · B, je definiran na obiˇcajen naˇcin kot Cij = k=1 Aik Bkj . Zastavimo si vpraˇsanje, kolikˇsno je minimalno ˇstevilo aritmetiˇcnih operacij, potrebnih za
izraˇcun vseh komponent C? Iz zgodovinskih razlogov, pa tudi na podlagi teoretiˇcnih
premislekov, je primerno kot prvi pribliˇzek upoˇstevati le operacije mnoˇzenja1 . Torej,
kolikˇsno je minimalno ˇstevilo mnoˇzenj, ki je potrebno za izraˇcun komponent matriˇcnega produkta?
1 Zgodovinski razlog je, da sta vˇ
casih na raˇ
cunalnikih mnoˇ
zenje in deljenje zahtevala mnogo veˇ
c
ˇ
casa kot seˇstevanje in odˇstevanje (danes to veˇ
c ni res); teoretiˇ
cni premislek pa je, da ima v algebraiˇ
cnih
izpeljavah mnoˇ
zenje posebno mesto in da je laˇ
ze ocenjevati ˇstevilo mnoˇ
zenj kot ˇstevilo seˇstevanj.
79
80
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
Najpreprostejˇsi algoritem za mnoˇzenje matrik seveda izhaja neposredno iz definicije. Zanj se brez teˇzav prepriˇcamo, da porabi n3 mnoˇzenj in je potemtakem klasiˇcen
primer raˇcunsko potratnega algoritma.
3.2.1
Metoda S. Winograda
Prvi, ki je omenjeni problem raziskoval in priˇsel do doloˇcenih rezultatov, je bil S.
Winograd l. 1967. Njegova metoda deluje, ko je n sodo ˇstevilo2 , sloni pa na uporabi
naslednjih koliˇcin:
πi,k,j
ρi,k
σk,j
=
=
=
=
(Ai,2k−1 + B2k,j )(B2k−1,j + Ai,2k )
Ai,2k−1 B2k−1,j + Ai,2k−1 Ai,2k + B2k,j B2k−1,j + B2k,j Ai,2k ,
Ai,2k−1 Ai,2k ,
B2k,j B2k−1,j ,
(3.1)
pri 1 ≤ i, j ≤ n in 1 ≤ k ≤ n2 . Vsako od zapisanih koliˇcin lahko izraˇcunamo z enim
samim mnoˇzenjem. Komponento Ci,j matriˇcnega produkta lahko nato izrazimo kot
n
Ci,j =
2
X
(πi,k,j − ρi,k − σk,j ).
(3.2)
k=1
Naj nπ , nρ in nσ predstavljajo ˇstevila elementov posamezne vrste. Potem je ˇstevilo
mnoˇzenj za izraˇcun vseh komponent matriˇcnega produkta enako
nπ + nρ + nσ .
(3.3)
Ker oˇcitno velja nπ = 21 n3 , nρ = nσ = 12 n2 , smo z metodo Winograda zmanjˇsali potrebno ˇstevilo mnoˇzenj pribliˇzno na polovico. Bodimo pozorni na to, da pri izraˇcunih
komponent produkta uporabljamo koliˇcine ρi,k in σk,j enako pogosto kot πi,k,j , vendar
so koliˇcine πi,k,j pri razliˇcnih komponentah razliˇcne, medtem ko se koliˇcine ρi,k in σk,j
pri razliˇcnih komponentah ponavljajo. Bistveno za delovanje algoritma je dejstvo, da
je mnoˇzenje navadnih ˇstevil komutativno (xy = yx). Namreˇc, ˇce to ne bi veljalo, ne
bi pri komponenti Ci,j iz koliˇcine πi,k,j mogli dobiti ˇclena Ai,2k B2k,j .
ˇ upoˇstevamo, da za
Kolikˇsno pa je ˇstevilo operacij seˇstevanja in odˇstevanja? Ce
izraˇcun ene koliˇcine πi,k,j porabimo 2 seˇstevanji, nato, da pri izraˇcunu komponent C
P n2
P n2
raˇcunamo vsote k=1
ρi,k ter k=1
σk,j , ki zahtevajo n2 −1 seˇstevanj, vseh takih vsot
pa je 2n, in konˇcno, da pri izraˇcunu Ci,j porabimo ˇse 2 dodatni seˇstevanji, dobimo,
1
n
2 · n3 + 2n( − 1) + 2n2 = n3 + 3n2 − 2n,
2
2
kar pa je veˇc kot zahteva klasiˇcna metoda. Zaradi tega in drugih okoliˇsˇcin, ki
zmanjˇsujejo hitrost metode v praksi, se metoda ni uveljavila.
2 V kolikor n ni sodo, obravnavamo A in B kot n0 × n0 matriki pri n0 = n + 1, pri ˇ
cemer so vsi
elementi v zadnji vrstici in zadnjem stolpcu enaki 0.
ˇ
3.2. MNOZENJE
MATRIK
 A11 A12

 A21 A22 
A31 A32
A41 A42
A13
A23
A33
A43
81
 A14
B11 B12

A24
 B21 B22 


A34
B31 B32
A44
B41 B42
B13
B23
B33
B43

B14

B24


B34
B44
Slika 3.1: Delitev problema mnoˇzenja matrik pri n = 4
3.2.2
Metoda V. Strassena
V. Strassen je pribliˇzno istoˇcasno z Winogradom iznaˇsel neko novo metodo za mnoˇzenje
matrik, ki tudi po velikostnem redu porabi manj mnoˇzenj od klasiˇcne metode. Metoda
sloni na neki posebni metodi mnoˇzenja 2 × 2 matrik, ki ne uporablja lastnosti komutativnosti ˇstevil. Zaradi tega v identitetah, ki predstavljajo osnovo za metodo, ˇstevila
lahko zamenjamo s podmatrikami obeh matriˇcnih faktorjev in doseˇzemo rekurzivni
razcep prvotne naloge.
ˇ sta A in B dve 2 × 2 matriki, lahko Strassenove produkte zapiˇsemo takole:
Ce
π11
π12
π13
π14
= (A11 + A22 )(B11 + B22 )
= (A12 − A22 )(B21 + B22 )
= (A11 + A12 )B22
= A22 (B11 − B21 )
π21
π22
π23
π24
= (A22 + A11 )(B22 + B11 )
= (A21 − A11 )(B12 + B11 )
= (A22 + A21 )B11
= A11 (B22 − B12 ).
(3.4)
Vseh skupaj je produktov na seznamu (3.4) 8, vendar sta π11 in π21 enaka, kar pomeni,
da jih je 7. Lahko ugotovimo, da dobimo produkte π21 , π22 , π23 , π24 iz π11 , π12 , π13 , π14
tako, da povsod indeks 1 zamenjamo z 2 in nasprotno, 2 z 1. Ni teˇzko ugotoviti, da
velja
C11
C12
C21
C22
=
=
=
=
+π11
+π12
−π13
+π13
−π14
−π24
−π14
+π21
+π22
+π23
−π23
(3.5)
−π24
Identitete (3.5) ne potrebujejo privzetka komutativnosti mnoˇzenja elementov Ai,j
in Bi,j . Zato lahko npr. pri n = 4 koliˇcine A11 , A12 , A21 , A22 in B11 , B12 , B21 , B22
zamenjamo s podmatrikami, kot je to prikazano na sliki 3.1.
Pri izraˇcunu porabe ˇcasa Strassenove metode uporabljamo izrek 1.3. V naˇsem
primeru smo velikost problema razpolovili (c = 2), za reˇsitev prvotnega problema pa
je potrebno reˇsiti sedem podobnih problemov poloviˇcne velikosti (a = 7). Cena za
delitev problema in za kasnejˇse sestavljanje reˇsitve je velikostnega reda Θ(n2 ) (torej
r = 2), ker je vsak element matrik potrebno vsaj enkrat uporabiti v nekem izraˇcunu.
V tem primeru velja a > cr , zato dobimo
T (n) = Θ(nlogc a ) = Θ(n2.80735 ).
(3.6)
82
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
Glede na rezultat (3.6) bi priˇcakovali, da se bo Strassenov algoritem moˇcno uveˇ pa zaradi njegove rekurzivne narave pride do
ljavil v praktiˇcnem raˇcunanju. Zal
prevelike porabe prostora, kar ga naredi neprimernega za delo z velikimi matrikami.
Klasiˇcni algoritem ima tudi to prednost, da uporablja zelo preproste operacije —
nekako bi lahko rekli, da je “homogen”. Zato je primeren za realizacijo na velikih
(“vektorskih”) raˇcunalnikih. Zaradi teh in podobnih razlogov se klasiˇcni algoritem ˇse
danes uporablja tam, kjer je potrebno mnoˇziti velike matrike. Dodaten razlog, zakaj
se uˇcinkovitejˇsi algoritmi za mnoˇzenje matrik v praksi niso uveljavili, tudi tam, kjer
bi to lahko priˇcakovali, je, da je do danes prav zaradi ˇcasovne potratnosti klasiˇcnega
algoritma nastala vrsta matematiˇcnih metod, ki doseˇzejo isti ali podoben uˇcinek brez
uporabe matriˇcnega mnoˇzenja.
3.3
3.3.1
Diskretna Fourierjeva transformacija in
algoritmi zanjo
Uvod
Diskretna Fourierjeva transformacija spada med pomembnejˇsa orodja uporabne matematike, sodobni algoritmi zanjo so pa tudi primeri elegantnih in uˇcinkovitih raˇcunalniˇskih
algoritmov. V tem sestavku bomo na kratko opisali diskretno Fourierjevo transformacijo, ali s kratico DFT, njeno uporabo pri raˇcunanju konvolucije polinomov in
algoritme zanjo. DFT je opisana v zelo obseˇzni literaturi. Na tem mestu lahko omenimo Aho, Hopcroft in Ullman [1, 7. poglavje] ali Kozak [10, §7.7].
3.3.2
Diskretna Fourierjeva transformacija
Pri definiciji diskretne Fourierjeve transformacije izhajamo iz n-razseˇznostnega vektorskega prostora nad nekim obsegom K(3)
Prostor oznaˇcujemo z VK . Pri K privzamemo, da
2π
ei n
vsebuje nek poseben element ω, ki mu pravimo n-ti
primitivni koren enote zaradi naslednjih lastnosti:
ei0
2π
ei n n
=
=
ω n = 1,
(3.7)
ω i 6= 1, pri 1 ≤ i ≤ n − 1.
(3.8)
1 in
Slika 3.2: Klasiˇcni primer
[Elementu ω pravimo koren enote zaradi lastnosti
n-tega primitivnega korena
(3.7) in primitivni koren enote zaradi (3.8).] Takoj
enote
lahko ugotovimo, da sta (3.7) in (3.8) enakovredni
3 Spomnimo se, da je obseg matematiˇ
cna struktura kolobarja, v katerem imata tako seˇstevanje kot
mnoˇ
zenje ustrezni inverzni operaciji. V nekaterih virih se od mnoˇ
zenja zahteva, da je komutativno,
v drugih te zahteve ni. Za naˇse potrebe lahko privzamemo, da je mnoˇ
zenje komutativno.
3.3
DISKRETNA FOURIERJEVA TRANSFORMACIJA
83
naslednji lastnosti:
n−1
X
ω pi =
i=0
n,
0,
pri p = n;
pri 1 ≤ p ≤ n − 1.
(3.9)
Dejansko: naj veljata (3.7) in (3.8). Veljavnost (3.9) pri p = n je oˇcitna. Naj bo sedaj
1 ≤ p ≤ n − 1 in zapiˇsimo:
1 − ω pn
= (1 − ω p )
= 0.
Pn−1
i=0
ω pi
(3.10)
Ker na desni strani prve vrstice (3.10) prvi faktor ni enak niˇc [na podlagi (3.8)], mora
biti drugi faktor enak niˇc in torej (3.9) velja. Nasprotno pa, naj ne veljata (3.7) in
(3.8). Pravzaprav (3.7) velja, ker nas zanimajo le koreni enote, torej naj koren enote
ni primitiven [ne velja (3.8)]. V tem primeru eksistira nek 1 ≤ p ≤ n − 1, pri katerem
velja ω p = 1. Tedaj pa pri tej vrednosti p ne more veljati druga vrstica desne strani
(3.9), in torej (3.9) ne velja. 2
3.1 Primer Klasiˇcen primer n-tega primitivnega korena enote je kompleksno ˇstevilo
2π
ei n (gl. sliko 3.2).
3.2 Definicija Diskretna Fourierjeva transformacija stopnje n prostora VK je linearna transformacija tega prostora z matriko F in elementi Fij = ω ij , pri 0 ≤ i, j ≤
n − 1.
Ponavadi je n znano in vnaprej doloˇceno tako, da stopnje transformacije niti ne omenjamo. Osnovna lastnost DFT je, da ima inverz v primeru, ko je izpolnjen naslednji
pogoj:
ˇ obseg k vsebuje element
3.3 Trditev Ce
−1
1 −ij
Fij = n ω .
1
n,
ima F inverz z matriko F −1 in elementi
Dokaz. Pri sprejetem privzetku o elementu n1 obsega je element v vrstici i in stolpcu
j produkta F · F −1 enak
n−1
1 X (i−j)h
ω
,
n
h=0
ta vsota pa je na podlagi (3.9) enaka
1
δij =
0
pri i = j;
sicer.
2
Koliˇcini δij ponavadi pravimo Kroneckerjev delta simbol.
84
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
3.4 Pripomba Pri eksponentu i·j elementa ω ij ugotovimo, da je pomemben le ostanek po deljenju z n zaradi relacije ω n = 1. Pogoj o eksistenci elementa n1 najpogosteje
opiˇsemo s pogojem, da ima K karakteristiko, ki je razliˇcna od n, pri ˇcemer je karakteristika obsega K tisti najmanjˇsi mnogokratnik 1, ki je enak 0. Na primer, pri ˇstevilih
ˇ takega mnogokratnika ni, definiramo karakteristiko kot ∞
po modulu 3 je to 3. Ce
(npr. pri racionalnih ˇstevilih). 2
3.5 Primer Pri n = 2 je n-ti primitivni koren enote enak -1 in sta matrika DFT in
njen inverz,
1
1
1
1
1
1
= F
F =
; F −1 =
1 −1
1 −1
2
2
ˇ pri
(seveda pa v sploˇsnem ne velja F −1 = n1 F ). Ce
koren enote z ω, sta matrika DFT in njen inverz,



1
1
1
1
1
 1
 1 ω ω 2 ω 3  −1
1
;F = 
F =
 1 ω2
1 ω2 
4 1
3
2
1
1
1 ω ω ω
ˇ upoˇstevamo, da velja ω 2 = ω −2 = −1, ω −1 = ω 3
Ce



1
1
1
1
 1

ω −1 −ω 
 ; F −1 = 1 
F =
 1 −1
1 −1 
4
1 −ω −1
ω
n = 4 oznaˇcimo n-ti primitivni
1
1
ω −1
ω −2
ω −3
ω −2
1
ω −2
1

ω −3 
.
ω −2 
ω −1
= −ω ter ω −3 = ω 1 , dobimo

1
1
1
1
1 −ω −1
ω 
.
1 −1
1 −1 
1
ω −1 −ω
Primer lahko zakljuˇcimo z izraˇcunom podobe nekega vektorja. Naj bo n = 4 in
x = [1, 1, 2, 2] t , pri ˇcemer x t oznaˇcuje transpozicijo vektorja x. Na podlagi pravkar
zapisane vrednosti F lahko izraˇcunamo F x kot
[6, −1 − ω, 0, −1 + ω] t .
Naj ˇse pripomnimo, da je v primeru n = 4 in ko je K obseg kompleksnih ˇstevil, ω
enako “imaginarnemu” ˇstevilu i (glej primer 3.1). 2
3.3.3
Interpretacija DFT s polinomi
V mnogih aplikacijah je primerna interpretacija DFT s polinomi: baza VK je sestavljena iz polinomov xi , pri 0 ≤ i ≤ n − 1. Ker imamo le n baznih elementov, je moˇzno
z elementi prostora predstavljati le polinome stopnje n − 1:
n−1
X
i=0
ai xi .
3.3
DISKRETNA FOURIERJEVA TRANSFORMACIJA
85
Lahko si pa tudi mislimo, da predstavljamo vse polinome (ne glede na stopnjo), vendar
izenaˇcimo dva polinoma, ki se razlikujeta le po koeficientih pri stopnjah ≥ n. V tem
primeru pravimo, da sta polinoma enaka po modulu xn . Povedano drugaˇce, dva
polinoma sta enaka po modulu xn takrat, ko sta ostanka po deljenju z xn ista. Torej
so elementi prostora VK polinomi ene spremenljivke po modulu xn s koeficienti iz K.
Glede na to, da polinome ne le seˇstevamo, temveˇc tudi mnoˇzimo, imamo pravzaprav
opravka s kolobarjem. Pri polinomih uporabljamo razliˇcne predstavitve, med katerimi
sta najpomembnejˇsi koeficientna predstavitev in pa vrednostna predstavitev. Prva
predstavitev ustreza pravkar omenjeni bazi za prostor polinomov po modulu xn : v tem
primeru je i-ta komponenta polinoma p(x) koeficient pri baznem elementu xi . Druga
predstavitev pa je povezana z n elementi, c0 , c1 , . . . , cn−1 (ki pripadajo K), polinom
p(x) pa predstavljamo z n-terko vrednosti p(c0 ), p(c1 ), . . . , p(cn−1 ) (gl. nalogi 2 in 3).
V naˇsem primeru je posebno zanimiv nabor elementov ci = ω i pri 0 ≤ i ≤ n − 1. Ni
se teˇzko prepriˇcati v to, da predstavlja DFT transformacijo, ki preslika koeficientno
predstavitev nekega polinoma v vrednostno predstavitev v toˇckah ω i , pri 0 ≤ i ≤ n−1.
Resniˇcno:
n−1
X
p(ω i ) =
aj ω i·j ,
j=0
kar predstavlja i-to komponento F ([a0 , a1 , . . . , an−1 ]) (gl. tudi nalogo 4).
3.3.4
Konvolucija polinomov
Za hip bomo obravnavali sploˇsne polinome (ne po modulu xn ). Vsak polinom si lahko
predstavljamo kot element vektorskega prostora neskonˇcne razseˇznosti, katerega bazni
elementi so xi , i ≥ 0, ki pa ima le konˇcno mnogo neniˇcelnih komponent.
3.6 Definicija Konvolucija polinomov p(x) in q(x) je koeficientna predstavitev njuˇ sta vektorja koeficientov polinomov p(x) in q(x), a in
nega produkta p(x) · q(x). Ce
b, po vrsti, oznaˇcujemo vektor koeficientov produkta p(x) · q(x) z a ◦ b.
Ko imamo dva polinoma stopnje n − 1,
p(x) =
Pn−1
i=0
ai xi ,
q(x) =
Pn−1
j=0
bj xj ,
je njun produkt,
p(x) · q(x) =
2n−2
X

n−1
X

i=0

aj bi−j  xi ,
j=0
pri ˇcemer koliˇcine bi z indeksom i, ki leˇzijo izven intervala [0, n − 1], izenaˇcimo z 0.
Torej, ko sta podana dva vektorja s komponentami
a = [a0 , a1 , . . . , an−1 ]
b = [b0 , b1 , . . . , bn−1 ] ,
86
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
je njuna konvolucija c = a ◦ b vektor z najveˇc 2n − 1 neniˇcelnimi komponentami. i-ta
komponenta ci pa je enaka
ci =
n−1
X
aj bi−j , 0 ≤ i ≤ 2n − 2.
j=0
ˇ
Teˇzava pri raˇcunanju konvolucije je, da je razmeroma potratna operacija. Ce
upoˇstevamo samo mnoˇzenja, zahteva raˇcunanje i-te komponente i + 1 mnoˇzenj, pri
0 ≤ i ≤ n − 1 in 2n − i − 1 pri n ≤ i ≤ 2n − 2, kar pomeni, da za vseh 2n − 2 komponent potrebujemo n2 mnoˇzenj (gl. nalogo 1). Izkaˇze pa se, da obstaja pot, ki zahteva
manj operacij mnoˇzenja (in tudi operacij nasploh). Ideja je v tem, da najprej ovrednotimo oba faktorja, p(x) in q(x), pri potencah 2n-tega primitivnega korena enote,
za kar uporabimo diskretno Fourierjevo transformacijo stopnje 2n, nato tako pridobljene vektorje F (p(x)) in F (q(x)) zmnoˇzimo po komponentah ter konˇcno uporabimo
inverzno DFT na vektorju, ki je sestavljen iz produktov istoleˇznih komponent. Ideja
sloni na dejstvu, da je vrednost produkta dveh polinomov v poljubni toˇcki, produkt
ˇ sta a in b vektorja koeficientov p(x) in q(x), lahko
vrednosti faktorjev v isti toˇcki. Ce
zapiˇsemo,
a ◦ b = F −1 (F (a) ∗ F (b)),
kjer simbol ∗ oznaˇcuje vektor, ki ga dobimo iz dveh faktorjev tako, da zmnoˇzimo
istoleˇzne komponente4 . Na prvi pogled je teˇzava v tem, da sta faktorja polinoma
stopnje n − 1, rezultat pa polinom stopnje 2n − 2. Ponavadi postopamo tako, da
oba vektorja faktorjev podaljˇsamo do dolˇzine 2n (z dodajanjem niˇcelnih komponent)
in tudi rezultat obravnavamo kot vektor dolˇzine 2n (namesto 2n − 1). Razlog je v
tem, da je vedno ugodno, ˇce je n potenca ˇstevila 2. To, kar smo doslej opisali, lahko
strnemo v naslednji izrek:
3.7 Izrek (o konvoluciji). Podana sta dva polinoma stopnje n − 1:
p(x) =
n−1
X
ai xi in q(x) =
i=0
n−1
X
bj xj .
j=0
Naj bosta
a = [a0 , a1 , . . . , an−1 , 0, . . . , 0] t in
b = [b0 , b1 , . . . , bn−1 , 0, . . . , 0] t
vektorja dolˇzine 2n, pri ˇcemer predstavlja
t
simbol za transponiranje, vektorja
F (a) = [a00 , a01 , . . . , a02n−1 ] t in F (b) = [b00 , b01 , . . . , b02n−1 ] t
pa sta ustrezni DFT transformiranki. Potem velja a ◦ b = F −1 (F (a) ∗ F (b)).
4 Naslednje
dejstvo navajamo kot zanimivost: spomnimo se, da je Kroneckerjev produkt neke m×n
matrike A in neke m0 × n0 matrike B, mm0 × nn0 matrika C = A ⊗ B z elementi Cii0 ,jj 0 = Aij Bi0 j 0 .
Zato lahko predstavimo operacijo ∗ takole: levi faktor si predstavljamo kot neko n × 1 matriko, desni
pa kot neko 1 × n matriko; potem je a ∗ b enako diagonali matrike a ⊗ b.
3.3
87
DISKRETNA FOURIERJEVA TRANSFORMACIJA
Dokaz. Ker velja ai = bi = 0, pri n ≤ i ≤ 2n − 1, lahko zapiˇsemo
Pn−1
Pn−1
a0l = j=0 aj ω lj , b0l = k=0 bk ω lk ,
pri 0 ≤ l ≤ 2n − 1. Torej velja
a0l b0l =
n−1
X n−1
X
aj bk ω l(j+k) .
(3.11)
j=0 k=0
Zapiˇsimo sedaj
a ◦ b = [c0 , c1 , . . . , c2n−1 ] t
ter
F (a ◦ b) = [c00 , c01 , . . . , c02n−1 ] t .
Ker velja cp =
P2n−1
j=0
aj bp−j , lahko zapiˇsemo
c0l =
2n−1
X 2n−1
X
aj bp−j ω lp .
p=0 j=0
ˇ zamenjamo vrstni red pri vsoti ter p − j s k, dobimo
Ce
c0l =
2n−1
X 2n−1−j
X
j=0
aj bk ω l(j+k) .
k=−j
Glede na to, da indeksa j in k lahko omejimo na interval [0, n − 1], lahko v drugi vsoti
spremenimo k = −j v k = 0 in 2n − 1 − j v n − 1, v prvi vsoti pa 2n − 1 v n − 1.
Zato je c0l enako a0l b0l , kot smo to zapisali v (3.11). 2
3.8 Primer Dana sta polinoma p(x) = 2x + 1 in q(x) = −2x + 1 (ki ju piˇsemo na
obiˇcajen naˇcin, po padajoˇcih potencah x) in ˇzelimo izraˇcunati njuno konvolucijo na
pravkar opisan naˇcin. Seveda jo je v tem primeru moˇzno izraˇcunati tudi neposredno
kot −4x2 + 1. Najprej koeficiente polinomov predstavimo z vektorjema dolˇzine 4:
p = [1, 2, 0, 0] t , q = [1, −2, 0, 0] t
(bodimo pozorni, da so sedaj koeficienti razvrˇsˇceni po naraˇsˇcajoˇcih potencah x), ki ju
nato zmnoˇzimo z leve z matriko DFT pri n = 4, ki smo jo predstavili v primeru 3.5:
F (p) = F · p = [3, 1 + 2ω, −1, 1 − 2ω] t , F (q) = F · q = [−1, 1 − 2ω, 3, 1 + 2ω] t .
Naslednji korak je izraˇcun vektorja
F (p) ∗ F (q) = [−3, 5, −3, 5] ,
88
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
na katerem nato uporabimo inverzno DFT (gl. ponovno primer 3.5):
F −1 (F (p) ∗ F (q)) =
1
[4, 0, −16, 0] ,
4
kar se ujema z neposrednim izraˇcunom. 2
V nekaterih aplikacijah uporabljamo tim. “ovito konvolucijo”.
3.9 Definicija Dana sta dva vektorja
a = [a0 , a1 , . . . , an−1 ] t , b = [b0 , b1 , . . . , bn−1 ] t .
Potem je pozitivna ovita konvolucija a in b vektor c = [c0 , c1 , . . . , cn−1 ] t s komponentami
i
n−1
X
X
ci =
aj bi−j +
aj bn+i−j .
j=0
j=i+1
Pozitivno ovito konvolucijo a in b oznaˇcujemo z a2b. Na podoben naˇcin definiramo
negativno ovito konvolucijo a in b kot vektor d = [d0 , d1 , . . . , dn−1 ] t s komponentami
di =
i
X
j=0
aj bi−j −
n−1
X
aj bn+i−j .
j=i+1
Negativno ovito konvolucijo a in b oznaˇcujemo z a3b.
3.10 Primer Naj bo n = 4 in naj bosta dana dva vektorja dolˇzine 4,
a = [a0 , a1 , a2 , a3 ] , b = [b0 , b1 , b2 , b3 ] .
V tem primeru ima njuna pozitivna (negativna) ovita konvolucija komponente
c0
c1
c2
c3
= a0 b0 ± a1 b3 ± a2 b2 ± a3 b1
= a0 b1 + a1 b0 ± a2 b3 ± a3 b2
= a0 b2 + a1 b1 + a2 b0 ± a3 b3
= a0 b3 + a1 b2 + a2 b1 + a3 b0 ,
pri ˇcemer za pozitivno ovito konvolucijo izbiramo znak +, za negativno pa znak −
(takrat ko je izbira nakazana). 2
3.11 Izrek Dana sta dva vektorja
a = [a0 , a1 , . . . , an−1 ] t , b = [b0 , b1 , . . . , bn−1 ] t .
3.3
89
DISKRETNA FOURIERJEVA TRANSFORMACIJA
Naj bo ω n-ti primitivni koren enote, za ψ pa naj velja ψ 2 = ω (torej je ψ 2n-ti
primitivni koren enote). Naj ima n multiplikativni inverz. Potem velja
a2b = F −1 (F (a) ∗ F (b))
in
ˆ
a3b = F −1 (F (ˆ
a) ∗ F (b)),
kjer velja za poljuben vektor
c = [c0 , c1 , . . . , cn−1 ] t ,
ˆ = [c0 , ψc1 , . . . , ψ n−1 cn−1 ] t .
c
Dokaz izreka je podoben dokazu izreka 3.7, ˇce upoˇstevamo ψ n = −1.
3.3.5
Rekurzivni algoritem za DFT
V tem razdelku bomo opisali osnovno idejo, ki pripelje do najenostavnejˇsega algoritma za DFT. Kot osnovo uporabljamo interpretacijo DFT s polinomi, ki smo jo
opisali v razdelku 3.3.3 in na podlagi katere
so komponente podobe vektorja
Pn−1 a =
[a0 , a1 , . . . , an−1 ], p(ω 0 ), p(ω 1 ), . . . , p(ω n−1 ) , kjer je p polinom p(x) = i=0 ai xi .
Izhajamo iz dveh preprostih lastnosti n-tega primitivnega korena enote. Naj bo
n = 2r. Potem velja
(ω j+r )2 = ω 2j ω 2r = ω 2j
(3.12)
in
ω j+r = −ω j .
(3.13)
V veljavnost (3.13) se prepriˇcamo na podlagi relacije (3.8). Namreˇc, razliko levega in
desnega dela (3.12) razcepimo in dobimo
(ω j+r + ω j )(ω j+r − ω j ) = 0.
Ker desni faktor leve strani ne more biti 0 [na podlagi (3.8)], velja torej (3.13).
Sedaj pa naj bo podan polinom p(x) z vektorjem koeficientov a. Torej
p(x) = a0 + a1 x + . . . + an−1 xn−1 .
Vpeljali bomo dva pomoˇzna polinoma, p1 (x) in p2 (x), stopnje r − 1:
p1 (x) = a1 + a3 x + . . . + a2i+1 xi + . . . + an−1 xr−1 ,
p2 (x) = a0 + a2 x + . . . + a2i xi + . . . + an−2 xr−1 .
(3.14)
Torej ima p1 (x) koeficiente lihih potenc xi polinoma p(x), p2 (x) pa sodih potenc.
Nato lahko zapiˇsemo
p(x) = xp1 (x2 ) + p2 (x2 ).
(3.15)
90
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
Ko iˇsˇcemo F (a), oziroma vrednosti p(ω k ) pri 0 ≤ k ≤ n − 1, lahko uporabimo relacijo
(3.15). Imamo torej
p(ω k )
p(ω k+r )
= ω k p1 (ω 2k ) + p2 (ω 2k ),
= ω k+r p1 (ω 2(k+r) ) + p2 (ω 2(k+r) )
= −ω k p1 (ω 2k ) + p2 (ω 2k ),
(3.16)
pri 0 ≤ k ≤ r − 1. Leve strani (3.16) lahko neposredno izraˇcunamo s algoritmom,
ki uporablja rekurzivni razcep: problem smo razbili na dva podproblema poloviˇcne
velikosti. Podproblema sta izraˇcuna pi (ω 2k ), pri 0 ≤ k ≤ r − 1 in i = 1, 2. Bodimo
pozorni na to, da je ω 2 primitivni r-ti koren enote in sta torej podproblema identiˇcna
prvotnemu problemu, razen da smo n prepolovili. Relacija (3.13) nam ˇse omogoˇca,
da dobimo eno polovico vrednosti p(ω k ) praktiˇcno zastonj (izraˇcunamo p(ω k ), pri
0 ≤ k ≤ r − 1, p(ω k+r ) pa dobimo skoraj brez dodatnega raˇcunanja, ˇce v desni strani
prve vrstice 3.16 negiramo prvi ˇclen).
3.12 Primer Opisano metodo bomo prikazali na majhnem primeru. Podan je polinom x3 + 2x2 + 2x + 1 in ˇzelimo izraˇcunati DFT vektorja njegovih koeficientov,
[1, 2, 2, 1]. V tem primeru sta p1 (x) = x + 2 in p2 (x) = 2x + 1. Lahko bi p1 in p2 ˇse
naprej razcepili in dobili ˇstiri polinome stopnje 0, vendar bomo p1 (ω 0 ), p1 (ω 2 ), p2 (ω 0 )
in p2 (ω 2 ) kar neposredno izraˇcunali z matriko DFT pri n = 2 (gl. primer 3.5).
p1 (ω 0 )
p1 (ω 2 )
p2 (ω 0 )
p2 (ω 2 )
=
=
1
1
1
−1
1
1
1
−1
2
1
1
2
=
=
3
1
3
−1
.
Nato za izraˇcun komponent transformiranega vektorja uporabimo enaˇcbe (3.16):
p(ω 0 ) =
p(ω 1 ) =
p(ω 2 ) =
p(ω 3 ) =
ω 0 p1 (ω 0 ) + p2 (ω 0 ) = 3 + 3 = 6
ω 1 p1 (ω 2 ) + p2 (ω 2 ) = −1 + ω
ω 2 p1 (ω 0 ) + p2 (ω 0 ) = 3 − 3 = 0
ω 3 p1 (ω 2 ) + p2 (ω 2 ) = −1 − ω
in dobimo isti rezultat kot ˇce [1, 2, 2, 1] neposredno zmnoˇzimo z leve z matriko DFT
za n = 4. 2
ˇ
Cas,
ki ga porabi algoritem, ki uporablja opisani izraˇcun, ocenimo na podlagi
izreka 1.3. Problem smo razcepili na dva podproblema (c = 2), ki ju moramo oba
reˇsiti (a = 2) in ker moramo za vsak element p(ω i ), 0 ≤ i ≤ n − 1, izraˇcunati le vsoto
dveh ˇclenov, je r = 1. Iz tega izpeljemo porabo ˇcasa Θ(n log n) (gl. tudi nalogo 5 za
nekatere podrobnosti).
3.3
DISKRETNA FOURIERJEVA TRANSFORMACIJA
3.3.6
91
Iterativni algoritem za DFT
Pri zasnovi algoritmov se poskuˇsamo izogibati rekurziji, ˇce je to le mogoˇce, ker je njena
realizacija ˇcasovno potratna. Izkaˇze se, da je to moˇzno storiti tudi v primeru DFT.
Podobno kot pri rekurzivnem algoritmu iz razdelka 3.3.5 izhajamo iz pojmovanja DFT
kot seznama vrednosti polinoma p(x) po modulu xn v toˇckah x = ω 0 , ω 1 , . . . , ω n−1 ,
pri ˇcemer so komponente vektorja, ki ga transformiramo, koeficienti p(x) pri stopnjah
x. Pri sestavljanju iterativnega algoritma se opiramo na dve trditvi. Prva je
3.13 Trditev Naj bo p(x) polinom nad izbranim obsegom K in naj bo c ∈ K. V tem
primeru velja
p(c) = p(x) mod (x − c).
(3.17)
Dokaz. Relacija (3.17) sledi iz tega, ker je x − c polinom prve stopnje in je zato
p(x) mod (x − c) polinom stopnje 0 (konstanta) c0 z lastnostjo
p(x) = q(x) · (x − c) + c0 ,
(3.18)
kjer je q(x) nek drug polinom, ki ima stopnjo za eno manjˇso od stopnje p(x). Oˇcitno
je pri x = c prvi ˇclen desne strani (3.18) enak 0 in je p(c) enako c0 . 2
Druga trditev, ki jo potrebujemo, je
3.14 Trditev Naj bodo p(x), s(x), t(x) in u(x) polinomi nad izbranim obsegom K in
naj velja s(x) = t(x) · u(x). V tem primeru velja
p(x) mod t(x) = (p(x) mod s(x)) mod t(x).
(3.19)
Dokaz. Relacija (3.19) sledi iz definicije p(x) mod s(x) = rs (x), kjer je rs (x) polinom,
ki ima stopnjo manjˇso ali enako stopnji s(x) ter lastnost,
p(x) = qs (x) · s(x) + rs (x),
(3.20)
pri ˇcemer je qs (x) nek drug polinom, ki zagotavlja enakost (3.20). Sedaj v levi strani
(3.19) zamenjajmo p(x) z desno stranjo (3.20):
(qs (x) · s(x) + rs (x)) mod t(x)
=
=
(qs (x) · t(x) · u(x) + rs (x)) mod t(x)
rs (x)) mod t(x).
(3.21)
Leva stran prve vrstice (3.21) je enaka desni strani druge vrstice zato, ker velja qs (x) ·
t(x) · u(x) mod t(x) = 0. 2
Relacija (3.19) omogoˇca, da uredimo vmesne delitelje v izraˇcunu p(x) mod (x−ω k ),
pri 0 ≤ k ≤ n − 1 v drevesno strukturo, s ˇcimer doseˇzemo, da izraˇcunov ni potrebno
ponavljati. Zadevo bomo najprej prikazali na primeru n = 4 in ˇsele nato podali opis
sploˇsnega algoritma.
92
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
x4 − 1
x2 − 1
x − ω0
= x−1
x2 + 1
x − ω2
= x+1
x − ω3
= x+ω
x − ω1
Slika 3.3: Drevesna urejenost deliteljev med izraˇcunom DFT pri n = 4.
x3 + 2x2 + 2x + 1
3x + 3
6
x−1
0
−1 + ω
−1 − ω
Slika 3.4: Ostanki po deljenju polinoma x3 + 2x2 + 2x + 1 z delitelji na sliki 3.3.
3.15 Primer Slika 3.3 prikazuje delitelje za primer n = 4. Mimogrede: neposredna
podrejenost dveh deliteljev nekemu tretjemu delitelju pomeni, da je produkt prvih
ˇ je podan polinom p(x) = a0 + a1 x + a2 x2 + a3 x3 , je potrebno
dveh enak tretjemu. Ce
izraˇcunati vrednosti p(x) mod (x−1), p(x) mod (x+1), p(x) mod (x−ω) in p(x) mod
(x + ω). Na podlagi relacije (3.19) bomo na primer pri izraˇcunu p(x) mod (x − ω)
najprej poiskali ostanek po deljenju p(x) z x4 − 1 (oˇcitno je to kar p(x)), nato bomo
delili ta ostanek z x2 + 1 in poiskali ostanek, in konˇcno bomo slednji ostanek delili
z x − ω. Opisano zaporedje izraˇcunov je na sliki 3.3 nakazano s ˇcrtkano potjo med
korenom in konˇcnim vozliˇsˇcem x − ω. Bodimo pozorni na to, da v spodnji vrstici
deliteljev na sliki 3.3 eksponenti ω niso urejeni v vrstnem redu 0, 1, 2, 3.
Metodo lahko prikaˇzemo na primeru 3.12, ki smo ga ˇze uporabili kot primer za
rekurzivno metodo. Izraˇcun ostankov je prikazan na sliki 3.4 in lahko ugotovimo, da
3.3
93
DISKRETNA FOURIERJEVA TRANSFORMACIJA
d03 (x)
d02 (x)
d01 (x)
d00 (x)
d10 (x)
d42 (x)
d21 (x)
d20 (x)
d30 (x)
d41 (x)
d40 (x)
d50 (x)
d61 (x)
d60 (x)
d70 (x)
Slika 3.5: Drevesna urejenost deliteljev med izraˇcunom DFT pri n = 8.
d03 (x) = x8 − ω 0
d02 (x) = x4 − ω 0
d42 (x) = x4 − ω 4
2
0
2
4
2
d01 (x) = x − ω
d21 (x) = x − ω
d41 (x) = x − ω 2
d61 (x) = x2 − ω 6
d00 (x) =
d10 (x) =
d20 (x) =
d30 (x) =
d40 (x) =
d50 (x) =
d60 (x) =
d70 (x) =
x − ω0
x − ω4
x − ω2
x − ω6
x − ω1
x − ω5
x − ω3
x − ω7
Slika 3.6: Vrednosti delitevljev pri n = 8.
so ostanki v spodnji vrstici istovetni z vrednostmi, ki smo jih dobili v primeru 3.12.
2
Sedaj se pa lotimo sploˇsnega algoritma. Obravnavali bomo primer n = 2k , pri
k ≥ 0. Delitelje uredimo v drevesno strukturo, podobno kot na sliki 3.3. Oznaˇcevanje
deliteljev, kakor tudi njihove dejanske vrednosti za primer k = 3 so prikazani na
slikah 3.5 in 3.6. Iz slik 3.3 in 3.5 ugotovimo, da ima drevo deliteljev k + 1 vodoravnih
vrstic, ki so oˇstevilˇcene od 0 do k, in sicer od spodnje vrstice do korena drevesa. Pri
delitelju z oznako dih predstavlja indeks h ˇstevilko vrstice (“viˇsino”), za prve indekse
i pri doloˇceni viˇsini h pa uporabljamo oˇstevilˇcenje, ki se zaˇcenja z 0 in uporablja
prirastek 2h . Lahko postavimo vpraˇsanje, zakaj i preprosto ne ustreza mestu delitelja
v svoji vrstici, vendar za enkrat nanj ˇse ne bomo odgovorili, naj zadostuje, da povemo,
da ima tudi ˇstevilo, ki predstavlja mesto delitelja svojo vlogo, ki jo bomo razloˇzili
v kratkem. Pri ˇstevilih, ki oznaˇcujejo eksponente oziroma indekse, je n izenaˇceno
z 0 (ker predstavljamo polinome po modulu xn !), zato za njih zadostuje dvojiˇska
94
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
i
}|
z
{
0 ... 0
l
h bitov
k bitov
Slika 3.7: Dvojiˇska predstavitev indeksa i delitelja dih .
rev4 (19) = rev4 (1011B) = 1101B = 21
Slika 3.8: Funkcija rev (dvojiˇska predstavitev je oznaˇcena z “B”).
predstavitev dolˇzine k (k bitov)5 . Pri taki predstavitvi in na podlagi pravkar zapisane
razlage predstavlja indeks i delitelja dih ˇstevilo, ki ima zadnjih h bitov enakih 0 (gl.
sliko 3.7), z drugimi besedami, i = i0 · 2h , pri nekem i0 v intervalu [0, . . . , 2k−h − 1].
Delitelji so definirani kot,
h
dih = x2 − ω s ,
(3.22)
pri ˇcemer je s podobno kot i neko ˇstevilo z dvojiˇsko predstavitvijo, ki ima na desni h
niˇcelnih bitov, torej je s = l · 2h . V takem primeru dobimo naslednjo povezavo med
delitelji v dveh sosednih vrsticah drevesa deliteljev:
h+1
x2
h+1
− ω l·2
h
h
h
h
= (x2 − ω l·2 )(x2 + ω l·2 )
h
h
h
h
n
= (x2 − ω l·2 )(x2 − ω l·2 + 2 ).
(3.23)
Preden nadaljujemo bomo zapisali ˇse neko definicijo, ki jo bomo potrebovali.
3.16 Definicija Naj bosta k in n pozitivni celi ˇstevili. Z revk (n) bomo oznaˇcevali
ˇstevilo z dvojiˇsko predstavitvijo dolˇzine k, ki je enako zrcalni podobi dvojiˇske predstavitve n (gl. sliko 3.8). V primeru, ko je dolˇzina dvojiˇske predstavitve n veˇc kot k, pred
zrcaljenjem odveˇcne bite odreˇzemo, v primeru, ko pa je manj kot k, dodamo ustrezno
ˇstevilo niˇcelnih bitov.
h
h
Sedaj se bomo poglobili v urejenost deliteljev x2 − ω l·2 v vrstici h. Relacija
h+1
h+1
(3.23) nam razodeva, da se delitelj iz viˇsje vrstice, x2
− ω l·2 , razcepi na dva
delitelja, pri katerih dobimo ustrezna eksponenta ω tako, da l · 2h+1 pomaknemo za
5 Seveda pa to ne velja za koeficiente a polinomov, ki jih predstavljamo kot obiˇ
cajna ˇstevila, ne
i
glede na vrednost k.
3.3
DISKRETNA FOURIERJEVA TRANSFORMACIJA
95
h + 1 bitov
z
}|
{
0 ... ... 0
l
0
l
1
l
0 ... 0
|
0 ... 0
{z }
h bitov
Slika 3.9: Odvisnost indeksov deliteljev v niˇzji vrstici drevesa od indeksa delitelja v
viˇsji vrstici.
eno dvojiˇsko mesto v desno in nato enkrat v prvo dvojiˇsko mesto z leve zapiˇsemo 0,
drugiˇc pa 1 (gl. sliko 3.9). Na podlagi te ugotovitve lahko dokaˇzemo naslednjo trditev,
3.17 Trditev Naj bo,
h
h
x2 − ω li ·2 , i = 0, 1, . . . , 2k−h − 1,
delitelj na mestu i z leve v vrstici h. V tem primeru je li · 2h = revk (i). Oˇcitno velja
tudi i = revk (li · 2h ).
Preden se lotimo dokaza, naj opozorimo, da v pravkar zapisani trditvi uporabljamo
mesto delitelja v vrstici in ne njegovega indeksa, kot je bil opisan prej.
Dokaz. Za zgornjo vrstico drevesa je trditev oˇcitna, saj vsebuje le en delitelj z
vrednostjo l0 = 0. Sedaj denimo, da trditev velja za delitelje v vrstici h + 1 in naj bo
h+1
h+1
x2
− ω l·2
nek delitelj iz te vrstice. Njegovo mesto je revk (l · 2h+1 ) (na podlagi
predpostavke), mesti njegovih naslednikov v niˇzji vrstici pa sta 2 · revk (l · 2h+1 ) in
ˇ
2 · revk (l · 2h+1 ) + 1 (ker je deliteljev v niˇzji vrstici dvakrat toliko kot v viˇsji). Ce
h
0
00
sta koeficienta pri 2 dveh naslednikov l in l , sledi iz (3.23) oziroma pripombe pred
trditvijo 3.17, da je
revk (l0 2h ) = 2 · revk (l · 2h+1 )
in
revk (l00 2h ) = 2 · revk (l · 2h+1 ) + 1.
Slednji dve enaˇcbi veljata zato, ker se desni pomik koliˇcine l · 2h+1 prevede v levi
pomik (in s tem mnoˇzenje z 2) koliˇcine revk (l · 2h+1 ). 2
96
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
3.18 Primer Naj bo n = 23 = 8. V tem primeru so delitelji v spodnji vrstici drevesa
(h = 0),
d00 (x) = (x − ω 0 ),
d40 (x) = (x − ω 1 ),
4
d10 (x) = (x − ω ),
d50 (x) = (x − ω 5 ,
2
d20 (x) = (x − ω ),
d60 (x) = (x − ω 3 ),
6
d30 (x) = (x − ω ),
d70 (x) = (x − ω 7 ).
Torej je zaporedje eksponentov ω,
0, 4, 2, 6, 1, 5, 3, 7,
kar je enako,
rev3 (0), rev3 (1), rev3 (2), rev3 (3), rev3 (4), rev3 (5), rev3 (6), rev3 (7). 2
Pri eksponentu ω, l · 2h , delitelja dih bodimo pozorni na dejstvo, da v primeru, ko
ne bi zrcalili zaporednega mesta delitelja temveˇc njegov indeks i (ki ima desnih h bitov
enakih 0), bi dobili l in ne l · 2h . Do sedaj smo za eksponent ω potrebovali lastnost,
da je mnogokratnik 2h , zato da smo izpeljali rekurzivno relacijo (3.23), odslej pa nas
njegov razcep v obliki l · 2h ne bo zanimal in bo zadostovalo, da je njegova vrednost
v zrcalni povezavi z mestom delitelja v svoji vrstici.
h
Glede na to, da imajo vsi delitelji dij preprosto obliko x2 − ω s , se tudi izraˇcun
P2h+1 −1
ostankov ustrezno poenostavi. Ko je p(x) = j=0
aj xj , lahko zapiˇsemo
p(x) mod (x
2h
s
− ω ) = r(x) =
h
2X
−1
(aj + ω s aj+2h )xj .
(3.24)
j=0
Relacijo (3.24) preverimo tako, da desno stran vstavimo namesto r(x) v

h
2X
−1
h
p(x) = 
aj+2h xj  (x2 − ω s ) + r(x).
j=0
Popoln iterativni algoritem za DFT je prikazan na sliki 3.10. V prikazanem algoritmu so vhodni podatki v tabeli a, rezultat pa v b. Bodimo pozorni na operacijo
zrcaljenja dvojiˇske predstavitve l v vrstici 8, ki je potrebna zaradi trditve 3.17.
Naˇsa zadnja pripomba o algoritmu na sliki 3.10 se bo nanaˇsala na njegovo porabo
prostora. Koeficienti polinoma r0,k (ostanek pri korenu drevesa) so kar vhodni podatki
a. Nato pa bi se na prvi pogled zdelo, da v vsaki vrstici drevesa potrebujemo eno
tabelo, ki vsebuje koeficiente ri,h+1 , ter dve, ki vsebujeta koeficiente rl,h in rl+2h ,h .
Ker pa je koeficientov ri,h+1 natanko toliko kot koeficientov rl,h in rl+2h ,h skupaj, je
skupna dolˇzina izhodnih tabel enaka dolˇzini vhodne tabele. Nadalje, ˇce smo pozorni
ugotovimo, da koeficiente rl,h in rl+2h ,h pravzaprav lahko spravimo v prostor, ki so ga
prej zasedali koeficienti ri,h+1 . Namreˇc, ˇce v vrsticah 9 in 10 izraˇcun koeficientov rl,h
3.3
DISKRETNA FOURIERJEVA TRANSFORMACIJA
1
3
3
4
5
6
(∗ n = 2k ∗)
BEGIN
Pn−1
(∗ Naj bo r0,k = j=0 aj xj ∗)
FOR h:=k −1 BY −1 TO 0 DO
i:=0 ;
WHILE i < n DO
P2h+1 −1
7
8
(∗ Naj bo ri,h+1 =
s:= revk (i DIV 2h ) ;
9
ri,h :=
10
11
13
13
14
16
97
P2h −1
j=0
j=0
aj xj ∗)
(aj + ω s aj+2h )xj ;
P2h −1
ri+2h ,h :=
(aj + ω s+n/2 aj+2h )xj ;
j=0
(h+1)
i := i + 2
END
END ;
FOR i:=0 TO n−1 DO brevk (i) := ri,0 END
END
Slika 3.10: Iterativni algoritem za DFT
in rl+2h ,h izvajamo istoˇcasno, lahko koeficiente rl,h zapisujemo na mesta koeficientov
aj ostanka ri,h+1 pri 0 ≤ j < 2h , koeficiente rl+2h ,h pa na mesta koeficientov aj+2h . Iz
tega sledi, da potrebujemo le eno tabelo koeficientov med celotnim izraˇcunom. Sedaj
postane oˇcitna tudi indeksacija deliteljev dih : i predstavlja zaˇcetni indeks koeficientov
ostanka ri,h v tabeli koeficientov a. Ker ima ri,h 2h koeficientov, naraˇsˇca i s takim
prirastkom. Lahko tudi ugotovimo, da posebna izhodna tabela b ni potrebna, kajti
zaradi lastnosti revk (revk (i)) = i, lahko izraˇcun v vrstici 14 izpeljemo kot eno samo
zaporedje zamenjav dveh vrednosti, ki ga lahko opravimo z eno zaˇcasno spremenljivko
(za podrobnosti gl. nalogo 6).
Do sedaj smo zanemarili neko navidez pomembno vpraˇsanje: opisali smo dva
uˇcinkovita algoritma za DFT, vendar nobenega za inverzno transformacijo! Glede na
to, da inverzno transformacijo potrebujemo enako pogosto kot DFT, bi kazalo, da
problema sploh nismo reˇsili. Vendar je na sreˇco moˇzno iz algoritma za DFT brez
teˇzav pridobiti algoritem za inverzno DFT na podlagi ugotovitve, da je v primeru,
ko je ω n-ti primitivni koren enote, tudi ω −1 n-ti primitivni koren enote (preverjanje
tega prepuˇsˇcamo bralcu za vajo). Na podlagi tega je moˇzno inverzno matriko DFT
predstaviti v obliki
1 −ij 1
F −1 =
ω
=
(ω −1 )ij .
n
n
Matrika na desni (brez faktorja n1 ) seveda predstavlja matriko DFT glede na nov n-ti
primitivni koren enote ω −1 . To pa pomeni, da je moˇzno inverzno DFT izraˇcunati
s poljubnim algoritmom za DFT po zamenjavi ω z ω −1 in z naknadnim mnoˇzenjem
vseh komponent rezultata z n1 .
98
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
Na koncu bi bilo potrebno ˇse preveriti, da iterativni algoritem na sliki 3.10 zahteva
O(n2 log n) operacij. Na ta naˇcin bi se prepriˇcali, da je po velikostnem redu enako
uˇcinkovit kot rekurzivni algoritem, ker pa ne uporablja rekurzije, lahko upamo, da je
dejansko boljˇsi (in tudi je). Vendar podrobno izpeljavo tega dejstva izpuˇsˇcamo, ker
brez teˇzav sledi iz zapisa algoritma na sliki 3.10 (vaja).
3.4
Povzetek osnovnih pojmov
1. Klasiˇcni algoritem za mnoˇzenje matrik in njegova poraba ˇcasa
2. Winogradov algoritem in zakaj ga ni moˇzno uporabiti rekurzivno
3. Strassenov algoritem in ocena njegove porabe ˇcasa
4. n-ti primitivni koren enote in njegove lastnosti
5. Matrika diskretne Fourierjeve transformacije in njene lastnosti
6. Koeficientna in vrednostna predstavitvi polinoma
7. Polinomi po modulu xn
8. Povezava med DFT in polinomi
9. Konvolucija polinomov ter izrek o konvoluciji
10. Pozitivna in negativna ovita konvolucija ter izrek o pozitivni in negativni oviti konvoluciji
11. Rekurzivni algoritem za DFT in lastnosti n-tega primitivnega korena enote, ki omogoˇcajo
njegovo delovanje
12. Iterativni algoritem za DFT (povezava med raˇcunanjem vrednosti polinoma in raˇcunanjem
ostanka polinoma po deljenju z linearnim polinomom; naˇcelo postopnega ali iteriranega raˇcunanja ostankov; urejanje deliteljev pri raˇcunanju ostankov v dvojiˇsko drevo;
operator zrcaljenja)
13. Algoritem za inverzno DFT.
3.5
Naloge
1. Preverite izraˇcun, da definicija konvolucije dveh polinomov stopnje n − 1 vsebuje n2
mnoˇzenj.
2. Opiˇsite matriko koordinatne transformacije, ki spremeni koeficientno predstavitev polinoma p(x) stopnje n−1 v vrednostno predstavitev pri vrednostih x = c0 , c1 , . . . , cn−1 .
3. Kakˇsen pogoj mora biti izpolnjen, da je predstavitev polinomov po modulu xn z vrednostmi pri c0 , c1 , . . . , cn−1 enakovredna predstavitvi s koeficienti pri xi ? Razmislite
o pomenu pojma “enakovredna”.
4. Bazo prostora polinomov po modulu xn pri koeficientni predstavitvi tvorijo polinomi
xi , 0 ≤ i ≤ n − 1. Kateri polinomi pa predstavljajo bazo prostora po opravljeni DFT?
99
3.5. NALOGE
5. Pri realizaciji rekurzivnega algoritma za DFT se sreˇcamo z naslednjim problemom: pri
prvem poskusu ugotovimo, da je potrebno uporabiti poleg prostora za vektor koeficientov vhodnega polinoma ˇse dodaten prostor za koeficiente polinomov, ki nastanejo
ˇ je prvotni vektor dolˇzine n, potrebujemo 2n dodatnih celic
pri rekurzivnih klicih. Ce
prostora (naloga: preverite to trditev). Razmislite o realizaciji rekurzivnega algoritma,
ki ne bi potreboval dodatnega prostora (kot smo to dosegli pri algoritmu za urejanje
s porazdelitvami). Napotek: osnovna teˇzava je, da so pri koliˇcinah, ki predstavljajo
rezultat rekurzivnih klicev,
p2 (ω 0 ), p1 (ω 0 ), . . . , p2 (ω 2i ), p1 (ω 2i ), . . . , p2 (ω 2(r−1) ), p1 (ω 2(r−1) )
in rezultatu DFT
b0 , b1 , . . . , br , br+1 , . . . , bn−1 ,
bi in br+i , pri 0 ≤ i ≤ r − 1 odvisni od p2 (ω 2i ) in p1 (ω 2i ), kar prepreˇcuje, da za prvi
in drugi vektor uporabimo isti prostor.
Moˇzna reˇsitev je, da rezultata rekurzivnih klicev preuredimo v vrstni red
p2 (ω 0 ), . . . , p2 (ω 2i ), . . . , p2 (ω 2(r−1) ), p1 (ω 0 ), . . . , p1 (ω 2i ), . . . , p1 (ω 2(r−1) ).
Po tem je moˇzno prostor, ki sta ga zasedala p2 (ω 2i ) in p1 (ω 2i ), uporabiti za bi in br+i .
Najugodneje je preurejanje izvajati ˇze na prvotnih koeficientih polinoma p. Koliko
ˇcasa porabi opisani postopek?
6. Na koncu iterativnega algoritma za DFT smo morali opraviti zamenjave koeficientov v
izhodni tabeli tako, da smo vsak koeficient zamenjali s koeficientom, ki ima “zrcalni”
indeks. Zapisano je, da za to operacijo ni potrebno imeti posebne tabele izhodnih
koeficientov. Vendar bi se na prvi pogled zdelo, da potrebujemo vsaj en bit informacije
na koeficient, ki nam pri obiskovanju koeficientov pove, ali smo koeficient ˇze zrcalili.
Predlagajte algoritem, ki odpravi potrebo tudi po tem dodatnem prostoru.
100
POGLAVJE 3. ALGORITMI Z REKURZIVNIM RAZCEPOM
Poglavje 4
ˇ
ˇ
POZRE
SNI
ALGORITMI
4.1
Uvod
V tem poglavju se bomo zaˇceli ukvarjati z optimizacijskimi problemi, kot pravimo
nalogi iskanja najboljˇse reˇsitve v neki mnoˇzici reˇsitev. Optimizacijski problemi se
pojavljajo v ˇstevilnih razliˇcicah, ki pogojujejo tudi razliˇcne pristope k njihovemu
reˇsevanju. V najpreprostejˇsi razliˇcici naloge imamo mnoˇzico “objektov”, ki jim znamo
prirediti “ceno”, oziroma vrednost, in iˇsˇcemo takega, ki ima najmanjˇso (ali najveˇcjo)
ceno, oziroma vrednost1 . Pogosto uporabljamo pri izbiri predmetov poleg kriterija
vrednosti ˇse kakˇsen drug kriterij, ki mu preprosto pravimo kriterij “dopustnosti”.
Sploˇsno zgradbo takega problema predstavlja kar navadno, linearno iskanje, kot ga
prikazuje slika 4.1. Ponavadi je osnovna teˇzava pri podobnih problemih velikost n
in je potrebno vloˇziti precej napora, da spravimo obseg raˇcunanja v znosne meje.
V skrajnem primeru je n neskonˇcno in je potrebno z matematiˇcno analizo izraˇcun
optimuma prevesti na iskanje po konˇcni mnoˇzici.
Vˇcasih pa imamo opravka z zmerno velikostjo n, vendar je naloga poiskati neko
podmnoˇzico elementov ui , 1 ≤ i ≤ n, ki ima ˇzelene, optimalne lastnosti (gl. sliko 4.2).
V takem primeru naloga pogosto postane neobvladljiva tudi pri zmerno velikem n (in
kljub temu, da je program na sliki 4.2 praktiˇcno identiˇcen s programom na sliki 4.1),
zato ker je ˇstevilo podmnoˇzic eksponentno odvisno od n.
V nekaterih primerih pa je moˇzno nalogo na sliki 4.2 moˇcno poenostaviti in izpeljati izbiro elementov optimalne podmnoˇzice tako, da jih izbiramo enega za drugim,
pri ˇcemer vsak element obravnavamo le enkrat. To je moˇzno, kadar je vrednost neke
podmnoˇzice preprosto vsota vrednosti njenih elementov in ko izbira nekega elementa
ne more postaviti pod vpraˇsaj izbire njegovih predhodnikov (izbire elementov so neodvisne). V tem primeru je moˇzno elemente ovrednotiti pred postopkom sestavljanja
optimalne podmnoˇzice in jih vkljuˇcevati v optimalno podmnoˇzico na podlagi njihove
vrednosti. Ker opisan algoritem najprej “pohrusta” element z najveˇcjo vrednostjo
1 Izraz
cena je primeren, ko iˇsˇ
cemo najmanjˇso koliˇ
cino, vrednost pa, ko iˇsˇ
cemo najveˇ
cjo.
101
102
ˇ SNI
ˇ ALGORITMI
POGLAVJE 4. POZRE
VAR maxvr :INTEGER;
x ,maxelx :index ; (∗ tip, ki mu pripadajo indeksi elementov ∗)
BEGIN
(∗ U je mnoˇzica elementov u1 , u2 , . . . , un ∗)
maxelx :=1; maxvr :=vrednost(u1 );
FOR x :=2 TO n DO
IF dopustno(ux ) & (vrednost(ux ) > maxvr ) THEN
maxvr :=vrednost(ux ); maxelx :=x
END
END
(∗ rezultat je element z indeksom maxelx in vrednostjo maxvr ∗)
END
Slika 4.1: Osnovna oblika algoritma za reˇsevanje optimizacijskega problema
VAR maxvr :INTEGER;
(∗ U je mnoˇzica elementov u1 , u2 , . . . , un ∗)
(∗ podmnoˇzico Ax ⊂ U predstavljamo s karakteristiˇcno funkcijo x, ki pa jo lahko
predstavimo kot ˇstevilsko vrednost, ˇcigar dvojiˇska predstavitev nakazuje,
kateri elementi so vkljuˇceni v podmnoˇzico ∗)
x ,mnx :INTEGER; (∗ indeksa trenutne podmnoˇzice in maksimalne podmnoˇzice ∗)
BEGIN
mnx :=0; maxvr :=vrednost(Amnx );
FOR x :=1 TO 2n − 1 DO
IF dopustno(Ax ) & (vrednost(Ax ) > maxvr ) THEN
maxvr :=vrednost(Ax ); mnx :=(x )
END
END
(∗ rezultat je Amnx z vrednostjo maxvr ∗)
END
Slika 4.2: Iskanje optimalne podmnoˇzice
ˇ SNEGA
ˇ
4.2. OSNOVNA ZGRADBA POZRE
ALGORITMA
103
TYPE
Element = . . .
VAR maxvr :INTEGER; s:SetOfElement;
VAR a: ARRAY OF Element;
BEGIN
(∗ U je mnoˇzica elementov u1 , u2 , . . . , un ∗)
(∗ Elemente u1 , u2 , . . . , un uredimo po nenaraˇsˇcajoˇci
vrednosti in tako urejeno zaporedje priredimo tabeli a ∗)
maxvr :=0; s:=∅;
FOR x :=1 TO n DO
IF dopustno(s∪{a[x]}) THEN
s:=s∪{a[x]} ; INC (maxvr ,Vrednost(a[x ]))
END
END
(∗ rezultat je mnoˇzica s z vrednostjo maxvr ∗)
END
Slika 4.3: Osnovna oblika poˇzreˇsnega algoritma
(najbolj “slasten” element), mu pravimo, da je “poˇzreˇsen”.
4.2
Osnovna zgradba poˇ
zreˇ
snega algoritma
Osnovna zgradba poˇzreˇsnega algoritma je prikazana na sl. 4.3. Iz slike je razvidno, da pri takem naˇcinu reˇsevanja ne gre za zapleten program in je torej morebitna
teˇzavnost reˇsevanja problema s poˇzreˇsnim algoritmom kveˇcjemu v iskanju primernega
poˇzreˇsnega vrstega reda in pa v dokazovanju, da poˇzreˇsna metoda resniˇcno poiˇsˇce
reˇsitev.
V preostanku poglavja bomo prikazali nekaj zgledov, kako se prepriˇcamo v pravilnost poˇzreˇsnega reˇsevanja problemov.
4.3
Razvrˇ
sˇ
canje zapisov na magnetnem traku
Imamo n zapisov, ki jih ˇzelimo zapisati na magnetni trak tako, da jih lahko kasneje
po potrebi preberemo. Naprava za magnetni trak ima lastnost, da pred vsako zahtevo
po branju zapisa trak previje na zaˇcetek, nato ˇzeleni zapis poiˇsˇce tako, da vsebino
traku bere od zaˇcetka proti koncu, dokler ne prebere iskanega. Trak se premika s
konstantno hitrostjo in zato je ˇcas za celotno operacijo sorazmeren dolˇzini traku do
ˇ je verjetnost zahteve po branju i-tega zapisa enaka pri vseh
konca iskanega zapisa. Ce
i, 1 ≤ i ≤ n, katero zaporedje zapisov na traku zagotavlja najmanjˇsi povpreˇcni ˇcas
branja enega zapisa. Dolˇzina zapisa z indeksom i je li . Naj bo zaporedje zapisov na
traku
i1 , i2 , . . . , in .
(4.1)
ˇ SNI
ˇ ALGORITMI
POGLAVJE 4. POZRE
104
ˇ
Cas,
ki ga porabimo za branje j-tega zapisa je potemtakem,
tj = c ·
j
X
lik ,
k=1
kjer je c koeficient proporcionalnosti med ˇcasom in dolˇzino. Povpreˇcni ˇcas za branje
vseh zapisov pri privzetku, da je njihovo branje enakoverjetno, pa je
n
t=
n
j
1X
c XX
tj =
lik .
n j=1
n j=1
(4.2)
k=1
Naloga je torej, poiskati zaporedje (4.1), ki zagotavlja minimalno vrednost koliˇcine
(4.2).
ˇ
Ceprav
je naloga trivialna, predstavlja njena reˇsitev prikaz osnovne tehnike reˇsevanja
sorodnih problemov. Naloga je namreˇc trivialna zato, ker iz pogojev vidimo, da se
zapisi pri zaˇcetku traku veˇckrat berejo od zapisov pri koncu in je torej smiselno postaviti krajˇse zapise na zaˇcetek. Torej na podlagi tega premisleka uganemo, da je
pravilna reˇsitev razvrstitev zapisov v nepadajoˇcem zaporedju njihove dolˇzine. V tem
primeru je predikat dopustno na sliki 4.3 neodvisen od x in vedno resniˇcen. Sedaj
dokaˇzimo, da v takem primeru poˇzreˇsno zaporedje predstavlja pravilno reˇsitev. Naj
bo
I = i1 , i2 , . . . , in ,
poˇzreˇsno zaporedje, torej zaporedje, za katerega velja
li1 ≤ li2 ≤ . . . ≤ lin ,
pri ˇcemer imamo dodaten pogoj, da v primeru dveh zapisov ij in ij+1 enakih dolˇzin velja ij < ij+1 . Sedaj denimo, da to zaporedje ni pravilna reˇsitev. Z drugimi besedami,
obstaja neko drugo zaporedje,
J = j1 , j2 , . . . , jn ,
ki je optimalno. Glede na to, da sta I in J razliˇcna, obstaja prvi indeks (ko gremo od
zaˇcetka proti koncu), kjer se razlikujeta. Naj bo to indeks h. Torej velja ik = jk , 1 ≤
k < h, in ih 6= jh . In ker se v obeh zaporedjih pojavljajo vsi indeksi, gotovo obstaja
t´
ako k > h, da je jk = ih . Sedaj J spremenimo v J 0 tako, da zamenjamo poloˇzaja jh
in jk , nato pa na podlagi (4.2) izraˇcunamo t(J) − t(J 0 ):
c(k − h)
(ljh − ljk ).
n
Glede na to, da velja ljk = lih ≤ ljh , ugotovimo, da velja t(J) − t(J 0 ) ≥ 0. V
ˇ
primeru vrednosti 0 je J 0 enakovredna reˇsitev, vendar bolj podobna reˇsitvi I. Ce
postopek nadaljujemo z J 0 namesto J, dobimo na koncu v primeru, ko je razlika
med povpreˇcnima ˇcasoma zaporedij vedno 0, zaporedje, ki je identiˇcno z I, kar je v
nasprotju s privzetkom, da I ni pravilna reˇsitev. Ko pa velja t(J) − t(J 0 ) > 0, smo
dobili strogo boljˇso reˇsitev od J, kar je v protislovju s privzetkom, da je J optimalna
reˇsitev.
t(J) − t(J 0 ) =
ˇ
4.4. RAZVRSˇCANJE
POSLOV V DELAVNICI Z ENIM STROJEM
•
reˇsitev
1,2
1,3
1,4
2,3
3,4
1
2
3
4
zaporedje
2,1
1,3 ali 3,1
4,1
2,3
4,3
1
2
3
4
105
vrednost
110
115
127
25
42
100
100
15
27
Slika 4.4: Reˇsitev problema razvrˇsˇcanja poslov iz primera 4.1
4.4
Razvrˇ
sˇ
canje poslov v delavnici z enim strojem
Neka delavnica ima en sam stroj, ki obdeluje posle enega za drugim in za vsak posel
ˇ imamo n poslov, tako da je i-temu prirejena vrednost vi in rok
porabi enoto ˇcasa. Ce
izgotovitve ti , se postavlja problem poiskati podmnoˇzico poslov in vrstni red njihovega
izvajanja, s katerima doseˇzemo najveˇcjo skupno vrednost izgotovljenih poslov pri
pogoju, da so vsi posli iz podmnoˇzice dokonˇcani do svojega roka.
4.1 Primer Imamo naslednje podatke:
n = 4 v = h100, 10, 15, 27i t = h2, 1, 2, 1i ,
kjer je v vektor vrednosti poslov, t pa vektor roka izgotovitve. Slika 4.4 prikazuje vse
moˇzne reˇsitve ter med njimi optimalno (gl. tudi nalogo 1). 2
Najprej vpeljemo nekaj pojmov: zaporedje poslov hi1 , i2 , . . . , ik i je dopustno, ko
se posli lahko obdelujejo v takem zaporedju, ne da bi katerikoli zamujal. Podmnoˇzica
poslov {i1 , i2 , . . . , ik } je dopustna v primeru, ko za posle iz podmnoˇzice obstaja neko
dopustno zaporedje.
Sedaj dokaˇzemo, da ni potrebno obravnavati vseh moˇznih zaporedij poslov iz neke
podmnoˇzice, temveˇc je pri preverjanju dopustnosti podmnoˇzice potrebno preveriti le
eno samo zaporedje.
ˇ je zaporedje izvajanja poslov
4.2 Trditev Ce
J = hj1 , j2 , . . . , jk i,
dopustno, je dopustno tudi poˇzreˇsno zaporedje
I = hi1 , i2 , . . . , ik i,
ki ima lastnost, da so posli urejeni po nepadajoˇcem roku izgotovitve: ti1 ≤ ti2 ≤ . . . ≤
tik , v primeru enakega roka pa po naraˇsˇcajoˇcem indeksu.
106
ˇ SNI
ˇ ALGORITMI
POGLAVJE 4. POZRE
Dokaz. Trditev dokaˇzemo podobno, kot smo dokazali optimalnost poˇzreˇsnega zaporedja iz razdelka 4.3: naj bo I poˇzreˇsno zaporedje in denimo, da ni dopustno. J je
dopustno zaporedje, ki pa se razlikuje od I. V tem primeru obstaja nek prvi indeks h
(od leve proti desni), pri katerem se zaporedji razlikujeta. Ker je I poˇzreˇsno zaporedje,
velja tih ≤ tjh in ker obe zaporedji vsebujeta iste elemente, je posel z indeksom ih tudi
v zaporedju J, na primer na k-tem mestu, pri ˇcemer velja k > h in seveda jk = ih .
Ko v J zamenjamo mesti poslov jh in jk , dobimo zaporedje J 0 , ki je bolj podobno
I in prav tako dopustno. Namreˇc jk = ih lahko obdelamo na h-tem mestu, ker vsak
posel lahko prestavimo naprej; po drugi strani pa lahko jh obdelamo na k-tem mestu
zato, ker velja tih = tjk ≤ tjh (ˇce je bilo moˇzno obdelati jk na k-tem mestu, je gotovo
moˇzno obdelati na tem mestu tudi jh , ki ima enak ali kasnejˇsi rok). Z veˇckratno
uporabo opisanega postopka pridemo do dopustnega zaporedja, ki je identiˇcno z I. 2
Naslednji izrek pa utemeljuje uporabo poˇzreˇsne metode.
4.3 Izrek Optimalno zaporedje izvajanja poslov je poˇzreˇsno zaporedje
I = hi1 , i2 , . . . , ik i,
kjer na koraku j izberemo posel z najveˇcjo vrednostjo med preostalimi posli, pod pogojem, da po prikljuˇcitvi novega posla mnoˇzica izbranih poslov ostane dopustna.
Dokaz. Naj trditev iz izreka ne drˇzi in naj bo I zaporedje poslov na podlagi poˇzreˇsnega
kriterija, kot je opisano v trditvi,
J = hj1 , j2 , . . . , jr i,
pa domnevno razliˇcno, optimalno zaporedje.
Najprej obe zaporedji uredimo po padajoˇci vrednosti, v primeru enakih vrednosti
pa po naraˇsˇcajoˇcem indeksu:
vi1 ≥ vi2 ≥ . . . ≥ vik ,
vj1 ≥ vj2 ≥ . . . ≥ vjr .
Takoj ugotovimo, da I ni stroga podmnoˇzica J (I ⊂ J in I 6= J), ker bi v takem
primeru tudi poˇzreˇsna metoda nadaljevala z izbiranjem elementov. Torej eksistira
indeks h ≤ min(k, r), tako da velja
iq = jq , q = 1, 2, . . . , h − 1 in ih 6= jh .
Poˇzreˇsna metoda izbira posle po padajoˇci vrednosti, v primeru enakih vrednosti
pa po naraˇsˇcajoˇcem indeksu. Zato velja vih ≥ vjh . V primeru vih > vjh ugotovimo,
da ih ∈
/ J (ker smo zaporedje J naknadno uredili po padajoˇci vrednosti oziroma, v
primeru enakih vrednosti, po naraˇsˇcajoˇcem indeksu); pri vih = vjh pa prav tako velja
ih ∈
/ J, ker poˇzreˇsna metoda v takem primeru posle izbira na podlagi naraˇsˇcajoˇcega
indeksa, J pa smo na tak naˇcin uredili naknadno.
107
4.5. POVZETEK OSNOVNIH POJMOV
Ker je J dopustna reˇsitev, lahko posle, ki jo sestavljajo, izvrˇsimo v vrstnem redu
nepadajoˇcega roka izgotovitve. Naj bo R podmnoˇzica poslov iz J, ki vsebuje zaˇcetne
posle iz pravkar opisanega zaporedja izvajanja, do vkljuˇcno posla, ki se izvaja na
koraku tih . Ker vsak posel traja en korak, velja
| R | = min(r, tih ).
Toda | R | < tih ni moˇzno (ker bi potem lahko vkljuˇcili ˇse posel ih ); torej velja
| R | = t ih .
Ker so posli do h-tega prisotni v obeh reˇsitvah, obstaja v R posel jh0 , pri h0 > h.
Sedaj sestavimo mnoˇzico,
J 0 = J − {jh0 } + {ih }.
Mnoˇzica J 0 je dopustna. Ker velja vih ≥ vjh ≥ vjh0 , velja tudi
X
i∈J 0
vi ≥
X
vi .
(4.3)
i∈J
Torej smo priˇsli do reˇsitve, ki je na podlagi (4.3) bodisi boljˇsa od J, kar je v nasprotju s
privzetkom o optimalnosti J, ali prav tako optimalna in bolj podobna poˇzreˇsni reˇsitvi
(ima daljˇsi skupni zaˇcetek). 2
Za nalogo razvrˇsˇcanja poslov v delavnici z enim strojem prikazuje slika 4.5 preprost
algoritem, ki uporablja urejanje z navadnim vstavljanjem. Reˇsitev E vsebuje posle, ki
so na podlagi trditve 4.2 urejeni po naraˇsˇcajoˇcem roku izgotovitve. Zanka v vrsticah
33–39 obravnava predmete enega za drugim in za vsak predmet preverja, ali ga je
dopustno vstaviti v obstojeˇco reˇsitev. To je moˇzno takrat, ko imajo vsi predmeti s
kasnejˇsim rokom kot je rok predmeta i, ˇse toliko zaloge pri svojem roku izgotovitve,
da jih lahko v reˇsitvi prestavimo za eno mesto viˇsje.
4.5
Povzetek osnovnih pojmov
1. Opis optimizacijskega problema
2. Opis poˇzreˇsne metode
3. Osnovna teˇzava pri realizaciji poˇzreˇsne metode
4. Znaˇcilen naˇcin dokazovanja pravilnosti poˇzreˇsne metode na primeru razvrˇsˇcanja zapisov na magnetnem traku
5. Naloga razporejanja poslov v delavnici z enim strojem.
ˇ SNI
ˇ ALGORITMI
POGLAVJE 4. POZRE
108
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
19
19
20
21
22
24
24
25
26
27
28
29
31
31
32
33
34
35
36
37
38
39
41
41
(∗ ˇstevilo poslov je n in imajo indekse 1, 2, . . . , n. Podatki o poslih
so zapisani v tabeli AElt, urejeni pa so po nenaraˇsˇcajoˇcih cenah;
AElt[i].t je skrajni rok izgotovitve posla i, AElt[i].v pa je njegova
vrednost. E[r] je indeks posla v optimalni reˇsitvi, ki se izvaja na
koraku r ∗)
TYPE Elt=RECORD v ,t:INTEGER (∗ opis posla ∗)
END;
VAR (∗ posli urejeni po nenaraˇsˇcajoˇci vrednosti ∗)
AElt : ARRAY n OF Elt ;
maxvr : INTEGER;
(∗ reˇsitev urejena po naraˇsˇcajoˇcem roku izgotovitve ∗)
E : ARRAY n+1 OF INTEGER;
i, (∗ tekoˇci indeks tabele AElt ∗)
j , (∗ pomoˇzna spremenljivka ∗)
k , (∗ tekoˇci indeks reˇsitve E ∗)
r , (∗ meja znotraj E , do katere elementov ne prestavljamo ∗)
: INTEGER;
PROCEDURE Dopustno(i,k :INTEGER;
VAR r :INTEGER):BOOLEAN ;
(∗ posel i je moˇzno dodati reˇsitvi velikosti k ;
r je mesto, nad katerega vstavimo nov posel ∗)
BEGIN
r :=k ;
(∗ poiˇsˇcemo mesto posla i ∗)
WHILE (E [r ].t > AElt[i].t) & (E [r ].t # r ) DO DEC (r ) END;
(∗ preverimo dopustnost ∗)
RETURN (E [r ].t≤AElt[i].t) & (AElt[i].t > r )
END Dopustno ;
BEGIN AElt[0].t:=0;E [0]:=0; (∗ ˇcuvaj ∗)
maxvr :=0; k :=1; E [1]:=1;
FOR i:=2 TO n DO
IF Dopustno(i,k ,r ) THEN
(∗ elemente reˇsitve prestavimo za eno mesto ∗)
FOR j :=k TO r +1 BY −1 DO E [j +1]:=E [j ] END;
(∗ i postavimo na svoje mesto v reˇsitvi, poveˇcamo k in maxvr ∗)
E [r +1]:=i; INC (k ); INC (maxvr ,AElt[k ].v )
END;
END
END.
Slika 4.5: Podrobnosti programa za razvrˇsˇcanje poslov
4.6. NALOGE
4.6
109
Naloge
1. Pri primeru 4.1 opravite natanˇcno analizo in dokaˇzite, da slika 4.4 prikazuje vse moˇzne
reˇsitve.
2. (Cormen, Leiserson in Rivest) Potnik se pelje po avtocesti od mesta A do B in ˇzeli
potovanje opraviti s ˇcimmanj postanki za polnjenje goriva. Ima tudi karto z razdaljami
ˇ velja privzetek, da v potnikovo posodo za gorivo gre
do vseh avtocestnih servisov. Ce
veˇc goriva kot je potrebno za najveˇcjo razdaljo med sosednjima servisoma, sestavite
uˇcinkovit algoritem za opisano nalogo in dokaˇzite, da je pravilen.
ˇ
3. Podanih je n predmetov z vrednostmi v1 , v2 , . . . , vn . Zelimo
poiskati podmnoˇzico m <
n predmetov, ki ima najveˇcjo skupno vrednost. Dokaˇzite, da reˇsitev lahko poiˇsˇcemo s
poˇzreˇsno metodo. Napotek: posnemajte metodo iz razdelka 4.3.
4. Problem 0-1 nahrbtnika je definiran z n predmeti, ki imajo vrednost ci in prostornino
vi pri 1 ≤ i ≤ n, ter ˇstevilom V , naloga pa je poiskati n ˇstevil xi ∈ {0, 1}, 1 ≤ i ≤ n,
tako da je
Pn
xi vi ≤ V,
Pi=1
n
x
c
i=1 i i
pa doseˇze najveˇcjo vrednost. Ta problem bomo obravnavali kasneje. V primeru pa,
ko dovolimo, da ima eno ˇstevilo xk , 1 ≤ k ≤ n, poljubno vrednost v intervalu [0, 1]
govorimo o poenostavljenem problemu nahrbtnika. Slednji problem je moˇzno reˇsiti
s poˇzreˇsno metodo, tako da za poˇzreˇsni kriterij izberemo koliˇcino ci /vi (“specifiˇcno
vrednost”). Dokaˇzite pravilnost te metode. Uporabite podoben pristop, kot smo ga
izbrali pri razvrˇsˇcanju zapisov na magnetnem traku.
110
ˇ SNI
ˇ ALGORITMI
POGLAVJE 4. POZRE
Poglavje 5
PRETOKI IN LINEARNO
PROGRAMIRANJE
5.1
Uvod
V tem poglavju nadaljujemo z metodami za reˇsevanje optimizacijskih problemov.
V predhodnem smo prikazali probleme, ki jih je mogoˇce reˇsevati na najpreprostejˇsi
moˇzen naˇcin, sedaj pa nadaljujemo s takimi, ki zahtevajo nekoliko bolj premiˇsljen pristop. Pravzaprav se bomo ukvarjali s problemi, ki imajo neko posebno matematiˇcno
znaˇcilnost, ki omogoˇca uˇcinkovito reˇsevanje. Gre za probleme, ki spadajo v podroˇcje
linearnega programiranja, oziroma za probleme, ki predstavljajo poenostavljeno obliko
problemov tega razreda.
5.2
Problem maksimalnega pretoka skozi omreˇ
zje
Poenostavljena oblika problema linearnega programiranja, ki jo bomo predstavili na zaˇcetku, je problem
maksimalnega pretoka skozi omreˇzje.
5.2.1
2
2
3
Definicija problema
4
3
1
1
1 6
Podan je graf z vozliˇsˇci 1, 2, . . . , n, vsaki povezavi hi, ji
1
pa je prirejeno nenegativno ˇstevilo cij , ki mu pravimo
2
2
ˇ si povezave predstakapaciteta (gl. sliko 5.1). Ce
5
3
2
vljamo kot cevi, po katerih se pretaka neka tekoˇcina,
je kapaciteta najveˇcja koliˇcina tekoˇcine, ki lahko v
Slika 5.1: Graf s kapacitetami
enoti ˇcasa preteˇce po povezavi v stabilnih razmerah.
povezav
Z drugimi besedami, kapaciteta je najveˇcji pretok po
povezavi. Smer pretoka je v smeri povezave, torej od i do j.
111
112
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
Sedaj opiˇsemo problem maksimalnega pretoka od nekega vhodnega vozliˇsˇca, ki mu
pravimo izvor , do nekega izhodnega vozliˇsˇca, ki mu pravimo ponor (denimo, da sta
to vozliˇsˇci 1 in n, po vrsti). Naj xij predstavlja pretok skozi povezavo hi, ji. Tedaj
oˇcitno velja,
0 ≤ xij ≤ cij .
(5.1)
Poleg tega pogoja velja pri vseh vozliˇsˇcih, razen izvora in ponora, ˇse zakon o ohranjanju pretoka. Z drugimi besedami, kar priteˇce v neko vozliˇsˇce i, mora iz njega tudi
izteˇci:
X
X
xji =
xij .
(5.2)
j
j
ˇ upoˇstevamo ˇse izvor in ponor, dobimo relacijo,
Ce

 −v, i = 1
X
X
0, i =
6 1, n
xji −
xij =

j
j
v, i = n.
(5.3)
ˇ je x = (xij ) nabor vrednosti, ki zadoˇsˇcajo pogojema (5.1) in (5.3) in ˇce je v(x)
Ce
koliˇcina na desni strani 5.3, pravimo, da je v celotni pretok med izvorom in ponorom.
Ko ne bo nevarnosti za nesporazum, bomo z besedo pretok poimenovali tudi nabor
ˇ ima v najveˇcjo vrednost med vsemi nabori, ki izpolnjujejo zapisane pogoje, je
x. Ce
v maksimalen pretok. V tem razdelku bomo spoznali nekaj lastnosti maksimalnega
pretoka, ki nam omogoˇcajo, da ga na uˇcinkovit naˇcin izraˇcunamo.
Naj bo P neusmerjena pot od izvora do ponora, kar pomeni, da lahko vsebuje
tako povezave, ki so usmerjene od izvora do ponora, kakor tudi take, ki so nasprotno
usmerjene. Na primer, na sliki 5.1 je primer take poti 1–2–4–5–6 in na njej so povezave
prve vrste 1–2, 2–4 in 5–6, povezava 4–5 pa je druge vrste. Na kratko bomo rekli
povezavi hi, ji prve vrste (torej, ko je usmerjena od i proti j), da je pozitivna, povezavi
ˇ so podani pretoki po vseh povezavah x = (xij ), ki
druge vrste pa, da je negativna. Ce
zadoˇsˇcajo pogojema (5.1) in (5.3) in neka pot P od izvora do ponora, pravimo, da je
P zasiˇcena v primeru, ko bodisi za neko pozitivno povezavo na poti velja, xij = cij ,
bodisi za neko negativno povezavo, xij = 0. Na primer na sliki 5.2 predstavlja slika
5.2b zasiˇceno pot, 5.2c pa nezasiˇceno pot. Lahko bi tudi rekli, da je neka pozitivna
povezava hi, ji zasiˇcena, ko velja xij = cij , negativna pa, ko velja xij = 0. V tem
primeru lahko opiˇsemo zasiˇceno pot kot tako, na kateri je vsaj ena povezava zasiˇcena.
Na sliki 5.2a je prikazan nek moˇzen pretok skozi graf. Prvo ˇstevilo ob povezavi
hi, ji predstavlja njeno kapaciteto cij , drugo pa pretok xij . Ni se teˇzko prepriˇcati, da
koliˇcine xij zadoˇsˇcajo pogojema (5.1) in (5.3) in da je celoten pretok med izvorom in
ponorom enak 3.
Na sliki 5.2c je prikazana nezasiˇcena pot od izvora do ponora pri pretoku na sliki
5.2a. Pretok po prikazani poti lahko poveˇcamo za eno enoto tako, da ga v vsaki pozitivni povezavi poveˇcamo za eno enoto in zmanjˇsamo prav za toliko v vsaki negativni
povezavi. Kot posledico dobimo poveˇcan pretok z vrednostjo 4, ki je prikazan na sl.
5.2d. Ni se teˇzko prepriˇcati, da tudi spremenjeni pretok zadoˇsˇca pogojema (5.1) in
(5.3).
ˇ
5.2. PROBLEM MAKSIMALNEGA PRETOKA SKOZI OMREZJE
2
2,1
4
3,1
3,2
1,0
1
1,1 6
1,0
2,2
3
2,2
2
3,2
1,0
1
2,1
6
1,0
5
3
(b) Zasiˇ
cena pot
2
4
2,2
4
3,2
3,1
1
4
2
3,1
(a) Zaˇ
cetni pretok
2,1
113
1,1 6
2,1
1
1,0 6
1,0
2,2
3
5
(c) Nezasiˇ
cena pot
3,2
1,0
2,2
2,2
5
(d) Poveˇ
can pretok
Slika 5.2: Postopek veˇcanja nekega zaˇcetnega pretoka. Pri povezavah pomeni prvo
ˇstevilo kapaciteto, drugo pa vrednost pretoka
Sedaj definirajmo pojem prereza med izvorom in ponorom. To je par kompleˇ hoˇcemo
mentarnih podmnoˇzic vozliˇsˇc hS, T i, pri ˇcemer velja 1 ∈ S ter n ∈ T . Ce
poudariti izvor in ponor, zapiˇsemo, da je hS, T i (1, n)-prerez. Kapaciteto prereza
hS, T i definiramo kot
X
c(S, T ) =
cij ,
(5.4)
i∈S,j∈T
torej je to vsota kapacitet vseh povezav med S in T , ki so usmerjene od S proti T .
Vrednost poljubnega (celotnega) pretoka med izvorom in ponorom ima neko lastnost, ki je sicer precej oˇcitna, a jo bomo opisali s posebnim izrekom:
5.1 Izrek (o zgornji meji za vrednost pretoka) G = hV, Ei naj bo graf z uteˇzenimi
ˇ
povezavami, pri ˇcemer uteˇzi predstavljajo kapacitete. Naj bo 1 izvor, n pa ponor. Ce
je x = (xij ) nabor pretokov po povezavah, ki zadoˇsˇca pogojema (5.1) in (5.3), v pa
vrednost celotnega pretoka med izvorom in ponorom, velja
v ≤ c(S, T ),
(5.5)
kjer je c(S, T ) kapaciteta poljubnega (1, n)-prereza hS, T i.
Dokaz. Izrek dokaˇzemo tako, da seˇstejemo vse enaˇcbe (5.3), ki so prirejene vozliˇsˇcem
114
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
i ∈ S. V tem primeru dobimo,
P
P
P
v =
( j xij − j xji )
Pi∈S
P
=
(x − xji ) + i∈S,j∈T (xij − xji )
Pi,j∈S ij
=
i∈S,j∈T (xij − xji ).
(5.6)
Vrednost desne strani tretje vrstice (5.6) je enaka vrednosti desne strani druge vrstice
zato, ker je prvi ˇclen druge vrstice enak 0. Namreˇc, v tem ˇclenu se vsaka koliˇcina xij ,
pri i, j ∈ S, pojavlja dvakrat, enkrat s pozitivnim predznakom, drugiˇc z negativnim
(pozitivni predznak se pojavi pri ciljnem vozliˇsˇcu povezave hi, ji, negativni pa pri
izhodiˇsˇcnem vozliˇsˇcu). Tretja vrstica torej pravi, da je vrednost v celotnega pretoka
enaka razliki vsot vseh pretokov skozi povezave, ki vodijo iz S v T in onih, ki so
nasprotno usmerjene1 . Ker pa velja xij ≤ cij ter xji ≥ 0, imamo,
X
v≤
cij = c(S, T ).
(5.7)
i∈S,j∈T
Torej celotni pretok od izvora do ponora ne presega kapacitete poljubnega prereza
(med izvorom in ponorom). 2
Pravkar zapisani izrek 5.1 ima preprosto, a pomembno posledico:
5.2 Posledica Naj bodo definicije iste kot v zapisu izreka 5.1. V primeru, ko pri
(5.5) velja enakost, je pretok v maksimalen.
Na primer v primeru poveˇcanega pretoka na sl. 5.2d dejansko obstaja (1,6)-prerez s
kapaciteto, ki je enaka vrednosti pretoka. Primer takega prereza je h{1, 2}, {3, 4, 5, 6}i.
Posledica 5.2 tedaj zagotavlja, da je pretok na sliki 5.2d maksimalen.
Sedaj bomo zapisali in dokazali tri osnovne izreke o pretokih, ki jih bomo kasneje
uporabili pri sestavljanju algoritma za izraˇcun maksimalnega pretoka.
5.3 Izrek (o zasiˇ
cenih poteh) Nek pretok je maksimalen natanko tedaj, ko so vse
poti od izvora do ponora zasiˇcene.
Dokaz. V primeru, ko obstaja nezasiˇcena pot od izvora do ponora, pretok oˇcitno ni
maksimalen, ker lahko pretok po njej poveˇcamo tako, kot smo to storili v primeru
na sliki 5.2a. Po drugi strani pa naj bo x nek pretok, ki ima vse poti zasiˇcene. Naj
bo S mnoˇzica vozliˇsˇc, ki vsebuje izvor ter vozliˇsˇca, do katerih pelje nezasiˇcena pot iz
izvora, T pa naj bo komplementarna mnoˇzica. Na podlagi definicije nezasiˇcene poti
sklepamo, da pri vseh i ∈ S in j ∈ T velja xij = cij ter xji = 0 (ker bi v nasprotnem
primeru tudi j pripadalo mnoˇzici S). Iz tega izpeljemo vrednost pretoka
X
v=
cij ,
i∈S,j∈T
1 Naˇ
celoma je moˇ
zno, da sta med i in j dve, nasprotno usmerjeni povezavi, sicer pa je tista
vrednost xij oziroma xji , ki ustreza neobstojeˇ
ci povezavi, enaka 0.
ˇ
5.2. PROBLEM MAKSIMALNEGA PRETOKA SKOZI OMREZJE
115
kar predstavlja kapaciteto prereza hS, T i. Na podlagi posledice 5.2 sklepamo, da je
pretok maksimalen. 2
Pomen izreka je, da nam ponuja kriterij za presojo, kdaj smo dosegli maksimalen
pretok.
5.4 Izrek (o celoˇ
stevilˇ
cnosti maksimalnega pretoka) V primeru, ko so vse kapacitete cela ˇstevila, obstaja tudi celoˇstevilˇcen maksimalen pretok.
Dokaz. Naj bodo vse kapacite celoˇstevilˇcne in naj bo zaˇcetni pretok x0 . V primeru,
ko v(x0 ) ni maksimalen, obstaja nezasiˇcena pot, kar ima za posledico eksistenco
ˇ v(x1 ) ˇse vedno ni maksiceloˇstevilˇcnega pretoka x1 , tako da velja v(x1 ) > v(x0 ). Ce
malen, imamo zopet nezasiˇceno pot itn. Glede na to, da je vrednost vsakega pretoka
najmanj za ena veˇcja od vrednosti predhodnega, na koncu pridemo do celoˇstevilˇcnega
pretoka, ki ima vse poti zasiˇcene in je torej maksimalen. 2
Pomen pravkar zapisanega izreka je v tem, da zagotavlja, da lahko pridemo do
reˇsitve v konˇcnem ˇstevilu korakov, pri ˇcemer je en korak sestavljen iz iskanja nezasiˇcene poti ter njenega zasiˇcenja.
5.5 Izrek (o max pretoku pri min prerezu) Vrednost maksimalnega pretoka je
enaka minimalni kapaciteti nekega (1, n)-prereza.
Dokaz. V primeru, ko je pretok enak minimalni kapaciteti nekega prereza, je gotovo
maksimalen na podlagi posledice 5.2. Ko pa imamo opravka z maksimalnim pretokom, lahko tako kot v dokazu izreka 5.3 poiˇsˇcemo prerez s kapaciteto, ki je enaka
pretoku. Ta prerez pa ima oˇcitno minimalno kapaciteto, ker je pretok manjˇsi ali enak
od kapacitet vseh prerezov. 2
Zapisani izrek ni toliko pomemben za praktiˇcno raˇcunanje kot za teoretiˇcno razlago
problema, ker ga uvrˇsˇca v druˇzino problemov, pri katerih poznamo podobne, tim.
izreke vrste min-max. V naˇsem primeru ga preprosto predstavljamo kot zanimivost.
5.2.2
Algoritem za maksimalni pretok
ˇ
Ceprav
je moˇzno algoritem za maksimalni pretok realizirati tako, da na vsakem koraku
poiˇsˇce najveˇcji moˇzen prirastek pritoka, se bomo v tem delu zadovoljili z algoritmom,
ki nima te lastnosti.
Algoritem je prikazan na sliki 5.3. V postopku vozliˇsˇca opremimo z oznakami,
ki imajo (pri vozliˇsˇcu j) obliko (i+ , δj ) ali (i− , δj ). (i+ , δj ) pomeni, da obstaja nezasiˇcena pot od izvora do vozliˇsˇca j, po kateri lahko pretok poveˇcamo za prirastek δj
in je (pozitivna) povezava hi, ji zadnja na tej poti. (i− , δj ) pa pomeni, da je zadnja
povezava na poti od izvora do vozliˇsˇca j povezava hj, ii (in je torej negativna). Na
zaˇcetku je le izvor (vozliˇsˇce 1) oznaˇcen s posebno oznako (−, ∞), ki se med celotnim
postopkom ne spreminja, nato oznaˇcujemo ostala vozliˇsˇca na en izmed dveh naˇcinov:
116
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
Vhod:
Seznam kapacitet cij povezav grafa G = hV, Ei, pri ˇ
cemer je V = {1, 2, . . . , n}.
Privzetek je, da je vozliˇsˇ
ce 1 izvor, vozliˇsˇ
ce n pa ponor ter da so vse kapacitete
celoˇstevilˇ
cne.
Izhod:
Maksimalna vrednost celotnega pretoka od izvora do ponora ter vrednosti pretokov
xij po posameznih povezavah, pri 1 ≤ i, j ≤ n, i 6= j
Postopek:
1. (Zaˇ
cetek) Zaˇ
cnemo z nekim moˇ
znim celoˇstevilˇ
cnim pretokom x, v skrajnem
primeru takim, pri katerem so pretoki skozi vse povezave enaki niˇ
c. Viru
(vozliˇsˇ
cu 1) priredimo stalno oznako (−, ∞), ostala vozliˇsˇ
ca nimajo oznak.
2. (Oznaˇ
cevanje in obiskovanje)
(a) Poiˇsˇ
cemo neko oznaˇ
ceno, a neobiskano vozliˇsˇ
ce i; ˇ
ce takega vozliˇsˇ
ca ni,
nadaljujemo s korakom 4;
(b) Pri vsaki povezavi hi, ji, za katero velja xij < cij in je j neoznaˇ
ceno,
priredimo vozliˇsˇ
cu j oznako (i+ , δj ), tako da je
δj = min{δi , cij − xij }.
Pri vsaki povezavi hj, ii, pri kateri velja xij > 0 in je j neoznaˇ
ceno,
priredimo vozliˇsˇ
cu j oznako (i− , δj ), tako da je
δj = min{δi , xji }.
(c) V primeru, ko je ponor (vozliˇsˇ
ce n) oznaˇ
cen, nadaljujemo s korakom 3,
sicer ponovimo korak 2 ;
3. (Veˇ
canje pretoka) Nezasiˇ
ceno pot odkrijemo tako, da zaˇ
cnemo pri ponoru in
uporabljamo prve komponente oznak. Na primer, prva komponenta oznake
pri ponoru nam odkrije predzadnje vozliˇsˇ
ce na poti, prva komponenta oznake
le-tega nam odkrije predpredzadnje vozliˇsˇ
ce itn. Pretok poveˇ
camo tako, da
poveˇ
camo ali zmanjˇsamo pretok skozi povezave na nezasiˇ
ceni poti, odvisno od
znaka prve komponente oznake. Nadaljevanje pri koraku 2.
4. (Doloˇ
canje prereza z minimalno kapaciteto) V tem primeru je trenutni pretok
maksimalen. Prerez z minimalno kapaciteto hS, T i dobimo tako, da postavimo
vsa oznaˇ
cena vozliˇsˇ
ca v S, neoznaˇ
cena pa v T . S tem smo izraˇ
cun zakljuˇ
cili.
Slika 5.3: Algoritem za maksimalni pretok
5.3. LINEARNO PROGRAMIRANJE
117
ˇ je vozliˇsˇce i oznaˇceno in obstaja povezava hi, ji, kjer velja xij < cij , lahko
Ce
nezaznamovano vozliˇsˇce j opremimo z oznako (i+ , δj ), pri ˇcemer je
δj = min{δi , cij − xij }.
ˇ je vozliˇsˇce i oznaˇceno in obstaja povezava hj, ii, kjer velja xji > 0, lahko
Ce
nezaznamovano vozliˇsˇce j opremimo z oznako (i− , δj ), pri ˇcemer je
δj = min{δi , xji }.
V primeru, ko procedura zaznamuje ponor n, smo odkrili nezasiˇceno pot in je
ˇ se procedura ustavi, ne da bi oznaˇcila
moˇzno vrednost pretoka poveˇcati za δn . Ce
ponor, so vse poti zasiˇcene. V tem primeru je moˇzno dobiti prerez z minimalno
kapaciteto hS, T i tako, da v S postavimo vsa vozliˇsˇca, ki so oznaˇcena, v T pa ostala
vozliˇsˇca.
Zaznamovano vozliˇsˇce je bodisi “obiskano” ali “neobiskano”. Vozliˇsˇce obiˇsˇcemo
tako, da preiˇsˇcemo vse povezave, ki izhajajo iz vozliˇsˇca ali prihajajo vanj in opremimo
vozliˇsˇca, ki se dotikajo teh povezav, z oznakami v primeru, ko je to mogoˇce in ko oznak
ˇse nimajo.
Pri algoritmu moramo najprej dokazati njegovo pravilnost, ki je podana s pogojem, da kadar se algoritem ustavi po koraku 4, je vrednost pretoka v maksimalna.
Dejansko: ko pridemo do koraka 4 po koraku 2a, ponor ni oznaˇcen in predstavlja
mnoˇzica oznaˇcenih vozliˇsˇc (ter ustrezna komplementarna mnoˇzica) prerez, iz katerega
vodijo same zasiˇcene povezave (kajti ˇce neka povezava ne bi bila zasiˇcena, bi se postopek oznaˇcevanja nadaljeval). Torej je v tem primeru celotni pretok enak kapaciteti
tega prereza in nam posledica 5.2 zagotavlja, da je pretok maksimalen.
Potrebno ˇstevilo operacij algoritma lahko ocenimo takole: naj bo m ˇstevilo povezav. Vsega skupaj moramo pri vsakem iskanju nezasiˇcene poti 2m-krat pregledati
povezave ter nato morebiti ˇse opraviti oznaˇcevanje2 . V primeru, ko so vse kapacitete celoˇstevilˇcne, moramo ponoviti iskanje nezasiˇcene poti najveˇc v-krat, kjer je v
vrednost maksimalnega pretoka. Torej je ˇstevilo operacij O(mv).
5.3
5.3.1
Linearno programiranje
Uvod
Pri problemu maksimalnega pretoka skozi graf smo omenili, da je le poseben primer
ˇsirˇsega razreda problemov, ki jim pravimo problemi linearnega programiranja. Slednji
razred problemov je izredno pomemben iz dveh razlogov: prviˇc, mnogi praktiˇcni
problemi se dajo prevesti na obliko linearnega programiranja in drugiˇc, za ta razred
problemov poznamo uˇcinkovit algoritem. V tem delu se bomo seznanili z nekaterimi
osnovnimi pojmi ter v osnovnih obrisih spoznali simpleksni algoritem. Izhajamo iz ndimenzionalnega vektorskega prostora nad obsegom K, za katerega pa ne privzemamo
2 V najslabˇ
sem primeru je potrebno vsako povezavo obravnavati dvakrat: enkrat ob obisku njenega
izvora, drugiˇ
c pa ob obisku njenega ponora.
118
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
kakih posebnih lastnosti (kot smo to storili, na primer, v razdelku 3.3 o diskretni
Fourierjevi transformaciji). Prostor bomo oznaˇcevali z Vn . Torej so njegovi elementi
n-terke x elementov K.
Problem linearnega programiranja opiˇsemo z m × n matriko A, s stolpˇcnim vektorjem b dolˇzine m ter vrstiˇcnim vektorjem c dolˇzine n, naloga pa je poiskati x ∈ Vn ,
z lastnostma A · x ≤ b in c · x je maksimalno. A · x predstavlja produkt matrike A in
stolpˇcnega vektorja x, c · x pa skalarni produkt c in x(3 ). Funkciji f = c · x pravimo
tudi ciljna funkcija problema.
Linearno programiranje obravnava zelo obseˇzna literatura. Naj omenimo le dve
deli: Vidav [15, 2. poglavje, str. 135] in Kemeny [7, 7. poglavje, str. 314]. Priˇcujoˇci
sestavek se ne drˇzi strogo nobenega od citiranih del, predvsem pa se ne dotikamo
ˇstevilnih vpraˇsanj, ki so pomembna za praktiˇcno uporabo linearnega programiranja. Na primer, ne omenjamo zveze med osnovnim in dualnim problemom in se ne
spuˇsˇcamo v primer, ko problem degenerira.
5.6 Primer Primerov problemov linearnega programiranja je brez ˇstevila, tipiˇcen pa
je naslednji: imamo n izdelkov, vsak izmed katerih zahteva na enoto izdelka doloˇceno
koliˇcino vsake od m surovin, prinaˇsa pa tudi na enoto izdelka doloˇcen dobiˇcek. Vsaka
surovina je na razpolago v omejeni koliˇcini, postavlja pa se vpraˇsanje, koliko kosov
vsakega izdelka izdelati, da bo dobiˇcek najveˇcji. Na primer, neki izdelovalec kartonskih
ˇskatel izdeluje dve vrsti ˇskatel, majhne in velike. Vsaka majhna ˇskatla porabi 0.5m2
kartona in prinaˇsa 1 SIT dobiˇcka, vsaka velika ˇskatla pa porabi 0.75m2 kartona in
ˇ je na razpolago 100m2 kartona, koliko ˇskatel vsake vrste
prinaˇsa 2 SIT dobiˇcka. Ce
naj izdela, da bo dobiˇcek ˇcim veˇcji? Uporabljamo tudi privzeti pogoj, da je koliˇcina
obeh vrst ˇskatel nenegativna. Koliˇcino majhnih in velikih ˇskatel oznaˇcujemo z x1 in
x2 , po vrsti. Torej lahko zapiˇsemo:
−x1
0.5x1
−x2
+0.75x2
≤
0
≤
0
≤ 100,
(5.8)
pri ˇcemer mora biti
x1 + 2x2
(5.9)
maksimalno. V matriˇcnem zapisu lahko zapiˇsemo problem takole:
#
"
#
"
0
−1
0
0
0.5
−1
0.75
·x≤
0
100
,
1
2
· x maksimalno.
(5.10)
V nadaljnjem besedilu bomo obravnavali naslednja vpraˇsanja: prviˇc, kakˇsna je
mnoˇzica toˇck x prostora Vn , ki izpolnjujejo pogoj Ax ≤ b, drugiˇc, kako opiˇsemo tiste
tudi soroden problem, ki zahteva, da poiˇsˇ
cemo v ∈ Vn∗ tako, da velja vA ≥ c in je b · v
∗
minimalno, pri ˇ
cemer je Vn dualen vektorski prostor, v in c sta vrstiˇ
cna vektorja, b pa je stolpˇ
cni
vektor. Vendar se v tem sestavku ne bomo spuˇsˇ
cali do takih podrobnosti, ker presegajo zastavljeni
okvir.
3 Obstaja
5.3. LINEARNO PROGRAMIRANJE
119
toˇcke mnoˇzice, kjer funkcija c · x doseˇze maksimum in tretjiˇc, kako te toˇcke uˇcinkovito
poiˇsˇcemo.
5.3.2
Konveksne poliedrske mnoˇ
zice
Naj bo a vrstiˇcni vektor dolˇzine n, b pa naj pripada K (torej je konstanta). Tedaj
pravimo mnoˇzici toˇck x prostora Vn , ki izpolnjujejo pogoj a · x = b, hiperravnina
prostora Vn . Pri n = 2 je hiperravnina premica, pri n = 3 je ravnina, itn. Mnoˇzici
toˇck x prostora Vn , ki izpolnjujejo pogoj a · x ≤ b, pravimo zaprt polprostor Vn (odprt
polprostor je doloˇcen s pogojem a · x < b), hiperravnini a · x = b pa pravimo mejna
hiperravnina zaprtega polprostora a · x ≤ b.
5.7 Primer Oglejmo si (5.8) iz primera 5.6. Prva relacija ustreza zaprtemu polprostoru, ki vsebuje ordinatno os in vse, kar je desno od nje, druga relacija ustreza
zaprtemu polprostoru, ki vsebuje abscisno os in vse, kar je nad njo, tretja pa ustreza
zaprtemu polprostoru, ki vsebuje premico 0.5x1 + 0.75x2 = 100 in vse, kar je pod njo.
Na podlagi dosedanjih definicij lahko takoj zapiˇsemo:
5.8 Trditev Mnoˇzica toˇck x prostora Vn , ki izpolnjujejo pogoj Ax ≤ b, kjer je A
neka m × n matrika, b pa je stolpˇcni vektor dolˇzine m, je presek najveˇc m zaprtih
polprostorov.
V treh dimenzijah pravimo telesu, ki je omejeno z ravninami, polieder in zato
mnoˇzici toˇck iz trditve 5.8 pravimo poliederska mnoˇzica tudi, kadar je n 6= 3.
Mnoˇzica toˇck x prostora Vn , ki izpolnjujejo pogoj Ax ≤ b ima naslednjo pomembno lastnost:
5.9 Trditev Naj velja Ax1 ≤ b in Ax2 ≤ b. Tedaj velja tudi,
A((1 − λ)x1 + λx2 ) ≤ b,
pri vseh vrednostih 0 ≤ λ ≤ 1.
Za dokaz gl. vajo 7. Sedaj se spomnimo, da je premica, ki vsebuje x1 in x2 ,
mnoˇzica toˇck, ki so odvisne od parametra λ in jih opisuje enaˇcba,
x = x1 + λ(x2 − x1 ), pri − ∞ < λ < +∞.
(5.11)
Torej leˇzijo toˇcke (1 − λ)x1 + λx2 , pri 0 ≤ λ ≤ 1, na daljici med x1 in x2 in trditev
5.9 pravi, ˇce dve toˇcki izpolnjujeta pogoj Ax ≤ b, ga izpolnjujejo tudi vse toˇcke
na daljici med njima. Za mnoˇzico, kjer velja ta lastnost, pravimo, da je konveksna.
Sedaj je tudi oˇcitno, zakaj mnoˇzicam toˇck x, ki izpolnjujejo neki pogoj Ax ≤ b,
pravimo konveksne poliederske mnoˇzice, oziroma s kratico KPM. (Vpraˇsanje: v ravnini
predstavite poliedersko mnoˇzico, ki NI konveksna.)
120
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
toˇ
cke,ki izpolnjujejo pogoj
x2
−x1
200
0.5x1
100
100 200
−x2
+0.75x2
≤
≤
≤
0
0
100
x1
Slika 5.4: Konveksna poliedrska mnoˇzica
5.10 Primer V primerih 5.6 in 5.7 je KPM, ki izpolnjuje pogoj Ax ≤ b, notranjost
trikotnika, ki je omejen z abscisno in ordinatno osema in premico 0.5x1 +0.75x2 = 100
(gl. sliko 5.4). V zvezi s tem primerom je morda koristno poudariti, da je vˇcasih KPM,
ki izpolnjuje pogoj Ax ≤ b, prazna. Na primer v primeru, ki ga obravnavamo, ˇce bi
dodali ˇse pogoj +x1 + x2 ≤ −1, bi bila ustrezna KPM prazna.
Na tem mestu je koristno vpeljati ˇse neko dodatno znaˇcilnost konveksnih poliedrskih mnoˇzic. Razlikovali bomo med omejeno KPM in neomejeno KPM. Seveda je
neomejena KPM taka, ki je “neskonˇcna”, vendar, kako to povedati na primeren naˇcin?
Najlaˇze to povemo tako, da istovetimo neomejene KPM s takimi KPM, ki vsebujejo
nek poltrak. Na primer v primeru 5.7, ˇce odpravimo omejitev 0.5x1 + 0.75x2 = 100,
dobimo KPM, ki vsebuje (na primer) poltrak, ki se zaˇcenja pri izhodiˇsˇcu in ima pozitivni kot 45◦ .
Pravkar smo videli, kako je videti neka konveksna poliedrska mnoˇzica v dveh dimenzijah. V treh dimenzijah je to “izboˇcen” polieder. V prostorih, ki imajo dimenzijo
veˇc kot tri, pa si takih mnoˇzic veˇc ne znamo predstavljati, ˇceprav seveda matematiˇcno
eksistirajo. Pri n = 2 smo ugotovili, da so mejne hiperravnine pravzaprav premice
in v tem primeru pravimo toˇckam, ki pripadajo po dvema mejnima hiperravninama
hkrati, obenem pa pripadajo tudi KPM, ekstremne toˇcke. Drugi pogoj (pripadnost
KPM) je pomemben, ker ni nujno, da se dve mejni hiperravnini vedno sekata v toˇcki,
ki pripada KPM. Na primer, v primeru 5.7 so ekstremne toˇcke (0, 0), (0, 132.3) in
(200, 0). V sploˇsnem primeru je ekstremna toˇcka neke KPM tista toˇcka x, ki izpolnjuje pogoja, prviˇc Bx = bB , kjer je B neka n × n podmatrika matrike A, bB pa
je ustrezni podvektor vektorja b in, drugiˇc, Ax ≤ b. V primeru 5.7 ekstremne toˇcke
(0, 0), (0, 132.3) in (200, 0) ustrezajo naslednjim podmatrikam B in podvektorjem bB
(po vrsti):
h
i
h i
h
i
h
i
h
−1
0
0 −1
0
−1
0.5 0.75
x=
i
x=
0
h 0
0
100
;
i
−1
0.5
0
0.75
x=
0
100
;
(5.12)
V primeru neomejene KPM dodamo h seznamu ekstremnih toˇck ˇse “neskonˇcno toˇcko”
zato, da lahko doloˇcene trditve izrazimo bolj jedrnato.
ˇ vzamemo neko poljubno n × n podmatriko B matrike A, seveda ni nujno, da
Ce
ima sistem Bx = bB reˇsitev. Pogoj za obstoj reˇsitve je, da je matrika B nesingularna,
5.3. LINEARNO PROGRAMIRANJE
121
oziroma, da je njena determinanta, |B|, razliˇcna od niˇc. Lahko bi rekli, da je v primeru
|B| = 0 reˇsitev Bx = bB toˇcka v neskonˇcnosti. Zaradi enostavnosti se bomo v bodoˇce
omejili na primere, ko tak primer ne nastopi, torej odslej privzemamo, da je poljubna
n × n podmatrika matrike A nesingularna. Naslednji privzetek se nanaˇsa na velikost
matrike A. Odslej k matriki A vedno dodamo ˇse pogoje −xi ≤ 0, s ˇcimer se omejimo
ˇ
na pozitivni “kvadrant” prostora Vn (in obenem doseˇzemo, da je m ≥ n). Ceprav
se
ne bomo spuˇsˇcali v podrobnosti, naj pripomnimo, da nas slednji pogoj pravzaprav
ne omejuje preveˇc, saj lahko ponavadi s preprostimi transformacijami spremenimo
problem, kjer −xi ≤ 0 ne velja, v takega, kjer so ti pogoji izpolnjeni.
5.3.3
Maksimum linearne funkcije na konveksni poliedrski
mnoˇ
zici
Preden zaˇcnemo obravnavati vpraˇsanje iz naslova razdelka, zapiˇsimo neko oˇcitno lastnost konveksnih poliederskih mnoˇzic:
5.11 Trditev Naj bo K KPM prostora Vn z matriko A in vektorjem omejitev b in
naj bo
a = ha1 , a2 , . . . , an i
neka vrstica A, b pa ustrezna komponenta b. Tedaj je mnoˇzica toˇck, ki izpolnjujejo
pogoj a · x = b (namesto a · x ≤ b), neka KPM K0 prostora Vn−1 , ekstremne toˇcke K0
pa ustrezajo doloˇcenim ekstremnim toˇckam K.
Dokaz. Na podlagi relacije a · x = b izrazimo xn z xi pri 1 ≤ i ≤ n − 1. Na ta
naˇcin spremenimo relacijo Ax ≤ b v A0 x0 ≤ b0 , kjer A0 nima vrstice a · x = b, ostali
a −a
elementi postanejo a0ij = ijan j , omejitve pa b0i = bi − abni . Tako smo ˇze dokazali, da
toˇcke, ki zadoˇsˇcajo pogoju a · x = b, tvorijo KPM K0 prostora Vn−1 . Preslikavo med
ekstremnimi toˇckami K0 in ekstremnimi toˇckami K nato dobimo na podlagi ugotovitve,
da so ektremne toˇcke K0 doloˇcene z naborom n − 1 vrstic matrike A0 , vsak tak nabor
pa ustreza enemu samemu naboru n vrstic matrike A (ki doloˇca neko ekstremno toˇcke
K) tako, da na matriki A0 uporabimo nasprotno transformacijo od tiste, s katero smo
A spremenili v A0 , in dodamo vrstico a. 2
Naj bo podana neka KPM prostora Vn . Iˇsˇcemo toˇcko ali toˇcke, kjer funkcija
c · x doseˇze maksimum. Pravzaprav nas bo zanimala funkcija c · x + δ, kjer je δ
neka poljubna konstanta, vendar ˇclen δ ne igra bistvene vloge. Reˇsitev zastavljenega
problema daje naslednji izrek:
5.12 Izrek (o maksimumu ciljne funkcije na KPM) Naj bo dana neka neprazna KPM K, ki je doloˇcena z m × n matriko A in vektorjem omejitev b ter neka
poljubna linearna funkcija c · x + δ. c · x + δ doseˇze svoj maksimum v neki ekstremni
toˇcki K.
Dokaz. Dokaz bomo izpeljali z indukcijo po n. Pri n = 1 se vse neenaˇcbe prevedejo
na obliko ai1 x1 ≤ bi . Vsaka neenaˇcba ustreza nekemu poltraku, njihov presek, ˇce
122
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
je neprazen, pa je bodisi konˇcen zaprt interval ˇstevilˇcne preme x1 (torej mnoˇzica
vrednosti b1 ≤ x1 ≤ b2 ) ali nek poltrak (a1 x1 ≤ b1 ). Primer vidimo na sliki 5.5. V tem
primeru ima linearna funkcija obliko c1 x1 +δ in na ˇstevilˇcni premi je bodisi konstantna,
monotono naraˇsˇca ali pa pada. Torej svoj maksimum doseˇze v eni ekstremni toˇcki (ki
je lahko tudi neskonˇcna).
−x ≤ −3
x≤7
−x ≤ −3 ∧ x ≤ 7
Pri n > 1 bomo dokazali, da eksistira neka ekstremna toˇcka x ∈ K, za katero pri vseh toˇckah y ∈ K
velja c·x+δ ≥ c·y+δ. Privzeli bomo, da obstaja neka
toˇcka x1 ∈ K z lastnostjo Ax1 < b (vse komponente
ˇ
Ax1 so strogo manjˇse od ustreznih komponent b). Ce
take toˇcke ni, velja vsaj za eno omejitev a·x1 = b (a je
neka vrstica A) in lahko eno komponento x1 izrazimo
z drugimi ter primer prevedemo na niˇzjo dimenzijo,
za katero smo izrek ˇze dokazali. Torej velja Ax1 < b.
Sedaj izberemo poljubno premico, ki vsebuje toˇcko
x1 . Presek premice in K je KPM K0 dimenzije 1 (gl.
Slika 5.5: Presek dveh konve- nalogo 9). Na K0 doseˇze c·x+δ svoj maksimum na eni
ksnih poliedrskih mnoˇzic di- od svojih dveh ekstremnih toˇck, npr. x2 (na podlagi
menzije ena
induktivne predpostavke). Ker pa x2 pripada vsaj
eni mejni hiperravnini KPM K, velja v toˇcki x2 tudi
ax2 = b vsaj za eno vrstico a matrike A. Iz trditve
5.11 sledi, da x2 pripada KPM K00 , ki ima manjˇso dimenzijo od K, ekstremne toˇcke K00
pa ustrezajo doloˇcenim ekstremnim toˇckam K. Sedaj ponovno uporabimo induktivno
predpostavko in lahko sklepamo, da eksistira neka ekstremna toˇcka x3 ∈ K, tako da
velja
c · x3 + δ ≥ c · x2 + δ ≥ c · x1 + δ.
Torej smo v vseh primerih dokazali, da toˇcki x1 ustreza neka ekstremna toˇcka x3 z
lastnostjo c · x3 + δ ≥ c · x1 + δ. 2
Na koncu
ˇse ugotovimo, da ima KPM K konˇcno mnogo ekstremnih toˇck, in sicer
m
najveˇc
.
n
Izrek 5.12 nam ˇze ponuja algoritem za probleme linearnega programiranja (z omejitvami, ki smo jih opisali na koncu razdelka 5.3.2): ˇce je podana KPM z m × n
matriko A, vektorjem omejitev b ter ciljno funkcijo c · x, preprosto poiˇsˇcemo vrednost ciljne funkcije v vseh ekstremnih toˇckah in izberemo tisto, v kateri je vrednost
najveˇcja. Vendar je ta algoritem razmeroma neuˇcinkovit, saj je obseg raˇcunanja za iskanje ekstremnih toˇck nesprejemljivo velik. V naslednjem razdelku se bomo ukvarjali
s vpraˇsanjem, kako lahko izraˇcun znatno pohitrimo.
123
5.3. LINEARNO PROGRAMIRANJE
5.3.4
Lokalni pogoj za globalni maksimum linearne funkcije na
konveksni poliedrski mnoˇ
zici
Naj bo K KPM prostora Vn z matriko A in vektorjem omejitev b in naj bo xB neka
ekstremna toˇcka mnoˇzice K. Kot ˇze vemo, je xB reˇsitev sistema linearnih enaˇcb
B · x = bB , kjer je B neka n × n podmatrika matrike A, bB pa vektor omejitev, ki
pripadajo vrsticam B. Ekstremna toˇcka xC je soseda toˇcke xB v primeru, ko je toˇcka
xC reˇsitev sistema C · x = bC , kjer novi sistem enaˇcb dobimo iz B · x = bB tako, da
zamenjamo eno samo enaˇcbo ax = b (z neko drugo enaˇcbo med enaˇcbami Ax = b).
Denimo na primer, da zamenjamo enaˇcbo a = b z a0 = b0 . Najprej si zastavimo
vpraˇsanje, kakˇsna je predstavitev premice, ki povezuje xB in xC ? Dobimo jo na
ˇ xB in xC zadoˇsˇcata pogojema
preprost naˇcin iz sploˇsne enaˇcbe premice (5.11). Ce
Bx = bB in Cx = bC po vrsti, zadoˇsˇcajo toˇcke na premici, ki povezuje ti dve toˇcki,
pogoj
[(1 − λ)B + λC] x = (1 − λ)bB + λbC .
Ker se B in C razlikujeta le v eni vrstici, bB in bC pa v ustrezni komponenti, se tudi
ˇ
pri (1 − λ)B + λC = (1 − λ)bB + λbC pojavlja parameter λ le v tisti vrstici. Ce
vrstici a pripadajo komponente ai , 1 ≤ i ≤ n (in podobno za a0 ), so torej elementi
(1 − λ)B + λC v vrstici, ki je odvisna od λ, (1 − λ)ai + λa0i , 1 ≤ i ≤ n. Podobno velja
za vektor omejitev (1 − λ)bB + λbC . Nato dokaˇzemo:
5.13 Trditev Vsaka ekstremna toˇcka KPM K prostora Vn z matriko A in vektorjem omejitev b ima najveˇc n sosedov. V kolikor je ˇstevilo sosedov n − k, ustreza k
manjkajoˇcih sosedov neskonˇcni ekstremni toˇcki.
Dokaz. Naj bo ekstremna toˇcka xB in naj velja BxB = bB . Ne da bi se omejili, lahko
privzamemo, da je matrika A enaka
B
A=
,
B0
vektor omejitev b pa
b=
bB
b0
.
Sedaj vpeljemo nove koordinate y na podlagi relacije x − xB = B −1 y in se nato
relacija,
Ax ≤ b,
spremeni v,
B
B0
(B
−1
bB
b0
0
b0 − B 0 xB
y + xB ) ≤
,
oziroma,
I
B 0 B −1
y≤
.
124
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
Z drugimi besedami, B smo transformirali v enotsko matriko, ekstremno toˇcko xB v
izhodiˇsˇce koordinatnega sistema, K pa premaknili v “negativni kvadrant” Vk . Sedaj
prehod od trenutne ekstremne toˇcke (ki ji pripada enotska n × n matrika) do sosednje
opravimo tako, da neko enaˇcbo yi = 0 zamenjamo z enaˇcbo, katere leva stran je ena
izmed vrstic B 0 B −1 y, desna pa ustrezna komponenta b0 − B 0 xB . Vendar, ker so vse
enaˇcbe yj = 0, j 6= i, ostale v veljavi, se spremenjena vrstica pretvori v ai yi = bi
in tako postane nova ekstremna toˇcka, yi = abii , yj = 0, j 6= i; torej se je daljica
med dvema ekstremnima toˇckama spremenila v eno izmed koordinatnih osi. Ker je
koordinatnih osi n, je seveda ˇstevilo ekstremnih toˇck ≤ n. Seveda lahko z razliˇcnimi
zamenjavami dobimo razliˇcne enaˇcbe yi = abii , vendar ekstremno toˇcko dobimo le v
primeru, ko toˇcka pripada K, to pa velja le za vrednost abii , ki leˇzi najbliˇzje izhodiˇsˇcu
novega koordinatnega sistema.
Lahko se tudi zgodi, da je ai = 0. V tem primeru pripada mnoˇzici K celotna
koordinatna os spremenljivke yi , in imamo opravka z neskonˇcno sosedno ekstremno
toˇcko. 2
Potem, ko smo uporabili opisano koordinatno transformacijo, je determinanta
podmatrike, ki doloˇca ekstremno toˇcko, produkt diagonalnih elementov podmatrike
(v primeru toˇcke xB smo transformiraliii B v I in je torej determinanta kar 1). Ko na
opisan naˇcin iz I dobimo C, je v primeru ai = 0 determinanta C enaka 0, z drugimi
besedami C je singularna. Torej ustrezajo neskonˇcnim sosednim ekstremnim toˇckam
singularne n × n podmatrike matrike A in ker smo privzeli, da takih ni, smo se tudi
obvarovali pred neskonˇcnimi ekstremnimi toˇckami.
Sedaj pa osnovni rezultat tega razdelka:
5.14 Izrek (o lokalnem pogoju za globalni maksimum) Naj bodo dani: neka
KPM K prostora Vn z matriko A in vektorjem omejitev b, neka linearna funkcija
f = c · x + δ ter neka n × n podmatrika B matrike A in ustrezna ekstremna toˇcka
ˇ je vrednost f v vseh
xB , ki predstavlja reˇsitev sistema linearnih enaˇcb B · x = bB . Ce
sosednih ekstremnih toˇckah manjˇsa ali enaka vrednosti f v toˇcki xB , potem f v xB
doseˇze svoj globalni maksimum na mnoˇzici K.
Dokaz. Izrek dokaˇzemo tako, da ponovno uporabimo koordinatno transformacijo, ki
smo jo uporabili v dokazu trditve 5.13. Po uporabi transformacije x − xB = B −1 y se
ciljna funkcija transformira v c(B −1 ·y +xB ) +δ. V trditvi 5.13 smo ugotovili, da ima
transformacija, ki jo uporabljamo, lastnosti (a) vse dovoljene vrednosti spremenljivk
yi , 1 ≤ i ≤ n, so nepozitivne in (b) do sosednih ekstremnih toˇck pridemo tako, da
ˇ sedaj velja pogoj iz izreka, da v nobeni
opravimo premik po neki koordinatni osi. Ce
sosednji ekstremni toˇcki vrednost ciljne funkcije ni veˇcja od vrednosti c · xB + δ, sledi,
da so vse komponente nove predstavitve koeficientov ciljne funkcije, c · B −1 nenegativne. V takem primeru pa tudi nobena linearna kombinacija dovoljenih vrednosti
spremenljivk (in vsaka toˇcka K ima tako lastnost) ne more dati veˇcje vrednosti ciljne
funkcije od c · xB + δ. 2
125
5.3. LINEARNO PROGRAMIRANJE
x1
+4
+1
+2
+1
x2
+1
+5
+3
+1
b
+5
+20
+8
0
y1
y2
y3
−f
Slika 5.6: Zaˇcetna simpleksna tabela.
Izrek 5.14 nas napeljuje na naslednji algoritem za reˇsitev problemov linearnega
programiranja: postavimo se v neko ekstremno toˇcko in ponavljamo zanko, v kateri se
vsakiˇc premaknemo do neke sosedne ekstremne toˇcke, kjer je vrednost ciljne funkcije
veˇcja; ˇce take ekstremne toˇcke ni, se ustavimo in smo na podlagi izreka 5.14 naˇsli
globalni maksimum ciljne funkcije.
5.3.5
Simpleksni algoritem
V tem razdelku bomo nekoliko bolj podrobno opisali algoritem, ki smo ga nakazali na
koncu prejˇsnjega razdelka. Pri opisu algoritma bomo uporabljali naslednji primer:
+4x1
+1x1
+2x1
+1x2
+5x2
+3x2
≤
5
≤ 20
≤ 8,
(5.13)
pri ˇcemer mora biti
x1 + x2
(5.14)
maksimalno. Pogojem (5.13) moramo seveda ˇse pripisati pogoj nenegativnosti vseh
spremenljivk. Uporabili bomo metodo, ki nekoliko spominja na dokaz izreka 5.14:
uporabili bomo nek koordinatni sistem, kjer prehod do sosedne ekstremne toˇcke
doseˇzemo s spremembo dveh koordinat (in ne ene kot v dokazu izreka 5.14), vendar ker bo ciljna funkcija odvisna le od ene izmed teh koordinat, bo zato takoj moˇzno
odkriti smer njenega spreminjanja. Natanˇcen opis postopka pa je naslednji: dodali
bomo m spremenljivk yi , pri 1 ≤ i ≤ m, in vsak pogoj ai · x ≤ bi spremenili v
ai · x + yi = bi , pri ˇcemer je bi komponenta b, ki ustreza vrstici ai matrike A. Na
ta naˇcin smo A podaljˇsali v desno z m × m enotsko matriko, vse neenakosti pa smo
spremenili v enakosti. Poleg pogojev, ki so izraˇzeni s spremenjeno matriko A, imamo
ˇse implicitne pogoje yi ≥ 0, 1 ≤ i ≤ m, in xj ≥ 0, 1 ≤ j ≤ n. Vsega skupaj imamo
torej n + m spremenljivk in n + 2m pogojev. Za zaˇcetno ekstremno toˇcko izberemo
toˇcko s komponentami yi = bi , pri 1 ≤ i ≤ m, in xj = 0, pri 1 ≤ j ≤ n. Tej ekstremni toˇcki ustreza m pogojev Ax + y = b ter n pogojev x = 0. Sedaj opiˇsemo
osnovni korak algoritma, s katerim poveˇcamo vrednost ciljne funkcije. V tem koraku
zamenjamo enega izmed opisanih pogojev z nekim pogojem yi = 0, 1 ≤ i ≤ m, ki
ni bil vsebovan v opisu trenutne ekstremne toˇcke. Z nekoliko premisleka ugotovimo,
da pogoj yi = 0 lahko nadomesti bodisi pogoj ai · x + yi = bi ali pa enega izmed
126
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
y1
x2
b
+ 14
− 14
− 24
+ 14
+ 19
4
+ 10
4
+ 54
x1
+ 75
4
+ 22
4
y2
− 14
+ 34
− 54
−f
y3
Slika 5.7: Prvi korak.
pogojev xj = 0, 1 ≤ j ≤ n. Prvi primer ni zanimiv zato, ker se pri nespremenjeni
vrednosti spremenljivk xj , 1 ≤ j ≤ n ciljna funkcija ne poveˇca. Torej moramo z yi = 0
nadomestiti enega izmed pogojev xj = 0, 1 ≤ j ≤ n. Izberemo tak pogoj xj = 0,
katerega odpravljanje zagotavlja veˇcanje ciljne funkcije. Pri roˇcnem izraˇcunu podatke
ponavadi uredimo v tabelo, ki je za primer (5.13) prikazana na sliki 5.6. Stolpci tabele
pripadajo vektorju omejitev ter spremenljivkam, ki trenutno imajo vrednost 0 in od
katerih je odvisna ciljna funkcija, vrstice pa spremenljivkam, ki so trenutno neniˇcelne
(od katerih pa ciljna funkcija ni odvisna). Prehod do sosedne ekstremne toˇcke z viˇsjo
vrednostjo funkcije f opravimo tako, da najprej izberemo neko spremenljivko x, ki ji
vrednost poveˇcamo, neki spremenljivki y 6= 0 pa priredimo vrednost 0 tako, da ostanejo vsi ostali pogoji izpolnjeni. Spremenljivko x izberemo na podlagi komponent
c (spodnje vrstice tabele): izberemo t´ako spremenljivko x, kateri ustreza pozitivna
vrednost v vrstici c, kar pomeni, da se pri veˇcanju te spremenljivke veˇca tudi vrednost
f . V naˇsem primeru izberemo x1 . x1 bomo toliko poveˇcali, da se bo neka vrednost y
ˇ se pri veˇcanju x1 tudi vse vrednosti y veˇcajo, to pomeni, da sosedna
spustila do 0. Ce
ektremna toˇcka ni konˇcna (v tabeli se to vidi po tem, da so v ustreznem stolpcu vse
vrednosti, razen one, ki pripada zadnji vrstici, negativne). V naˇsem primeru to ne
velja, saj so koeficienti v prvem stolpcu, ki pripada x1 , 4, 1, 2. Ko smo izbrali spremenljivko x1 , da jo bomo postavili v mnoˇzico neniˇcelnih spremenljivk, pogledamo,
katera spremenljivka yi se bo pri veˇcanju x1 prva spustila do 0. To se bo zgodilo z
y1 , pri vrednosti x1 = 45 . Sedaj bomo postavili y1 v zgornjo vrstico, x1 pa v desni
stolpec in obenem spremenili A z upoˇstevanjem novih razmer. Kakˇsne spremembe
so potrebne? Vrstici, ki ustreza y1 , moramo dati novo obliko, ko se x1 pojavlja s
koeficientom 1: to doseˇzemo preprosto tako, da celo vrstico delimo z elementom na
preseku stolpca x1 in vrstice y1 (temu elementu pravimo pivota ali, slovensko, opora).
Naslednja sprememba je, da moramo iz vseh vrstic, ki ustrezajo ostalim y spremenljivkam, izloˇciti spremenljivko x1 . To storimo tako, da od vsake vrstice odˇstejemo
novo vrednost v vrstici, ki ustreza x1 , pomnoˇzeno s starim elementom stolpca x1 (ki
pripada vrstici, ki jo spreminjamo). Enako storimo z zadnjo vrstico v tabeli, ki vsebuje komponente c. Nova tabela za naˇs primer je prikazana na sliki 5.7. V naslednjem
koraku je edina pozitivna komponenta c c2 (za prvo komponento ni presenetljivo, da
je manjˇsa od niˇc, saj ustreza poti, po kateri smo priˇsli v trenutno ekstremno toˇcko,
127
5.4. POVZETEK OSNOVNIH POJMOV
y1
y3
b
3
+ 10
7
+ 10
2
− 10
1
− 10
1
− 10
− 19
10
4
+ 10
3
− 10
7
+ 10
x1
+ 83
10
+ 22
10
− 29
10
y2
x2
−f
Slika 5.8: Drugi korak.
in to na podlagi kriterija veˇcanja ciljne funkcije). Na podlagi poskusov ugotovimo,
da se z veˇcanjem x2 prva spusti do niˇc spremenljivka y3 , kar pomeni, da bo prav ta
spremenljivka zamenjala x2 . Tabela, ki smo jo spremenili na podlagi istih pravil kot
prej, je prikazana na sliki 5.8.
Celotni simpleksni algoritem je prikazan na sliki 5.9.
5.4
Povzetek osnovnih pojmov
1. Problem maksimalnega pretoka skozi omreˇzje
2. Zakon o ohranjanju pretoka
3. Poti med izvorom in ponorom — pozitivne in negativne povezave
4. Zasiˇcene in nezasiˇcene povezave, oziroma poti
5. Izrek o zasiˇcenih poteh
6. Izrek o celoˇstevilˇcnosti maksimalnega pretoka
7. Izrek o maksimalnem pretoku pri minimalnem prerezu
8. Algoritem za maksimalni pretok
9. Problem linearnega programiranja in primeri
10. Ciljna funkcija
11. Hiperravnina v prostoru Vn
12. Zaprt polprostor v Vn
13. Mejna hiperravnina zaprtega polprostora
14. Konveksnost
15. Konveksna poliedrska mnoˇzica Vn (KPM)
16. Omejena, neomejena KPM
17. Ekstremna toˇcka KPM
18. Linearna funkcija doseˇze svoj maksimum na KPM v neki ekstremni toˇcki
19. Osnovni privzetek, ki ga uporabljamo v naˇsi obravnavi problema linearnega programiranja
128
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
Vhod:
m×n matrika A, vektor omejitev b dolˇ
zine m in linearna ciljna funkcija f = c·x+δ.
Izhod:
vrednosti spremenljivk xi , pri 1 ≤ i ≤ n, kjer f doseˇ
ze maksimum (ter velikost tega
maksimuma).
Postopek:
1. Sestavimo zaˇ
cetno simpleksno tabelo tako, da elemente A vpiˇsemo v vrstice
1 . . . m in stolpce 1 . . . n. V vrstico m + 1 zapiˇsemo komponente c, v stolpec
n + 1 pa komponente b. V element hm + 1, n + 1i zapiˇsemo vrednost −δ.
Stolpce poimenujemo x1 , x2 , . . . , xn , b, vrstice pa y1 , y2 , . . . , ym , −f .
2. Izberemo katerikoli stolpec xJ , ki mu ustreza pozitivna komponenta cJ in
ˇ takega stolpca ni, se ustavimo, ker smo globalni maksimum
nadaljujemo. Ce
f ˇ
ze dosegli in lahko vrednosti neniˇ
celnih spremenljivk odˇ
citamo iz stolpca
n + 1, negativno vrednost funkcije f pa iz elementa hm + 1, n + 1i.
3. Izberemo tisto vrstico yI , ki ima pozitiven aIJ in mu ustreza najmanjˇsa vreˇ so vse vrednosti aIJ negativne, to pomeni, da f nima konˇ
cne
dnost abI . Ce
IJ
maksimalne vrednosti in se ustavimo.
4. Vrstico yI spremenimo tako, da vse elemente, razen aIJ , delimo z aIJ , element
aIJ pa nadomestimo z a 1 .
IJ
5. Ostale vrstice yi spremenimo tako, da od vseh elementov aij , razen aiJ ,
a aiJ
odˇstejemo Ij
ter aiJ zamenjamo z − aaiJ .
a
IJ
IJ
6. Stolpec xJ preimenujemo v yI , vrstico yI pa v xJ in se vrnemo na korak 2.
Slika 5.9: Simpleksni algoritem
20. Sosedne ekstremne toˇcke in njihovo ˇstevilo
21. Lokalni pogoj za globalni maksimum linearne funkcije na KPM
22. Simpleksni algoritem.
5.5
Naloge
1. Poiˇsˇcite vse prereze z minimalno kapaciteto v grafu na sl. 5.1.
3mc35
3
Z
>
~ l
Z
5
2
1m- 2m
5
Z ? >
c24
~ m
Z
3
4
Slika 5.10: Graf iz naloge 2.
129
5.5. NALOGE
2. Za graf na sl. 5.10 izrazite vrednost maksimalnega pretoka kot funkcijo c24 in c35 .
3. Mnoˇzico S, ki jo sestavljajo vozliˇsˇca, do katerih vodi nezasiˇcena pot od izvora (vozliˇsˇca
1), lahko definiramo rekurzivno:
1 ∈ S,
i ∈ S, xij < cij ⇒ j ∈ S,
i ∈ S, xji > 0 ⇒ j ∈ S.
Podajte podobno rekurzivno definicijo mnoˇzice T , ki jo sestavljajo vozliˇsˇca, iz katerih
vodijo nezasiˇcene poti do ponora (vozliˇsˇca n).
4. Katera izmed naslednjih dveh trditev je resniˇcna?
ˇ je x maksimalen pretok, eksistirata i in j, tako da je bodisi xij = 0 ali xji = 0
(a) Ce
(b) Obstaja tak maksimalen pretok, pri katerem velja za nek i in j bodisi xij = 0
ali xji = 0.
Podajte utemeljitev svojega mnenja.
5. Kritiˇcno povezavo definiramo kot tisto povezavo, katere odstranitev najbolj zmanjˇsa
maksimalni pretok. Presodite, ali je naslednja trditev resniˇcna: kritiˇcna povezava je
povezava z maksimalno kapaciteto v prerezu minimalne kapacitete. Podajte utemeljitev svojega mnenja.
6. Dokaˇzite trditev 5.9.
7. V primeru 5.6 smo obravnavali primer problema linearnega programiranja. Spremenite
zapis problema (matriko A, vektor omejitev b in ciljno funkcijo c), tako da bo ustrezal
(a) istemu opisu z dodatno omejitvijo “ˇstevilo majhnih ˇskatel ni manjˇse od ˇstevila
velikih ˇskatel”. Nariˇsite geometrijsko predstavo spremenjenega problema.
(b) Poleg predhodne omejitve naj velja ˇse “ˇstevilo majhnih ˇskatel ne presega 20”.
Tudi za ta primer opiˇsite A, b in c ter nariˇsite geometrijsko predstavo.
8. Konveksno poliedrsko mnoˇzico (KPM) smo opisali kot mnoˇzico elementov x, ki zadoˇsˇcajo
pogoju Ax = b. Opiˇsite isto mnoˇzico potem, ko smo v prostoru Vn uporabili neko
koordinatno transformacijo.
9. Naj bosta K1 in K2 konveksni poliedrski mnoˇzici prostora Vn . Dokaˇzite, da je njun
presek KPM dimenzije, ki je enaka ali manjˇsa od dimenzij K1 in K2 . Napotek: dimenzijo Ki definiramo kot minimalno ˇstevilo r, tako da lahko z neko koordinatno
transformacijo predstavimo Ki v obliki A · x ≤ b, pri ˇcemer je A m × n matrika z r
neniˇcelnimi stolpci.
10. Problem linearnega programiranja smo opisali z m × n matriko A, (stolpˇcnim) vektorjem b ter (vrstiˇcnim) vektorjem c, potrebno pa je poiskati (stolpˇcni) vektor x tako,
da velja Ax ≤ b in c · x je maksimalno. Doloˇcite koliˇcine A, b in c pri problemu
maksimalnega pretoka.
130
POGLAVJE 5. PRETOKI IN LINEARNO PROGRAMIRANJE
Poglavje 6
ˇ
DINAMICNO
PROGRAMIRANJE IN
ˇ POTI
NAJCENEJSE
6.1
Uvod
Dinamiˇcno programiranje je pristop k reˇsevanju problemov, ki je soroden z metodo
rekurzivnega razcepa, uporablja pa se predvsem za reˇsevanje doloˇcene vrste optimizacijskih problemov. Podobno kot pri rekurzivnem razcepu, tudi v tem primeru nalogo
razbijemo na podnaloge, vendar v nasprotju z rekurzivnim razcepom, kjer so podnaloge neodvisne, so lahko pri dinamiˇcnem programiranju medsebojno odvisne. Zaradi
tega je potrebno v tem primeru reˇsitve vseh podnalog hraniti, ker se neka podnaloga
med reˇsitvijo celotnega problema lahko pojavi veˇckrat.
6.1 Primer Pri urejanju s porazdelitvami kot tipiˇcni nalogi, ki jo reˇsujemo z rekurzivnim razcepom, razdelimo prvotno nalogo na dva dela, nato dva dela reˇsujemo
loˇceno, ker reˇsevanje ene podnaloge ni povezano z reˇsevanjem druge. 2
6.2 Primer Kot bomo pa videli kasneje, je tipiˇcna naloga, ki jo reˇsujemo z dinamiˇcnim programiranjem, iskanje najcenejˇsih poti v grafih med dvema izbranima
toˇckama. Na sliki 6.1 je prikazan graf, kjer je vsaki povezavi prirejena cena. Naloga
ˇ ceno najcenejˇse poti med i in j
je poiskati najcenejˇso pot med vozliˇsˇcema 1 in 6. Ce
oznaˇcimo z uij , lahko zapiˇsemo
u16 = M IN (u14 + c46 , u15 + c56 ).
Torej je celotna naloga odvisna od cene najcenejˇsih poti med 1 in 4 ter med 1 in 5.
Vendar obe podnalogi vsebujeta nadaljnji podnalogi iskanja cen najcenejˇsih poti med
131
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
132
c12
c24
2
c13
c46
c34
c25
1
4
3
c35
6
5
c56
Slika 6.1: Graf z uteˇzenimi povezavami
1 in 2 ter med 1 in 3. Zato izraˇcuna u14 in u15 nista neodvisna. 2
6.2
Problem 0-1 nahrbtnika
Prvi problem, ki ga bomo reˇsevali z metodo dinamiˇcnega programiranja, je 0-1 nahrbtnik: podano je n predmetov, pri ˇcemer ima i-ti predmet prostornino vi in vrednost
ˇ imamo nahrbtnik s prostornino V , se postavlja problem izbire take podci . Ce
mnoˇzice predmetov, ki ima najveˇcjo skupno vrednost (vsota vrednosti predmetov v
podmnoˇzici), obenem pa po skupni prostornini ne presega V . Torej,
Pn
xi vi ≤ V,
Pi=1
n
i=1 xi ci maksimalno,
xi ∈ {0, 1}.
Problem bomo reˇsili tako, da ga bomo najprej razcepili na podprobleme, nato pa
slednje reˇsevali po velikosti (zaˇceli bomo z najmanjˇsim). S ki (W ) bomo oznaˇcili vrednost optimalnega nahrbtnika, ki ima skupno prostornino W , ˇce upoˇstevamo le prvih
i predmetov. Bodimo pozorni, da je ki funkcija enega argumenta, katere vrednost je
izraˇzena v istih enotah kot vrednosti predmetov, ci . Oˇcitno v tem primeru velja
ki (W ) = M AX(ki−1 (W ), ki−1 (W − vi ) + ci ), 1 ≤ i ≤ n,
(6.1)
pri ˇcemer definiramo,
k0 (W ) =
−∞ pri W < 0
0
sicer.
(6.2)
Razlaga enaˇcbe (6.1), ki ji pravimo Bellmanova enaˇcba, je, da moramo pri odloˇcitvi,
ali predmet i pripada optimalni podmnoˇzici predmetov, primerjati optimalno vrednost
nahrbtnika z upoˇstevanjem i − 1 predmetov, kar ustreza primeru, ko i-ti predmet NI
vkljuˇcen v optimalno podmnoˇzico, z optimalno vrednostjo, ko je i-ti predmet vkljuˇcen.
Slednjo vrednost dobimo kot vsoto optimalne vrednosti z upoˇstevanjem i − 1 predmetov in prostornino, ki je zmanjˇsana za prostornino i-tega predmeta, in vrednosti
i-tega predmeta. Reˇsitev prvotne naloge je kn (V ).
133
6.2. PROBLEM 0-1 NAHRBTNIKA
k0 (W )
W
Slika 6.2: Stopnica
Funkcije ki (W ) raˇcunamo po naraˇsˇcajoˇci vrednosti i, definicija (6.2) pa je posledica
enaˇcbe (6.1). Namreˇc potrebno je zagotoviti, da je nemogoˇce dobiti pozitivno vrednost
drugega argumenta desne strani (6.1) v primeru W − vi < 0, ne glede na velikost ci .
ˇ pri izraˇcunu k1 (W ) stopnico k0 (W )
Funkciji (6.2) pravimo stopnica (gl. sliko 6.2). Ce
vstavimo v enaˇcbo (6.1) namesto ki−1 (W ), ustreza desni parameter stopnici, ki je
zamaknjena v desno za vi in navzgor za ci (gl. sliko 6.3). Na ta naˇcin dobimo dve
stopnici, oziroma po veˇckratni uporabi enaˇcbe (6.1) “vzpenjajoˇce se stopnice” ali, ˇce
uporabimo nekoliko bolj uˇcen izraz, odsekoma konstantno, nepadajoˇco funkcijo (OKN
funkcijo).
Zaradi preproste zgradbe OKN funkcij je tudi raˇcunanje z njimi razmeroma preprosto. OKN funkcijo predstavljamo z zaporedjem parov, ki predstavljajo zamike,
pri ˇcemer prvi element para predstavlja zamik po abscisni osi, drugi element pa po
ordinatni osi.
6.3 Primer Podani so naslednji podatki
n = 4, V = 9
v = (4, 2, 3, 7)
c = (5, 2, 3, 9).
Iz podatkov izraˇcunamo vrednost optimalnega nahrbtnika in optimalno mnoˇzico.
Vrednost raˇcunamo na podlagi enaˇcbe (6.1), pri ˇcemer desni argument funkcije ki
oznaˇcujemo z li = ki (W − vi+1 ) + ci+1 . Rezultat izraˇcuna je prikazan v tabeli na sliki
6.4. Na vsakem koraku iz ki−1 ter li−1 izraˇcunamo ki tako, da pare v ki−1 in li−1
uredimo po naraˇsˇcajoˇci vrednosti prve komponente para in pri doloˇceni vrednosti u
izberemo par z najveˇcjo vrednostjo v. Drugaˇce povedano: ˇce imamo para (u1 , v1 ) in
(u2 , v2 ) in ˇce velja
(u2 ≥ u1 ) ∧ (v2 ≤ v1 ),
(6.3)
lahko (u2 , v2 ) izloˇcimo. Na primer pri izraˇcunu k4 na sliki 6.4 sta izpadla para (7,8)
in (9,10). Poleg tega je moˇzno izloˇciti vse pare s prvo komponento veˇcjo od celotne
prostornine V .
Iz funkcij ki in li je moˇzno tudi sestaviti optimalno podmnoˇzico. V funkciji k4
poiˇsˇcemo par, ki doloˇca vrednost pri celotni prostornini (v naˇsem primeru V = 9).
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
134
k0 (W )
l0 (W )
W
(a) Stopnica
k1 (W )
W
(b) Zamaknjena stopnica
(c) Vzpenjajoˇce se stopnice
Slika 6.3: Odsekoma konstantne nepadajoˇce funkcije
i
0
1
2
3
4
k/l ki oziroma li
k
(0, 0)
l
(4, 5)
k
(0, 0)(4, 5)
l
(2, 2)(6, 7)
k
(0, 0)(2, 2)(4, 5)(6, 7)
l
(3, 3)(5, 5)(7, 8)(9, 10)
k
(0, 0)(2, 2)(3, 3)(4, 5)(6, 7)(7, 8)(9, 10)
l
(7, 9)(9, 11)
k
(0, 0)(2, 2)(3, 3)(4, 5)(6, 7)(7, 9)(9, 11)
Slika 6.4: Izraˇcun optimalnega nahrbtnika
6.2. PROBLEM 0-1 NAHRBTNIKA
135
To je (9,11). Nato ta par poiˇsˇcemo v k3 , oziroma l3 . Ker se ta par nahaja v definiciji
l3 , sklepamo, da je predmet 4 prisoten v optimalni podmnoˇzici. Ker je par (9,11)
nastal iz (2,2), sedaj poiˇsˇcemo (2,2) v k2 , oziroma l2 . Najdemo ga v k2 , kar pomeni,
da predmet 3 ni prisoten v optimalni podmnoˇzici. Na podoben naˇcin ugotovimo, da
je predmet 2 v optimalni podmnoˇzici, predmet 1 pa ni.
Algoritem za reˇsitev problema 0-1 nahrbtnika je prikazan kot popoln program 6.1.
Program uporablja tudi zunanji modul Qs, ki realizira dinamiˇcne sezname in ki je
prikazan kot program 6.2.
Program 6.1: Izraˇ
cun optimalnega 0-1 nahrbtnika
1
3
3
5
6
6
7
8
9
10
11
12
13
14
15
16
17
18
20
21
21
22
23
24
26
26
27
28
29
30
31
32
33
34
MODULE Knapsack ;
IMPORT In,Qs,Out;
TYPE
ObjRec = RECORD v ,c:LONGINT
END; (∗ podatki o predmetih ∗)
PAObjRec = POINTER TO AObjRec ;
AObjRec = ARRAY OF ObjRec ;
PICNfunc = POINTER TO ICNfunc;
ICNfunc = RECORD(Qs.Lifo) vStep,cStep: LONGINT
END ; (∗ OKN funkcija ∗)
ICNfuncPair = RECORD k ,l :Qs.Lifo
END;(∗ k => OKN funkcija; l => zamaknjena OKN funkcija ∗)
PAICNfuncPair = POINTER TO AICNfuncPair ;
AICNfuncPair = ARRAY OF ICNfuncPair ;
PABOOLEAN = POINTER TO ARRAY OF BOOLEAN ;
ABOOLEAN = ARRAY OF BOOLEAN ;
VAR
i,n,V ,optV : LONGINT ;
pObjects: PAObjRec; (∗ opisi predmetov ∗)
pRes : PAICNfuncPair ;
pOptSet: PABOOLEAN ;(∗ optimalna mnoˇzica ∗)
PROCEDURE Init;
VAR i:LONGINT ;p:PICNfunc;
BEGIN In.Open;
(∗ preberemo ˇstevilo predmetov in prostorsko omejitev ∗)
In.LongInt(n);In.LongInt(V );
NEW (pObjects,n);
FOR i:=0 TO n−1 DO
In.LongInt(pObjects[i].v );
In.LongInt(pObjects[i].c)
se nadaljuje
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
136
Izraˇ
cun optimalnega 0-1 nahrbtnika (nadaljevanje)
35
36
37
38
39
40
41
42
43
44
45
47
47
48
49
50
51
53
53
54
55
56
58
58
59
60
61
62
63
64
65
67
67
68
69
70
71
72
74
74
76
76
77
78
79
END;
NEW (pRes,n+1);
FOR i:=0 TO n DO
pRes[i].k .Init;pRes[i].l .Init
END;
NEW (pOptSet,n);
NEW (p);
p.vStep:=0;
p.cStep:=0;
pRes[0].k .Insert(p)
END Init;
PROCEDURE MkTranslPar (i:LONGINT );
(∗ Izracun zamaknjene OKN funkcije ∗)
VAR p:Qs.Lifo;
r :Qs.Fifo;
q:PICNfunc;
BEGIN
r .Init;
p:=pRes[i].k ;
WHILE (p.next # NIL)
& (p.next(PICNfunc).vStep+pObjects[i].v <=V )
DO
NEW (q);
q.vStep:=p.next(PICNfunc).vStep+pObjects[i].v ;
q.cStep:=p.next(PICNfunc).cStep+pObjects[i].c;
r .Insert(q);
p.Step
END;
pRes[i].l :=r .first (∗ kazalec na seznam parov ∗)
END MkTranslPar ;
PROCEDURE Merge(i:LONGINT );
(∗ zlivanje OKN funkcije in iste funkcije z zamikom ∗)
VAR p,q :Qs.Lifo;
plast:PICNfunc;
s:Qs.Fifo;
r :PICNfunc;
PROCEDURE Insert;
BEGIN
NEW (r );
IF p.next(PICNfunc).vStep<q.next(PICNfunc).vStep THEN
r ↑:=p.next(PICNfunc)↑;p.Step
ELSIF p.next(PICNfunc).vStep>q.next(PICNfunc).vStep THEN
se nadaljuje
6.2. PROBLEM 0-1 NAHRBTNIKA
Izraˇ
cun optimalnega 0-1 nahrbtnika (nadaljevanje)
80
81
82
83
84
85
86
87
88
89
90
91
92
94
94
95
97
97
98
99
101
101
102
103
105
106
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
r ↑:=q.next(PICNfunc)↑;q.Step
ELSIF p.next(PICNfunc).cStep<=q.next(PICNfunc).cStep THEN
r ↑:=q.next(PICNfunc)↑;
q.Step;
p.Step
ELSE
r ↑:=p.next(PICNfunc)↑;
q.Step;
p.Step
END ;
plast:=r ;
s.Insert(r )
END Insert;
PROCEDURE Skip(p:Qs.Lifo);
(∗ zanemarjanje odveˇcnih parov ∗)
BEGIN
WHILE (p.next#NIL)
&(p.next(PICNfunc).vStep>=plast.vStep)
&(p.next(PICNfunc).cStep<=plast.cStep)
DO
p.Step
END;
END Skip;
BEGIN
s.Init;
p:=pRes[i−1].k ;q:=pRes[i−1].l ;
WHILE (p.next # NIL) & (q.next # NIL) DO
Insert;
Skip(p);
Skip(q)
END;
WHILE p.next # NIL DO
NEW (r );
r ↑:=p.next(PICNfunc)↑;
p.Step;
s.Insert(r )
END;
WHILE q.next # NIL DO
NEW (r );
r ↑:=q.next(PICNfunc)↑;
q.Step;
s.Insert(r )
END;
se nadaljuje
137
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
138
Izraˇ
cun optimalnega 0-1 nahrbtnika (nadaljevanje)
125
126
128
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
154
154
155
156
157
158
159
160
161
163
164
165
165
167
168
168
169
pRes[i].k :=s.first
END Merge;
PROCEDURE OptSet;
VAR i:LONGINT ;
p:Qs.Lifo;
q:PICNfunc;
optR:ICNfunc;
BEGIN
IF n>0 THEN
p:=pRes[n].k ;
REPEAT q:=p.next(PICNfunc); p.Step
UNTIL (p.next = NIL) OR (p.next(PICNfunc).vStep > V );
optV :=q.cStep;
optR:=q↑;
FOR i:=n−1 TO 0 BY −1 DO
p:=pRes[i].k ;
WHILE (p.next # NIL)
&(
(p.next(PICNfunc).vStep # optR.vStep)
OR (p.next(PICNfunc).cStep # optR.cStep)
)
DO p.Step
END ;
pOptSet[i]:= p.next = NIL ;
IF pOptSet[i] THEN
optR.vStep:=optR.vStep−pObjects[i].v ;
optR.cStep:=optR.cStep−pObjects[i].c
END
END;
Out.Ln;Out.String(“Optimalna vrednost: ”);
Out.Int(optV ,10);
Out.Ln;Out.String(“Optimalna mnozica:”);
FOR i:=0 TO n−1 DO
Out.Ln;Out.Int(i+1,2);
IF pOptSet[i] THEN Out.String(“: +”)
ELSE Out.String(“: −”)
END
END
END
END OptSet;
BEGIN
Init ;
FOR i:=1 TO n DO
se nadaljuje
6.2. PROBLEM 0-1 NAHRBTNIKA
Izraˇ
cun optimalnega 0-1 nahrbtnika (nadaljevanje)
170
171
172
174
174
MkTranslPar (i−1);
Merge(i)
END ;
OptSet
END Knapsack .
Izraˇ
cun optimalnega 0-1 nahrbtnika (konec)
Program 6.2: Dinamiˇ
cni seznami
1
2
3
5
6
7
7
9
9
10
12
12
14
14
16
16
17
19
19
20
21
23
23
24
25
26
27
29
29
30
31
32
34
34
MODULE Qs;
(∗
Dinamiˇcni seznami
∗)
TYPE
PEmpty∗ = POINTER TO Empty;
Empty∗ = RECORD
END;
PLifo∗ = POINTER TO Lifo;
PFifo∗ = POINTER TO Fifo;
Lifo∗ = RECORD(Empty) next∗: PLifo
END ; (∗ sklad − “zadnji noter, prvi ven”∗)
Fifo∗ = RECORD(Empty)
first∗,last∗: Lifo
END; (∗ navadni seznam − “prvi noter, prvi ven” ∗)
(∗ algoritmi ∗)
PROCEDURE (VAR p:Lifo)Init∗;
(∗ Zaˇcetne nastavitve ∗)
BEGIN p.next:=NIL
END Init;
PROCEDURE (VAR p:Lifo)Insert∗(q:PLifo);
(∗ q↑ na zaˇcetek p ∗)
BEGIN q.next:=p.next ; p.next:=q
END Insert;
PROCEDURE (VAR p:Lifo)Step∗;
se nadaljuje
139
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
140
Dinamiˇ
cni seznami (nadaljevanje)
35
36
37
39
39
40
41
42
44
44
45
47
47
48
49
50
51
53
53
54
56
56
57
58
59
61
61
62
(∗ pomikanje po seznamu ali brisanje elementov ∗)
BEGIN p.next:=p.next.next
END Step;
PROCEDURE (VAR p:Fifo)Init∗;
(∗ Zaˇcetne nastavitve ∗)
BEGIN p.first.Init
END Init;
PROCEDURE (VAR p:Fifo)Insert∗(q:PLifo);
(∗ Seznam podaljˇsamo s q↑ ∗)
BEGIN
IF p.first.next=NIL THEN p.first.Insert(q)
ELSE p.last.next.Insert(q)
END;
p.last.next:=q
END Insert;
PROCEDURE (VAR f :Fifo)Join∗(VAR g:Fifo);
(∗ Zdruˇzimo seznama f in g ∗)
BEGIN
IF f .first.next=NIL THEN
f :=g
ELSE f .last.next.next:=g.first.next;
f .last.next:=g.last.next
END
END Join;
END Qs.
Dinamiˇ
cni seznami (konec)
6.3
Problem najcenejˇ
sih poti
Problem iskanja najcenejˇsih poti v grafu je tipiˇcen problem, ki se reˇsuje z metodo
dinamiˇcnega programiranja (v posebnih primerih pa tudi z drugimi metodami). V
tem razdelku bomo opisali veˇc razliˇcic problema in metod reˇsevanja.
Podan je usmerjen graf G = hV, Ei, pri ˇcemer je V mnoˇzica vozliˇsˇc, E pa mnoˇzica
povezav. Na primer na sliki 6.1 je mnoˇzica vozliˇsˇc {1, 2, 3, 4, 5, 6}, mnoˇzica povezav
pa {(1, 2), (1, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 6)(5, 6)}. Poleg tega imamo ˇse funkcijo
c : E −→ IR (namesto IR lahko uporabljamo katerokoli popolnoma urejeno mnoˇzico,
na kateri je definirano seˇstevanje). Koliˇcini c(e) pri e ∈ E pravimo cena povezave e.
Na primer, na sliki 6.1 je cena povezave hi, ji oznaˇcena s cij . Graf, ki mu je prirejena
cenilna funkcija c, poimenujemo graf z uteˇzenimi povezavami . Pot med vozliˇsˇcema iZ
ˇ POTI
6.3. PROBLEM NAJCENEJSIH
141
in iK je zaporedje vozliˇsˇc
iZ = i1 , i2 , . . . , in = iK ,
tako da je hij , ij+1 i ∈ E, 1 ≤ j < n, njena cena pa je
uiZ ,iK =
n−1
X
c(ij , ij+1 ).
j=1
V kolikor pri neki poti velja iZ = iK , ji pravimo cikel . Naloga iskanja najcenejˇsih
poti ima ˇstevilne razliˇcice, od katerih bomo obravnavali najpomembnejˇse. Najprej
razlikujemo med iskanjem najcenejˇsih poti
• med zaˇcetnim vozliˇsˇcem in vsemi ostalimi ter
• med vsemi pari vozliˇsˇc.
Lahko bi pomislili, da bi bilo potrebno k dvema zapisanima nalogama dodati ˇse nalogo iskanja najcenejˇse poti med zaˇcetnim vozliˇsˇcem ter nekim posameznim konˇcnim
vozliˇsˇcem, kajti gotovo je taka naloga laˇzja kot iskanje poti med zaˇcetnim vozliˇsˇcem
in vsemi ostalimi. Napaka! Empiriˇcne izkuˇsnje namreˇc kaˇzejo, da sta ti dve nalogi po
teˇzavnosti enakovredni.
6.3.1
Najcenejˇ
se poti med zaˇ
cetnim vozliˇ
sˇ
cem in vsemi ostalimi
Za to, da v nekem grafu z uteˇzenimi povezavami, G = hV, E, ci, obstaja pot z enoliˇcno
doloˇceno najniˇzjo ceno od zaˇcetnega vozliˇsˇca, 1, do vseh ostalih vozliˇsˇc in da ima
konˇcno vrednost, morata biti izpolnjena dva pogoja: prviˇc, zaˇcetno vozliˇsˇce mora biti
povezano z vsemi ostalimi in drugiˇc, graf ne sme imeti negativnih ciklov (ciklov, pri
katerih je vsota cen povezav negativna). Oba pogoja sta oˇcitna, na primer, ˇce drugi
ni izpolnjen, od vsake poti do kateregakoli vozliˇsˇca, do katerega vodi pot skozi neko
vozliˇsˇce na negativnem ciklu, obstaja cenejˇsa pot, ki jo dobimo tako, da se sprehodimo
po ciklu veˇckrat.
Najcenejˇse poti imajo neko pomembno lastnost, ki nam omogoˇca, da jih raˇcunamo
z dinamiˇcnim programiranjem:
6.4 Trditev Naj bo dan graf z uteˇzenimi povezavami G = hV, E, ci in neka najcenejˇsa
pot med vozliˇsˇcema iZ in iK . Naj bo i1 , i2 , . . . , in neka pot, ki je del poti med iZ in
iK . V tem primeru je i1 , i2 , . . . , in najcenejˇsa pot med i1 in in .
ˇ i1 , i2 , . . . , in ni najcenejˇsa pot med i1 in in , jo zamenjamo z najcenejˇso
Dokaz. Ce
potjo in dobimo cenejˇso pot med iZ in iK kot je prvotna, kar nasprotuje privzetku,
da je prvotna pot med iZ in iK najcenejˇsa. 2
Pri izpolnjenih dveh osnovnih pogojih (vozliˇsˇce 1 je povezano z vsemi ostalimi in
odsotnost negativnih ciklov) je reˇsitev naloge moˇzno opisati z nekim naborom enaˇcb,
ki jim pravimo Bellmanove enaˇcbe.
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
142
Bellmanove enaˇ
cbe. Naj bo 1 zaˇcetno vozliˇsˇce in ui , pri 1 ≤ i ≤ n, cena najcenejˇse
poti med 1 in i. V tem primeru lahko zapiˇsemo
0
pri i = 1;
ui =
(6.4)
mink6=i {uk + cki } sicer.
Z besedami: najcenejˇsa pot do zaˇcetnega vozliˇsˇca ima ceno 0, do ostalih vozliˇsˇc pa je
najcenejˇsa pot podaljˇsek neke druge najcenejˇse poti.
Pri zapisanih pogojih je reˇsitev Bellmanovih enaˇcb natanko reˇsitev problema najcenejˇsih poti, kar dokaˇzemo z dvema izrekoma:
6.5 Izrek Naj bo G = hV, Ei graf z uteˇzenimi povezavami, ki nima negativnih ciklov.
Naj bo vozliˇsˇce 1 povezano z vsemi ostalimi in naj bo u1 , u2 , . . . , un reˇsitev problema
najcenejˇsih poti od vozliˇsˇca 1 do vseh ostalih. V tem primeru zadoˇsˇcajo koliˇcine ui
pri 1 ≤ i ≤ n Bellmanovim enaˇcbam (6.4).
Dokaz. Dejstvo, da za vsak ui velja ui = uk + cki pri nekem k, sledi iz trditve 6.4.
Sedaj pa denimo, da trditev iz izreka ni resniˇcna. V tem primeru obstaja i, tako da
ui = min{uk + cki }
k6=i
ˇ nato spremenimo predhodno vozliˇsˇce k tako, da pravkar zapisana
ni resniˇcno. Ce
enaˇcba postane resniˇcna, dobimo cenejˇso pot do i, kar je v protislovju s privzetkom,
da predstavlja nabor u1 , u2 , . . . , un reˇsitev problema najcenejˇsih poti od vozliˇsˇca 1 do
vseh
ostalih. 2
V primeru, ko so koliˇcine u1 , u2 , . . . , un reˇsitev
Bellmanovih enaˇcb (6.4), se izkaˇze, da je vozliˇsˇca grafa
moˇzno urediti v drevesno strukturo. Relacija “vo3
2
zliˇsˇce i je neposredno podrejeno vozliˇsˇcu j” oziroma
3
5
v simboliˇcnem zapisu, i ≺ j, je definirana kot j je
5
4
vrednost k, pri kateri uk + cki doseˇze minimum. Ker
2
mora biti j doloˇceno enoliˇcno, se domenimo, da v pri6
meru uk0 + ck0 j = uk00 + ck00 j izberemo manjˇsega od
dveh
indeksov, k 0 in k 00 .
Slika 6.5:
Drevo najceˇ
Ce za vsak i zapiˇsemo zaporedje indeksov i ≺ i1 ≺
nejˇsih poti za graf na sliki
i
.
.
., ugotovimo , da ima vsak element enega predho2
6.1, ˇce so cene povezav
c12 = 2, c13 = 2, c24 = dnika (na podlagi definicije), zaporedje pa se konˇcuje z
3, c25 = 5, c34 = 4, c35 = vozliˇsˇcem 1 (ker je to edino vozliˇsˇce brez predhodnika,
ˇ
gl. sliko 6.5). Stevilu
povezav na poti od vozliˇsˇca i do
6, c46 = 2 in c56 = 2
korena, ˇce uporabljamo povezave, na podlagi katerih
je definirana relacija ≺, pravimo globina vozliˇsˇca i.
2
1
2
6.6 Izrek Podan je graf G = hV, Ei z uteˇzenimi povezavami brez negativnih ciklov.
V tem primeru je reˇsitev Bellmanovih enaˇcb (6.4) enoliˇcna in predstavlja reˇsitev problema najcenejˇsih poti od vozliˇsˇca 1 do vseh ostalih.
ˇ POTI
6.3. PROBLEM NAJCENEJSIH
143
Dokaz. Najprej za poljubno reˇsitev Bellmanovih enaˇcb (6.4)
u1 , u2 , . . . , un
dokaˇzemo, da predstavlja ui ceno neke poti od vozliˇsˇca 1 do i. Dokaz izpeljemo z
indukcijo po globini vozliˇsˇca v drevesu vozliˇsˇc, ki je bilo pravkar opisano. Za globino
0 (vozliˇsˇce 1 oziroma koren drevesa) je trditev oˇcitna, kajti u1 = 0 je cena prazne
poti. Sedaj dokaˇzimo trditev za vozliˇsˇce i s privzetkom, da smo trditev za vozliˇsˇca na
ˇ velja i ≺ j, je globina j manjˇsa od globine
globini, ki je manjˇsa od i, ˇze dokazali. Ce
i in smo za uj ˇze dokazali, da je cena neke poti. Na podlagi definicije je potemtakem
ui cena poti do j, ki je podaljˇsana s povezavo hj, ii.
Naj bo sedaj u1 , u2 , . . . , un reˇsitev problema najcenejˇsih poti, ki na podlagi izreka
6.5 zadoˇsˇca Bellmanovim enaˇcbam (6.4) in naj bo u1 , u2 , . . . , un neka druga reˇsitev
Bellmanovih enaˇcb, ki se razlikuje od u1 , u2 , . . . , un . Za reˇsitev u1 , u2 , . . . , un sestavimo drevo vozliˇsˇc in izberemo neko vozliˇsˇce i na najmanjˇsi globini, pri katerem velja
ui 6= ui . V tem primeru oˇcitno velja ui > ui . Vendar, ker velja pri vseh vozliˇsˇcih
j, uj ≥ uj , pri tistih na manjˇsi globini, kot je globina i pa uj = uj , sklepamo, da
ui = mink6=i {uk + cki } ne velja, kar nasprotuje trditvi, da je u1 , u2 , . . . , un reˇsitev
Bellmanovih enaˇcb (6.4), s ˇcimer smo trditev izreka dokazali. 2
Vendar z dokazom predhodnih dveh izrekov naloga izraˇcuna najcenejˇsih poti ˇse
zdaleˇc ni zakljuˇcena. Namreˇc, kot smo v uvodu poglavja zapisali, se izraˇcun pri
metodi dinamiˇcnega programiranja izvaja tako, da postopno raˇcunamo podnaloge prvotne naloge, zaˇcenˇsi z najmanjˇsimi. Pri reˇsevanju 0-1 nahrbtnika smo z enaˇcbo (6.1)
ˇze odkrili hierarhijo velikosti podproblemov, saj je raˇcunanje funkcije ki−1 “manjˇsa
naloga” od raˇcunanja ki (1 ). Pri sedanji nalogi pa enaˇcbe (6.4) narekujejo, da pri
vsaki koliˇcini ui uporabljamo vse ostale uk , kar pomeni, da brez dodatne informacije
ne poznamo vrstnega reda izraˇcunov.
V nadaljevanju poglavja bomo opisali nekaj primernih hierarhij podnalog pri
reˇsevanju problema najcenejˇsih poti.
Najcenejˇ
se poti v acikliˇ
cnih grafih. Eden od moˇznih naˇcinov za urejanje pod∗
nalog iskanja najcenejˇsih poti je na podlagi dejstva, da takrat, ko velja u −→
/ v (med
u in v ni poti), naloga iskanja najcenejˇsih poti do v ne more biti odvisna od iskanja
najcenejˇsih poti do u (ker ni moˇzno za iskanje “dobre” poti do v izkoristiti neko pot
do u). V takem primeru lahko reˇsujemo nalogo iskanja najcenejˇsih poti do v pred
nalogo iskanja najcenejˇsih poti do u.
∗
V primeru, ko graf nima ciklov, ima u −→ v (med u in v obstaja pot) za posledico
∗
v −→
/ u (med v in u ni poti) in zato pri veljavnem prvem pogoju ter na podlagi
zgoraj zapisane misli naloga iskanja najcenejˇsih poti do u ne potrebuje rezultata
naloge iskanja najcenejˇsih poti do v. V sploˇsnem lahko iz tega naˇcela izpeljemo
1 Primerna in natanˇ
cna definicija pojma “manjˇsa naloga” je, da je P1 manjˇsa naloga kot P2 , v
kolikor pri iskanju reˇsitve za P1 ne potrebujemo rezultatov P2 .
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
144
3
1
0
5
4
2
Slika 6.6: Stopnje vozliˇsˇc nekega acikliˇcnega grafa
neko urejenost vozliˇsˇc grafa ≺, na podlagi katere pridobijo Bellmanove enaˇcbe (6.4)
naslednji videz:
0
pri i = 1
ui =
(6.5)
mink≺i {uk + cki } sicer
in lahko raˇcunanje podnalog ui uredimo na podlagi urejenosti ≺ (torej “manjˇse”
koliˇcine ui raˇcunamo pred “veˇcjimi”). To, kar smo pravkar zapisali, lahko povzamemo
z naslednjo trditvijo:
6.7 Trditev Graf G = hV, Ei je acikliˇcen natanko tedaj, ko obstaja popolna urejenost
V z lastnostjo,
∗
u v =⇒ u −→
/ v.
(6.6)
Dokaz. Trditev je sestavljena iz dveh delov. Prvi pravi, da, v kolikor opisana popolna
urejenost obstaja, je graf acikliˇcen; drugi pa nasprotno, ˇce je graf acikliˇcen, taka
urejenost zagotovo obstaja.
Dokaz prvega dela je oˇciten, saj lahko na podlagi urejenosti ≺ vozliˇsˇca razvrstimo
v ravno ˇcrto, pogoj (6.6) pa pomeni, da povezave gredo le od leve proti desni, kar
seveda pomeni, da ni ciklov. Pri dokazu drugega pa iz privzetka acikliˇcnosti definiramo
urejenost, ki ima ˇzeleno lastnost. Najprej definiramo pojem stopnje vozliˇsˇca v kot
najveˇcje ˇstevilo povezav na neki poti, ki izhaja iz v. Pojem je dobro definiran, kajti
kadar je graf acikliˇcen, iz vsakega vozliˇsˇca vodi konˇcno mnogo poti in je potemtakem
tudi najveˇcje ˇstevilo povezav na neki poti natanˇcno definirano. Kot primer prikazuje
slika 6.6 acikliˇcni graf, kjer so vozliˇsˇca oznaˇcena s stopnjami. Ker oˇcitno velja
∗
u −→ v =⇒ stopnja(u) > stopnja(v),
oziroma,
∗
stopnja(u) ≤ stopnja(v) =⇒ u −→
/ v,
lahko relaciji u v ustrezajo padajoˇce stopnje. Bolj natanˇcno, v primeru stopnja(u) <
stopnja(v) definiramo u v, v primeru stopnja(u) = stopnja(v) pa bodisi u v ali
u ≺ v. 2
Urejenosti pravimo topoloˇska urejenost (vozliˇsˇc grafa), postopek za njen izraˇcun
pa je prikazan na sliki 6.7. Postopek izhaja iz tega, da ima zagotovo najviˇsjo stopnjo
(in s tem najmanjˇsi poloˇzaj v urejenosti ) neko vozliˇsˇce, do katerega ne vodi nobena
povezava. Zato najprej poiˇsˇcemo neko tako vozliˇsˇce in ga zapiˇsemo kot naslednje
ˇ POTI
6.3. PROBLEM NAJCENEJSIH
145
Vhod:
Seznam povezav E grafa G = hV, Ei.
Izhod:
Topoloˇsko urejeno zaporedje vozliˇsˇ
c, V .
Postopek:
1. Preberemo seznam parov hi, ji in na podlagi seznama zgradimo podatkovno
strukturo, ki predstavlja graf. Vsakemu vozliˇsˇ
cu v priredimo koliˇ
cino inv , ki
predstavlja ˇstevilo povezav, ki so usmerjene v vozliˇsˇ
ce;
2. r = ∅;
3. poiˇsˇ
cemo vsa vozliˇsˇ
ca v, pri katerih je inv = 0, ter jih dodamo seznamu r;
ˇ
ce takega vozliˇsˇ
ca ni in je mnoˇ
zica vozliˇsˇ
c neprazna, je to znak, da G vsebuje
cikel. V tem primeru se ustavimo;
4. spremenljivki u priredimo prvi element seznama r ter ga obenem odstranimo
s seznama;
5. vse povezave, ki so usmerjene iz u, odstranimo in vsakiˇ
c, ko odstranimo neko
povezavo, zmanjˇsamo za 1 koliˇ
cino inv , ˇ
ce je v vozliˇsˇ
ce, kamor je bila povezava
usmerjena;
6. u damo na konec izhodnega zaporedja;
7. ˇ
ce je seznam r prazen, se ustavimo, sicer nadaljujemo pri 3.
Slika 6.7: Topoloˇsko urejanje
(oziroma zaˇcetno) vozliˇsˇce v vrstnem redu . Nato vse povezave, ki izhajajo iz tega
ˇ
vozliˇsˇca, izbriˇsemo in postopek ponovimo2 . Cas,
ki ga porabi postopek za topoloˇsko
urejanje ni teˇzko oceniti: naj bo ˇstevilo vozliˇsˇc n, ˇstevilo povezav pa m. Za sestavljanje
podatkovne strukture, ki predstavlja vozliˇsˇca, in za obiskovanje vozliˇsˇc, ki nimajo
vhodnih povezav, potrebujemo ˇcas Θ(n), ˇcas za izraˇcun vhodne stopnje vozliˇsˇc ter za
aˇzuriranje slednje koliˇcine pa je Θ(m), torej je skupen ˇcas Θ(m + n).
6.8 Primer Sled algoritma na sliki 6.7 na primeru s slike 6.1 je prikazana v tabeli
na sliki 6.8. 2
Dijkstrov algoritem. V kolikor imajo vse povezave v grafu pozitivne cene, se
nam ponuja neka druga moˇznost urejanja izraˇcunov koliˇcin ui v enaˇcbah 6.4. V tem
primeru jih lahko raˇcunamo na podlagi naraˇsˇcajoˇce vrednosti (ui ). To je moˇzno zato,
ker v primeru ui > uj najcenejˇsa pot do i ne pride v poˇstev kot gradnik za najcenejˇso
∗
pot do j (ˇcetudi velja i −→ j) zato, ker bi povezave od i do j (ki so pozitivne) le
ˇse poveˇcale vrednost te koliˇcine. Posledica tega je da, lahko izraˇcunamo ui kasneje
2 V naˇ
sem primeru, ko iˇsˇ
cemo najcenejˇse poti med zaˇ
cetnim vozliˇsˇ
cem in vsemi ostalimi, je na
zaˇ
cetku zaˇ
cetno vozliˇsˇ
ce edino, ki izpolnjuje pogoj, da nima k sebi usmerjenih povezav (zaradi
privzetka o povezanosti zaˇ
cetnega vozliˇsˇ
ca z vsemi ostalimi).
146
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
r=1
u = 1 (odstranimo
r = 2,3
u = 2 (odstranimo
r=3
u = 3 (odstranimo
r = 4,5
u = 4 (odstranimo
r=5
u = 5 (odstranimo
r=6
u=6
povezavi 1-2 ter 1-3)
povezavi 2-4 ter 2-5)
povezavi 3-4 ter 3-5)
povezavo 4-6)
povezavo 5-6)
Slika 6.8: Sled algoritma za topoloˇsko urejanje (slika 6.7) za graf na sliki 6.1. Izpis r
se nanaˇsa na trenutek, ko se izvrˇsi toˇcka 3, izpis u pa se nanaˇsa na trenutek, ko se
izvrˇsi toˇcka 5
kot uj . Torej izraˇcune uredimo tako, da na vsakem koraku izraˇcunamo naslednjo
veˇcjo koliˇcino ui . Algoritmu, ki deluje na ta naˇcin, pravimo Dijkstrov algoritem, po
izumitelju E. W. Dijkstri in je prikazan na sliki 6.9.
Za razumevanje algoritma je bistvena invarianta zanke, ki obsega toˇcke 2-5 na
sliki 6.9. Le-ta se glasi: “Koliˇcine ui za elemente mnoˇzice P so dokonˇcne in pravilne
vrednosti cen najcenejˇsih poti, koliˇcine ui za elemente T pa predstavljajo le zgornjo
mejo dokonˇcne vrednosti. ui za nek element i ∈ T predstavlja najmanjˇso ceno med
takimi potmi do i, v katerih le vozliˇsˇce i pripada T , ostala pa pripadajo P .”
Zapisana invarianta oˇcitno velja pred toˇcko 2, njeno sploˇsno veljavnost pa dokaˇzemo
z indukcijo. Pred prvim izvajanjem zanke je njena veljavnost oˇcitna, na podlagi
zaˇcetnih prirejanj (P vsebuje le vozliˇsˇce 1, cena poti do njega pa je 0). Sedaj je potrebno dokazati, da invarianta ostane v veljavi tudi po izvajanju jedra zanke. Denimo,
da smo v neki iteraciji na 3. koraku (slika 6.9) naˇsli element k. Moramo se prepriˇcati,
da je uk dejansko pravilna vrednost najcenejˇse poti med 1 in k. Naj to ne drˇzi. V tem
primeru obstaja neka druga, cenejˇsa pot do k. Pri cenejˇsi poti se ne more zgoditi, da
vse povezave, razen zadnje, povezujejo elemente P , kajti med takimi je pot s ceno uk
ˇze najcenejˇsa. Torej gre domnevno najcenejˇsa pot do nekega vozliˇsˇca h0 , nato preskoˇci
v mnoˇzico T pri elementu k 0 , od koder nadaljuje pot do k (gl. sliko 6.10). Vendar,
ker je uk0 ≥ uk , bi morala pot med k 0 in k imeti skupno negativno ceno, ˇce bi hoteli
doseˇci manjˇso vrednosti od uk . To pa ni moˇzno zaradi izhodiˇsˇcnega privzetka, da so
cene povezav pozitivne. Torej je uk najcenejˇsa pot do k. Pravzaprav ni nujno, da pot
k 0 −→ k poteka le po vozliˇsˇcih T . Lahko tudi enkrat ali veˇckrat preskoˇci nazaj v P .
Vendar to ne spremeni zapisanega premisleka in zakljuˇcek ostane isti.
Nadalje moramo preveriti, ali se po popravku vrednosti ui , pri i ∈ T ohranja
lastnost, da je ui cena najcenejˇse med potmi, pri katerih le konˇcno vozliˇsˇce ne pripada
ˇ POTI
6.3. PROBLEM NAJCENEJSIH
147
Vhod:
Seznam cen povezav, cij , grafa G = hV, Ei, pri ˇ
cemer je V = {1, 2, . . . , n}.
Izhod:
Vrednosti najcenejˇsih poti, ui .
Postopek:
1. Koliˇ
cinam ui priredimo zaˇ
cetne vrednosti c1i , ˇ
ce povezava h1, ii obstaja, sicer
dobi ui vrednost ∞; nato razdelimo V na dve medsebojno tuji podmnoˇ
zici:
P = {1} in T = {2, . . . , n}.
2. ˇ
ce je T prazno, se ustavimo, sicer nadaljujemo;
3. poiˇsˇ
cemo minimalno vrednost uk v mnoˇ
zici T ter k prestavimo v mnoˇ
zico P ;
ˇ
ce ima veˇ
c koliˇ
cin ui isto minimalno vrednost, izberemo najmanjˇsi indeks;
4. popravimo koliˇ
cine ui za i ∈ T po pravilu ui := min(ui , uk + cki );
5. vrnemo se na korak 2.
Slika 6.9: Dijkstrov algoritem
k0
T
ch0 k0
h0
chk
h
1
k
P
Slika 6.10: Dijkstov algoritem: izbira naslednjega elementa k, do katerega poznamo
najcenejˇso pot
P (gl. sliko 6.9, toˇcka 4). To pa oˇcitno drˇzi, saj potem, ko smo dodali k mnoˇzici P ,
je edina nova moˇznost za povezave med P in i, pot, ki pelje preko k. In to moˇznost
smo ravno preverili pri popravljanju vrednosti ui .
6.9 Primer Delovanje Dijkstrovega algoritma na grafu s slike 6.11 je prikazano na
tabeli na sliki 6.12. 2
Tudi ˇcas Dijkstrovega algoritma ni teˇzko oceniti: ˇcas za zaˇcetni izraˇcun koliˇcin
ui , 2 ≤ i ≤ n, pri ˇcemer je n ˇstevilo vozliˇsˇc, je Θ(n). Nato pri i-tem izvajanju jedra
zanke 2-5 potrebujemo ˇcas Θ(n−i) za izbiro najmanjˇse vrednosti ui ter za spremembo
koliˇcin ui . Celotni ˇcas je torej enak Θ(n2 ).
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
148
1
7
2
2
7
7
7
3
4
3
2
6
1
2
5
1
Slika 6.11: Primer grafa
u
u
u
u
u
u
1
0∗
0∗
0∗
0∗
0∗
0∗
2
2
2∗
2∗
2∗
2∗
2∗
3
7
5
5∗
5∗
5∗
5∗
4
∞
9
9
7
7∗
7∗
5
∞
9
6
6∗
6∗
6∗
6
∞
∞
∞
8
8
8∗
Slika 6.12: Potek Dijkstrovega algoritma za graf na sliki 6.11 (elementi mnoˇzice P so
oznaˇceni z zvezdicami). Odsotnost povezave med P in i je nakazana z znakom ∞.
Tako zasnovan algoritem za najcenejˇse poti v grafih spada med poˇzreˇsne algoritme
(ker izbiramo k na podlagi najmanjˇse vrednosti ui , i ∈ T ), kljub temu, da se od
algoritmov iz poglavja 4 razlikuje po tem, da se ocene preostalih predmetov (ui pri
i ∈ T ) spreminjajo med raˇcunanjem. Trditev je upraviˇcena zato, ker je najbolj
znaˇcilna lastnost poˇzreˇsnih algoritmov, da predmete izbiramo enega za drugim na
podlagi njihove vrednosti in nobena izbira predmeta ne more postaviti pod vpraˇsaj
neke predhodne izbire.
Bellman-Fordov algoritem. Pri zadnjem naˇcinu urejanja podnalog naloge iskanja
najcenejˇsih poti uporabljamo pribliˇzke koliˇcin ui , ki se razlikujejo po ˇstevilu povezav
na neki poti. Pri tem z uhi oznaˇcimo najcenejˇso pot do i med vsemi potmi, ki vsebujejo
h ali manj povezav. Oˇcitno je, da pot s h povezavami lahko uporablja kot gradnike
le poti, ki imajo manj kot h povezav. Zato lahko izraˇcun uredimo tako, da raˇcunamo
koliˇcine uhi po naraˇsˇcajoˇcem h. Dokonˇcne vrednosti koliˇcin ui dobimo kot vrednosti
un−1
, kjer je n ˇstevilo vozliˇsˇc v grafu.
i
V tem primeru imajo Bellmanove enaˇcbe (6.4) obliko

pri i = 1;
 0
h
c
pri h = 1;
ui =
1i

h−1
h−1
min{ui , mink6=i {uk + cki }} sicer.
(6.7)
ˇ POTI
6.3. PROBLEM NAJCENEJSIH
149
ˇ
ˇ
ˇ
OBICAJNO
MATRICNO
MNOZENJE
Cij =
n
X
Aik · Bkj .
k=1
ˇ
ˇ
SPREMENJENO MATRICNO
MNOZENJE
n
Cij = min{Aik + Bkj }.
k=1
Slika 6.13: Dve vrsti matriˇcnega mnoˇzenja
ˇ privzamemo, da je cii = 0, lahko zadnjo vrstico zapiˇsemo v enostavnejˇsi obliki,
Ce
n
uhi = min{ukh−1 + cki }.
k=1
(6.8)
Za ta algoritem se ni teˇzko prepriˇcati, da porabi ˇcas Θ(n3 ).
6.3.2
Najcenejˇ
se poti med vsemi pari vozliˇ
sˇ
c
Naˇceloma je moˇzno poiskati najcenejˇse poti med vsemi pari vozliˇsˇc tako, da algoritem
za najcenejˇse poti med zaˇcetnim vozliˇsˇcem in vsemi ostalimi sproˇzimo pri vsakem
ˇ je ˇstevilo vozliˇsˇc n, dobimo potemtakem algoritem s ˇcasovno zahtevnostjo
vozliˇsˇcu. Ce
nT (n), kjer je T (n) ˇcasovna zahtevnost algoritma za najcenejˇse poti med zaˇcetnim
vozliˇsˇcem in vsemi ostalimi.
Zanimiva pa je naloga poiskati algoritem za najcenejˇse poti med vsemi pari vozliˇsˇc,
ki bi imel manjˇso zahtevnost od zapisane vrednosti. V nadaljevanju bomo predstavili
dva takˇsna algoritma.
Posploˇ
seni Bellman-Fordov algoritem. V tem primeru izhajamo iz BellmanFordovega algoritma. Koliˇcino ui iz (6.8) poimenujemo u1i , oziroma po zamenjavi i
z j, u1j , nato pa dobimo kot vrednost najcenejˇse poti, ki vsebuje najveˇc h povezav,
od i do j izraz

pri i = j
 0
cij
pri h = 1
uhij =
(6.9)

h−1
minnk=1 {uik
+ ckj } pri 2 ≤ h ≤ n − 1.
ˇ koliˇcine uh uredimo v matriko velikosti n × n in jo poimenujemo C h , pri ˇcemer je
Ce
ij
C 1 matrika cen cij , lahko opazimo, da je izraz (6.9) dobro znano pravilo za element
hi, ji matriˇcnega produkta C h−1 · C 1 potem, ko smo operacijo mnoˇzenja zamenjali s
seˇstevanjem in vsoto nadomestili z minimalizacijo (gl. sliko 6.13).
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
150
h
h−1
uhj
h−1
uih
i
uh−1
ij
j
vozliˇsˇca 1, . . . , h − 1
Slika 6.14: Osnovna operacija pri Floyd-Warshallovem algoritmu
Na prvi pogled s tako spremembo zapisa nismo pridobili niˇc. Na podlagi prvega
odstavka tega razdelka ugotavljamo, da porabi posploˇseni Bellman-Fordov algoritem
ˇcas nT (n) = Θ(n4 ). Ocena se ne spremeni, ˇce uporabljamo matriˇcni zapis, kajti
matrika najcenejˇsih poti je
1
1
(6.10)
U =C
· . . . · C }1 ,
| · C {z
n−1 faktorjev
in ˇce privzamemo, da eno matriˇcno mnoˇzenje porabi Θ(n3 ) operacij, vsega skupaj pa
imamo n − 2 matriˇcnih mnoˇzenj, dobimo tudi na ta naˇcin oceno Θ(n4 ) operacij.
Vendar nas matriˇcni zapis napelje na idejo, da (6.10) raˇcunamo po shemi,
2| · 2 ·{z. . . · 2}
(C ) dlog2 (n−1)e
1
(6.11)
(torej z iteriranim kvadriranjem), kar pri nespremenjeni oceni za ˇstevilo operacij
posameznega matriˇcnega mnoˇzenja pripelje do konˇcne ocene
Θ(n3 log2 n).
(6.12)
Bodimo pozorni na to, da je ˇstevilo kvadriranj k = dlog2 (n − 1)e, kar pomeni, da je
2k najmanjˇsi eksponent 2, ki je veˇcji od n − 1.
Floyd-Warshallov algoritem. Pri Bellman-Fordovem algoritmu smo podnaloge
uredili na podlagi najveˇcjega ˇstevila povezav na poti med dvema vozliˇsˇcema. Izkaˇze
se, da obstaja ˇse en naˇcin za njihovo urejanje, ki pripelje do hitrejˇsega algoritma. V
tem primeru uredimo podnaloge naloge iskanja najcenejˇse poti med i in j na podlagi
najveˇcjega indeksa nekega vmesnega vozliˇsˇca na poti med i in j (v primeru, ko je pot
sestavljena iz ene same povezave, definiramo najveˇcji indeks vmesnega vozliˇsˇca kot
0). Na primer, na sliki 6.11 imamo med vozliˇsˇcema 1 in 4 poti 1-2-4, 1-3-4 in 1-3-5-4.
Najveˇcji indeksi vmesnih vozliˇsˇc so 2, 3 in 5, po vrsti. V tem primeru so Bellmanove
ˇ POTI
6.4. PREVEDBA 0-1 NAHRBTNIKA NA NAJCENEJSE
inA
Tin
151
inB (inA )
MB
outA (inA )
Tout
outB (inB (inA ))
Slika 6.15: Prevedba problema A na problem B
enaˇcbe
uhij =
cij
h−1
h−1
min{uh−1
ij , uih + uhj }
pri h = 0;
sicer
(6.13)
in dokonˇcne vrednosti najcenejˇsih poti, uij , dobimo kot unij .
Porabo ˇcasa ocenimo tako, da preˇstejemo ˇstevilo operacij minimalizacije. Pri vsaki
vrednosti 0 < h ≤ n izraˇcunamo n2 vrednosti uhij , za katere porabimo konstanten ˇcas.
Torej je celotni ˇcas Θ(n3 ).
6.4
Prevedba 0-1 nahrbtnika na najcenejˇ
se poti
Lahko pokaˇzemo, da je problem najcenejˇsih poti v nekem smislu najteˇzji v svojem
razredu. To utemeljimo tako, da pokaˇzemo, da si lahko pri reˇsitvi drugih problemov
pomagamo z algoritmom, ki reˇsuje problem najcenejˇsih poti. Namreˇc, teˇzko si je
predstavljati, da bi bil problem B laˇzji od problema A, obenem pa bi lahko A reˇsili,
ˇce poznamo naˇcin reˇsevanja problema B. Zaenkrat je pojem “pomagamo” ˇse nekoliko
nenatanˇcen, zato ga bomo doloˇcili nekoliko natanˇcneje.
Podana sta problema A in B, ki sta opisana s svojimi vhodnimi podatki inA in
inB (gl. sliko 6.15). Za vsak problem je moˇznih neskonˇcno vhodnih podatkov, kot
npr. v primeru najcenejˇsih poti, ko je problem moˇzno postaviti za najrazliˇcnejˇse grafe
in cene povezav. Problema A in B imata reˇsitvi outA (inA ) in outB (inB ) (na ta naˇcin
nakaˇzemo, da je reˇsitev odvisna od vhodnih podatkov). Pravimo, da A prevedemo
na B (ali, da si pri reˇsitvi A pomagamo z B), ˇce obstajata transformaciji Tin in
Tout , tako da Tin spremeni inA v inB (inA ) (zopet smo nakazali, da so podatki, ki jih
transformacija sestavi, odvisni od podatkov inA ), Tout pa spremeni outB (inB (inA )) v
outA . Dodaten pogoj je, da sta transformaciji Tin in Tout razmeroma preprosti, tako
da je skoraj celotno delo pri reˇsevanju A odvisno od raˇcunskega napora pri reˇsevanju
B. V veˇcje podrobnosti se ne bomo spuˇsˇcali.
Najpreprostejˇsi primer opisanega postopka je prevedba problema najdraˇzje poti
skozi graf na problem najcenejˇse poti. Torej ˇzelimo poiskati najdraˇzjo pot od zaˇcetnega
vozliˇsˇca v grafu do vseh ostalih (problem A), imamo pa na razpolago algoritem, ki zna
poiskati najcenejˇso pot (problem B). Kako lahko uporabimo algoritem za problem B
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
152
xs
x01
0
x02
0
c2
0
...
xt
0
c3
c1
..
.
.. xv2 2
.
0
..
. x
xv1 111
0
..
.
xv1 +v2 ,2
..
. c2
xv1
0
xv2
0
c2
..
.
x0n
0
c2
xW 1
xvn
0
...
0
c3
xv+v2 ,2
..
.
0
xW n
xW 2
0
..
.
0
...
0
Slika 6.16: Graf, ki ustreza sploˇsnemu problemu 0-1 nahrbtnika.
za reˇsevanje problema A? V tem primeru so podatki inA ter inB , podatki o grafih
in cenah povezav. Za reˇsitev problema A z algoritmom za B zadostuje, da Tin vse
cene povezav negira, Tout pa vse vrednosti ui ponovno negira. V tem primeru bo
najcenejˇsa pot problema B ustrezala najdraˇzji poti problema A. Ta preprosti primer
tudi nekoliko daje obˇcutek, kaj smo mislili s pogojem, da morata Tin in Tout biti
enostavni operaciji.
Netrivialen primer istega postopka predstavlja prevedba problema 0-1 nahrbtnika
ˇ je podan problem nahrbtnika s ˇstevilom predmetov n,
na problem najdraˇzje poti. Ce
vektorjema v (prostornin predmetov) in c (cen predmetov) ter prostorsko omejitvijo
W , bomo opisali transformacijo Tin , ki spremeni opis nahrbtnika v opis grafa G =
hV, Ei s cenami povezav cij , pri i, j ∈ V tako, da bo najdraˇzja pot od zaˇcetnega
vozliˇsˇca v G do nekega posebnega konˇcnega vozliˇsˇca enoliˇcno doloˇcala reˇsitev problema
nahrbtnika. Privzetek, iz katerega izhajamo, je, da so vse prostornine celoˇstevilˇcne.
Oˇcitno se tudi primer poljubnih racionalnih prostornin da prevesti na to obliko tako,
da vse prostornine pomnoˇzimo z najmanjˇsim skupnim mnogokratnikom imenovalcev
ˇstevil, ki predstavljajo vrednosti prostornin. Graf G definiramo tako, da je V =
153
6.5. POVZETEK OSNOVNIH POJMOV
xs
x01
x02
0
3
x11
0
x12
x22
x31
0
2
x41
0
x13
0
1
x33
0
0
x43
0
0
x23
0
x42
xt
0
0
6
x24
0
x34
6
0
x25
0
x35
0
0
1
0
0
x15
x14
1
4
2
4
x32
x05
0
1
4
0
x04
0
0
2
x21
x03
0
x44
x45
0
Slika 6.17: Primer prevedbe za konkretni problem 0-1 nahrbtnika (6.14)
{xs , xt } ∪ {xij | 0 ≤ i ≤ W, 1 ≤ j ≤ n}, E pa vsebuje, prviˇc, dve povezavi, ki izvirata
pri xs ; ena s ceno 0 do vozliˇsˇca x01 in druga s ceno c1 do vozliˇsˇca xv1 ,1 , drugiˇc V + 1
povezav s ceno 0, ki izvirajo pri vozliˇsˇcih xin , 0 ≤ i ≤ W in vodijo do xt in konˇcno
povezave, ki vodijo iz vozliˇsˇc xij , 0 ≤ i ≤ W, 1 ≤ j ≤ n − 1, in sicer tako, da iz vsakega
izhajata dve povezavi, ena do vozliˇsˇca xi,j+1 s ceno 0 in druga do vozliˇsˇca xi+vj+1 ,j+1
s ceno cj . Graf G je shematiˇcno prikazan na sliki 6.16.
ˇ kot konkreten zgled vzamemo naslednji problem 0-1 nahrbtnika:
Ce
W = 4,
v1 = 1, v2 = 2, v3 = 2, v4 = 1, v5 = 3,
c1 = 3, c2 = 2, c3 = 4, c4 = 1, c5 = 6,
(6.14)
dobimo kot rezultat opisane transformacije graf, ki je prikazana na sliki 6.17.
6.5
Povzetek osnovnih pojmov
1. Razlika med dinamiˇcnim programiranje in rekurzivnim razcepom
2. Tipiˇcne naloge, ki jih reˇsujemo z dinamiˇcnim programiranjem
3. 0-1 nahrbtnik. Bellmanova enaˇcba. OKN funkcija
4. Najcenejˇse poti v grafih. Razliˇcne vrste nalog najcenejˇsih poti
5. Bellmanove enaˇcbe pri problemu najcenejˇsih poti. Osnovni privzetek za uporabnost
Bellmanovih enaˇcb. Zakaj ni moˇzno iz Bellmanovih enaˇcb neposredno pridobiti algoritma za reˇsevanje problema
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
154
−6
1
1
3
2
2 −4
3
3
9
4
3
2
1
5
1
6
5
2
6 8
6
4
9
2
3
(a) Graf brez ciklov
1
10
4
3
1
3
2
5
6
4
(b) Graf s pozitivnimi povezavami
Slika 6.18: Dva grafa
6. Najcenejˇsa pot od zaˇcetnega vozliˇsˇca do vseh ostalih v acikliˇcnem grafu
7. Dijkstrov algoritem
8. Bellman-Fordov algoritem in posploˇseni Bellman-Fordov algoritem. Uˇcinkovita izvedba slednjega algoritma
9. Floyd-Warshallov algoritem
10. Prevedba 0-1 nahrbtnika na najcenejˇse poti.
6.6
Naloge
1. Naj bodo povezave nekega grafa podane z matriko




A=
0
∞
∞
∞
∞
−1
0
∞
0
0
3
5
0
−1
0
∞
6
∞
0
−1
6
8
10
∞
0





in naj bodo najcenejˇse poti od zaˇcetnega vozliˇsˇca, u1 = 0, u2 = −1, u3 = 3, u4 = 5 in
u6 = 6. Sestavite drevo najcenejˇsih poti.
2. Poiˇsˇcite reˇsitev problema najcenejˇsih poti od vozliˇsˇca 1 do vseh ostalih za acikliˇcen
graf na sliki 6.18a.
3. Uporabite Dijsktrov algoritem na grafu na sliki 6.18b.
4. Naj bodo povezave nekega grafa podane z matriko
 0
 ∞
 ∞

A=
 ∞
 ∞

∞
∞
∞
0
9
4
0
−1
4
4
−1
0
0
1
−1
3
10
−3
8
0
2
3
∞
3
2
3
8
0
2
∞
∞
11
2
6
3
0
2
∞
0
1
3
−1
0
0




.



Poiˇsˇcite najcenejˇse poti od vozliˇsˇca 1 do vseh ostalih z Bellman-Fordovo metodo.
6.6. NALOGE
155
5. Uporabite “matriˇcno mnoˇzenje” (posploˇseno Bellman-Fordovo metodo) na grafu na
sliki 6.18b.
6. Uporabite Floyd-Warshallov algoritem na grafu na sliki 6.18b.
156
ˇ
POGLAVJE 6. DINAMICNO
PROGRAMIRANJE
Poglavje 7
SESTOPANJE
7.1
Uvod
Sestopanje je primerno, ko v neki mnoˇzici moˇznih reˇsitev iˇsˇcemo eno ali veˇc reˇsitev, za
katere je znaˇcilno, da jih je moˇzno sestaviti z zaporednimi koraki, pri ˇcemer na vsakem
koraku lahko ugotovimo, ali smo na pravi poti (ali je delna reˇsitev “dopustna”). Ko
na nekem koraku izˇcrpamo vsa moˇzna nadaljevanja, ne da bi dosegli ˇzeleni cilj, zadnji
korak trenutne reˇsitve podremo (“sestopimo”) in nadaljujemo od prejˇsnjega koraka v
drugi smeri.
Izraz “sestopanje” izvira iz prispodobe drevesa:
reˇsitve si predstavljamo, kot da so urejene v drevesno
strukturo, pri ˇcemer nasledniki nekega vozliˇsˇca predstavljajo moˇzne alternative na nekem koraku. Torej
“sestopimo”, ko pri nekem vozliˇsˇcu ugotovimo, da ne
moremo nadaljevati s “plezanjem” do konˇcne reˇsitve
in se spustimo po isti poti do predhodnega vozliˇsˇca
(gl. sliko 7.1).
Glede na to, da je metoda sestopanja najmanj
uˇcinkovita (beri: najpoˇcasnejˇsa) med vsemi metodami sestavljanja algoritmov, ki smo jih obravnavali, se k njej zatekamo le takrat, ko nobena druga
ni uporabna in ko moramo preprosto preizkusiti vse
moˇznosti. Njena prednost pa je v tem, da je raz- Slika 7.1: Plezanje po drevesu
meroma enostavna za realizacijo in ne potrebuje po- in sestopanje
globljenega poznavanja problema, ki ga reˇsujemo. Iz
pravkar zapisane pripombe sledi, da jo lahko uporabljamo na zaˇcetku raziskav nekega problema, kasneje, ko problem bolje spoznamo, pa
morebiti odkrijemo kakˇsno uˇcinkovitejˇso reˇsitev.
Metodo bomo prikazali na nekaj znaˇcilnih in dobro znanih problemih.
157
158
POGLAVJE 7. SESTOPANJE
1
2
4
4
5
6
7
8
9
11
11
12
13
14
15
PROCEDURE poskus(i: INTEGER);
BEGIN izbira prvega koraka na seznamu moˇznih;
REPEAT
IF korak dopusten THEN
zapiˇsi ga ;
IF ni ˇse konec THEN
poskus(i+1) ;
IF izid neuspeˇsen THEN sestop END
ELSE zapiˇsi “izid uspeˇsen”
END
END;
izbira naslednjega koraka
UNTIL izid uspeˇsen
OR (konec seznama moˇznih korakov )
END poskus ;
Slika 7.2: Vzorec za osnovno proceduro sestopanja
7.2
Problem skakaˇ
cevega obhoda
Problem opiˇsemo takole: podana je ˇsahovska deska velikosti n × n (obiˇcajno je n = 8,
vendar ima lahko n tudi drugaˇcno vrednost) in skakaˇc, ki se premika na obiˇcajen
naˇcin. Na primer, moˇzne poteze skakaˇca, ki je postavljen na polje, ki je oznaˇceno z
ˇ skakaˇca postavimo na polje hi, ji,
“∗”, so na sliki 7.3 prikazane s ˇstevilkami 0-7. Ce
2
je naloga poiskati zaporedje n − 1 skakaˇcevih potez, s katerimi le-ta obiˇsˇce vsa polja
in seveda vsako polje le enkrat (gl. tudi nalogo 2).
Pri sestavljanju algoritma, ki realizira metodo sestopanja, moramo najprej izbrati pri7
merne podatkovne strukture za problem, ki ga
0
7
6
reˇsujemo. Ko je ta del naloge opravljen, se lotimo
1
6
5
samega algoritma. Algoritem obiˇcajno vsebuje
∗
4
neko osrednjo proceduro, ki izvaja “poskuse”,
3
5
2
pridobimo pa jo iz osnovnega vzorca, ki je pri2
4
3
kazan na sliki 7.2, tako da ga prilagodimo trenu1
tnemu problemu.
00 1 2 3 4 5 6 7
V primeru skakaˇcevega obhoda izberemo kot
primerno
podatkovno strukturo za predstavitev
ˇ
Slika 7.3: Sahovnica velikosti 8 × 8
ˇ
s
ahovnice
tabelo
in moˇzne poteze skakaˇca
a: ARRAY n,n OF INTEGER.
(7.1)
Njeni elementi predstavljajo obiskanost polj ˇsahovnice, in sicer tako, da z -1
oznaˇcujemo neobiskana polja, z 0 zaˇcetno polje in z i, 0 < i ≤ n2 − 1 polje, ki je
bilo obiskano na i-ti potezi.
ˇ
7.2. PROBLEM SKAKACEVEGA
OBHODA
159
Naslednja podatkovna struktura, ki jo potrebujemo, je predstavitev moˇznih skakaˇcevih potez. Kot najprimernejˇsa se izkaˇze uporaba dveh tabel, dx in dy velikosti 8, ki
podajata odmik ciljnega polja od izvornega polja po x in y oseh (gl. tudi sliko 7.3):
i
dx
dy
0
1
2
1
2
1
2
2
-1
3
1
-2
4
-1
-2
5
-2
-1
6
-2
1
7
-1
2
Sedaj bomo vse sploˇsne opise na sliki 7.2 nadomestili z elementi, ki se nanaˇsajo na problem
skakaˇcevega obhoda. Prvi na vrsti je stavek izbira prvega koraka na seznamu moˇznih. Za uresniˇcitev stavka je potrebno v proceduri poskus
deklarirati celoˇstevilˇcno spremenljivko j, ki ˇsteje
ˇstevilo opravljenih poskusov, in ji na zaˇcetku prirediti vrednost 0. Za realizacijo stavka korak dopusten je najprej potrebno definirati pojem dopustnosti. Korak je dopusten, ko ciljno polje
7
6
5
∗
4
3
2
1
00 1 2 3 4 5 6 7
ˇ
Slika 7.4: Sahovnica
velikosti 8 × 8
in moˇzne poteze dame
1. ni zunaj mej ˇsahovnice in
2. ˇse ni zasedeno.
Torej lahko ta stavek v primeru, ko sta koordinati izvornega polja podani z globalnima
spremenljivkama x in y, realiziramo kot
(x +dx [j ]≥0)&(x +dx [j ]<n)
&(y+dy[j ]≥0)&(y+dy[j ]<n)
&(a[x +dx [j ],y+dy[j ]]<0).
Stavek zapiˇsi ga realiziramo preprosto kot,
x :=x +dx [j ] ; y:=y+dy[j ] ; a[x ,y]:=i ,
ni ˇse konec pa kot i < n2 − 1. Za izid neuspeˇsen potrebujemo globalno spremenljivko
uspeh, ki ji na zaˇcetku priredimo vrednost FALSE. V tem primeru se izid neuspeˇsen
prevede preprosto na ∼uspeh. sestop se prevede na zaporedje,
a[x ,y]:=−1 ; x :=x −dx [j ] ; y:=y−dy[j ],
zapiˇsi “izid uspeˇsen” na uspeh := TRUE, stavek izid uspeˇsen na uspeh in konec seznama moˇznih korakov na j = 8.
Popoln program za skakaˇcev obhod, ki smo ga pravkar razvili in ki vsebuje tudi
zaˇcetna prirejanja ter izpis rezultata, je prikazan kot program 7.1.
160
POGLAVJE 7. SESTOPANJE
Program 7.1: Skakaˇ
cev obhod
1
3
3
4
5
6
8
8
9
10
11
12
14
14
15
17
17
18
19
21
22
22
24
24
25
26
28
28
29
30
32
32
33
34
35
36
38
38
40
40
41
42
43
45
MODULE Skakac;
CONST
n=8;
x0 =1;
y0 =1;
VAR
a: ARRAY n,n OF INTEGER;
dx ,dy: ARRAY 8 OF INTEGER;
x ,y : INTEGER;
uspeh: BOOLEAN ;
PROCEDURE Inita;
VAR i,j :INTEGER;
BEGIN
FOR i:=0 TO n−1 DO
FOR j :=0 TO n−1 DO
a[i,j ]:=−1
END
END
END Inita;
PROCEDURE poskus(i: INTEGER);
VAR j : INTEGER;
BEGIN j :=0;
REPEAT
IF (x +dx [j ]>=0)&(x +dx [j ]<n)
&(y+dy[j ]>=0)&(y+dy[j ]<n)
&(a[x +dx [j ],y+dy[j ]]<0)
THEN
x :=x +dx [j ] ; y:=y+dy[j ] ; a[x ,y]:=i ;
IF i < n∗n−1 THEN
poskus(i+1) ;
IF ∼uspeh THEN
a[x ,y]:=−1 ; x :=x −dx [j ] ; y:=y−dy[j ]
END
ELSE uspeh:=TRUE
END
END;
INC (j )
UNTIL uspeh OR (j =8)
END poskus ;
se nadaljuje
7.3. PROBLEM OSMIH DAM
161
Skakaˇ
cev obhod (nadaljevanje)
45
47
47
48
49
50
51
52
53
54
56
56
57
58
59
60
62
63
63
65
66
66
67
68
69
70
71
72
74
74
PROCEDURE Izpis;
BEGIN
Out.String(“PROBLEM SKAKACEVEGA OBHODA”);
Out.WrLn;
Out.String(“Zacetna x−koordinata: ”);
Out.Int(x0 );
Out.String(“Zacetna y−koordinata: ”);
Out.Int(y0 );
Out.WrLn;
IF ∼uspeh THEN Out.String(“Ni resitve”)
ELSE
FOR i:=7 STEP −1 TO 0 DO
FOR j :=0 TO 7 DO
Out.Int(a[i,j ]);Out.String(“;”)
END;
Out.WrLn
END
END
END Izpis;
BEGIN
dx [0]:=1; dx [1]:=2; dx [2]:=2; dx [3]:=1;
dx [4]:=−1; dx [5]:=−2; dx [6]:=−2; dx [7]:=−1;
dy[6]:=1; dy[7]:=2; dy[0]:=2; dy[1]:=1;
dy[2]:=−1; dy[3]:=−2; dy[4]:=−2; dy[5]:=−1;
x :=x0 ; y:=y0 ; uspeh:=FALSE ; Inita;
a[x ,y]:=0;
poskus(1);
Izpis
END Skakac.
Skakaˇ
cev obhod (konec)
7.3
Problem osmih dam
Problem osmih dam se prav tako kot predhodni problem nanaˇsa na podroˇcje ˇsaha,
lahko pa ga uporabimo za to, da poudarimo nek pomemben vidik tehnike sestopanja.
Kot smo ˇze omenili, je metoda sestopanja ˇcasovno potratna in pogosto se izkaˇze, da
za doseganje praktiˇcno uporabnih rezultatov razpoloˇzljiv raˇcunalnik komaj zadostuje.
Zaradi tega je potrebno pri tej metodi biti ˇse posebno pozoren na uˇcinkovitost operacij,
ki se najpogosteje izvajajo, saj je od tega lahko odvisno, ali bomo dosegli praktiˇcno
uporaben rezultat.
Zopet imamo ˇsahovnico velikosti n × n, na katero je sedaj potrebno postaviti n
ˇsahovskih dam tako, da nobena ne napada druge. Spomnimo se, da se v ˇsahu dama
162
POGLAVJE 7. SESTOPANJE
PROCEDURE dopustno(x ,y:INTEGER): BOOLEAN ;
(∗ Preverjanje dopustnosti postavitve dame na polje (x ,y) ∗)
VAR i: INTEGER;
BEGIN
(∗ Preverjamo le polja z absciso, i < x ∗)
(∗ preizkus, ali je vrstica dopustna ∗)
i:=0; WHILE (i < x ) & (a[i,y] = 0) DO INC (i) END;
IF i < x THEN RETURN FALSE END;
(∗ dopustnosti stolpca ni potrebno preverjati, ker damo vedno postavimo
v prazen stolpec ∗)
(∗ preizkus, ali je diagonala, ki se spuˇsˇca od leve proti desni, dopustna ∗)
i:=0; WHILE (i < x ) & (a[x −i−1,y+i+1] = 0) DO INC (i) END;
IF i < x THEN RETURN FALSE END;
(∗ preizkus, ali je diagonala, ki se dviga od leve proti desni, dopustna ∗)
i:=0; WHILE (i < x ) & (a[x −i−1,y−i−1] = 0) DO INC (i) END;
RETURN i = x
END dopustno;
Slika 7.5: Predikat dopustno pri problemu osmih dam in predstavitvi ˇsahovnice s
tabelo (7.1)
premika, oziroma napada po vrsticah, stolpcih in dveh vrstah diagonal (gl. sliko 7.4).
Problem bomo zopet reˇsevali s sestopanjem. V proceduri poskus na sliki 7.2 se
sedaj parameter i nanaˇsa na postavitev dame v i-ti stolpec. Torej bomo na prvem
koraku damo postavili v 1. stolpec, na drugem v 2. stolpec itn. do n-tega koraka.
Pri tem problemu je zanimiva izbira podatkovne strukture za ˇsahovnico. Na podlagi izkuˇsenj s problemom skakaˇcevega obhoda bi bila prva misel ponovno uporabiti
podatkovno strukturo (7.1). V takem primeru bi lahko prisotnost dame na polju hx, yi
oznaˇcili z 1, nezasedenost polja pa z 0. Predikat dopustno(x, y) (ko je dama na polju
z absciso x in ordinato y) je pri tej predstavitvi prikazan na sliki 7.5. Izkaˇze pa se, da
predikat dopustno lahko mnogo uˇcinkoviteje realiziramo, ˇce uporabljamo podatkovne
ˇ
strukture, ki neposredno vsebujejo informacijo o prostih vrsticah in diagonalah. Ce
v ta namen uporabljamo naslednje podatkovne strukture:
prVrst: ARRAY n OF BOOLEAN ; (∗ nezasedenost vrstic ∗)
prDgRzlXY :ARRAY 2∗n−1 OF BOOLEAN ; (∗ nezasedenost diagonal s konstantno
razliko komponent; indeks diagonale je x − y + n − 1 ∗)
prDgVstXY :ARRAY 2∗n−1 OF BOOLEAN ; (∗ nezasedenost diagonal s konstantno
vsoto komponent; indeks diagonale je x + y ∗)
in jim priredimo vrednost vsakiˇc, ko postavimo neko damo, porabi predikat dopustno
mnogo manj ˇcasa:
163
7.4. PROBLEM TRDNIH ZAKONOV
j := 0
izbira prvega
koraka
korak dopusten
prVrst[j]
& prDgRzlXY [i − j + n − 1]
& prDgVstXY [i + j]
polozajDame[i] := j;
prVrst[j] := FALSE ;
prDgRzlXY [i − j + n − 1] := FALSE ;
prDgVstXY [i + j] := FALSE ;
i<n
∼uspeh
prVrst[j] := TRUE ;
prDgRzlXY [i − j + n − 1] := TRUE ;
prDgVstXY [i + j] := TRUE ;
uspeh := TRUE
zapiˇsi ga
ni ˇse konec
izid neuspeˇsen
sestop
zapiˇsi
“izid uspeˇsen”
izbira naslednjega
koraka
konec seznama
moˇznih korakov
INC (j)
j=n
Slika 7.6: Zamenjave v vzorcu na sliki 7.2 pri problemu osmih dam
w
m0
w0
m
Slika 7.7: Zakon med m in w ni trden
PROCEDURE dopustno(x ,y);
BEGIN
RETURN prVrst[y] & prDgRzlXY [x −y+n−1] & prDgVstXY [x +y]
END dopustno;
(x in y, koordinati dame, ki jo nameravamo postaviti na ˇsahovnico, sta pravzaprav
enaki vrednostim spremenjlivk i in j v proceduri poskus).
Za konec obravnave problema osmih dam je na sliki 7.6 prikazana tabela zamenjav
v vzorcu procedure poskus s slike 7.2, s katerimi ga priredimo za problem osmih dam.
164
7.4
POGLAVJE 7. SESTOPANJE
Problem trdnih zakonov
Na koncu bomo opisali ˇse en problem, ki ga reˇsujemo s sestopanjem, pripada pa
druˇzini problemov, ki ima precejˇsen praktiˇcen pomen. Gre za probleme prirejanja
(angl. matching), katerih tipiˇcen (ˇceprav ne dobesedno praktiˇcno pomemben) predstavnik je problem trdnih zakonov: je n ˇzensk in prav toliko moˇskih, ki imajo predstavnike nasprotnega spola razvrˇsˇcene po naklonjenosti (do prve(ga) ˇcuti najveˇcjo
naklonjenost). Naloga je poiskati n “trdnih zakonov”, pri ˇcemer je zakon med ˇzensko
w in moˇskim m netrden takrat, ko bodisi obstaja moˇski m0 , ki je poroˇcen z w0 , in ima
w raje kot svojo ˇzeno w0 , obenem pa ima tudi w raje m0 kot svojega moˇza m, ali pa
obstaja ˇzenska w00 , ki je poroˇcena z m00 , in ima raje m kot svojega moˇza m00 , obenem
pa ima tudi m raje w00 kot svojo ˇzeno w (gl. sliko 7.7).
ˇ so vrstni redi pripadnikov nasprotnega spola po naklonjenosti taki,
7.1 Primer Ce
kot jih kaˇze naslednja tabela:
NAKLONJENOST
ˇ
ˇ
ZENSK
DO MOSKIH
w1 1 2 3
w2 2 3 1
w3 3 2 1
NAKLONJENOST
ˇ
ˇ
MOSKIH
DO ZENSK
m1 2 3 1
m2 1 2 3
m3 3 1 2
seznam zakonov
hw1 , m3 i, hw2 , m2 i, hw3 , m1 i
ni trden, ker pri zakonu hw1 , m3 i obstaja moˇski m2 , ki ima w1 raje kot svojo ˇzeno
w2 , obenem pa ima w1 raje m2 kot svojega moˇza m3 . 2
Problem lahko ponovno reˇsimo z ustreznimi zamenjavami v vzorcu na sliki 7.2.
Zaˇcetni podatki so podani z dvema tabelama, nklMpriZ in nklZpriM tako, da je
nklMpriZ [i, j] indeks moˇskega, ki je na i-tem mestu na seznamu naklonjenosti ˇzenske
j (in z nasprotnima vlogama moˇskih in ˇzensk pri drugi tabeli). Podobno kot pri problemu osmih dam je kljuˇc do uˇcinkovite reˇsitve izbira primernih podatkovnih struktur,
ki zmanjˇsujejo obseg raˇcunanja znotraj osnovne procedure poskus. Najprej se lotimo
osnovne zgradbe problema. Reˇsujemo ga tako, da izberemo bodisi ˇzenske ali moˇske in
pri vsakem klicu procedure poskus poskuˇsamo poroˇciti naslednjega pripadnika izbrane
skupine z nekim predstavnikom nasprotnega spola. Prva (ˇse ne dokonˇcna) razliˇcica
procedure poskus je prikazana na sliki 7.8. V tej razliˇcici predstavlja i i-to ˇzensko (i
bi prav tako lahko predstavljal moˇskega), tabela logiˇcnih vrednosti jeSamski pa vodi
evidenco o neporoˇcenih moˇskih (v primeru, ko bi i predstavljalo moˇske, bi uporabljali
tabelo jeSamska). Tabela moz rabi za izpis konˇcne reˇsitve (moz[i] predstavlja moˇza
ˇzenske i). Predikat Trden pa je zaenkrat ˇse nedoloˇcen. Na podlagi prej zapisane
definicije lahko zapiˇsemo njegovo prvo razliˇcico v obliki, ki je prikazana na sliki 7.9.
Oˇcitno je uˇcinkovitost procedure na sliki 7.9 odvisna od hitrosti raˇcunanja predikatov
m je poroˇcen in ima raje i kot svojo ˇzeno in z je poroˇcena in ima raje j kot svojega
165
7.4. PROBLEM TRDNIH ZAKONOV
izbira prvega
koraka
korak dopusten
zapiˇsi ga
ni ˇse konec
izid neuspeˇsen
sestop
zapiˇsi
“izid uspeˇsen”
izbira naslednjega
koraka
konec seznama
moˇznih korakov
j := 0
jeSamski [j]
& Trden(i, j)
jeSamski [j] := F ALSE;
moz [i] := j
i<n
∼uspeh
jeSamski [j] := T RU E;
uspeh := TRUE
INC (j)
j=n
Slika 7.8: Zamenjave v vzorcu na sliki 7.2 za problem trdnih zakonov
PROCEDURE Trden(i,j :INTEGER):BOOLEAN ;
VAR x ,m,z :INTEGER;
BEGIN x :=0;
m:=nklMpriZ [x ,i];
WHILE m # j DO
IF m je poroˇcen in ima raje i kot svojo ˇzeno
THEN RETURN FALSE
END;
INC (x ) ;
m:=nklMpriZ [x ,i]
END;
x :=0;
z :=nklZpriM [x ,j ];
WHILE z # i DO
IF z je poroˇcena in ima raje j kot svojega moˇza
THEN RETURN FALSE
END;
INC (x ) ;
z :=nklZpriM [x ,j ]
END ;
RETURN TRUE
END Trden;
Slika 7.9: Preverjanje trdnosti zakona
166
POGLAVJE 7. SESTOPANJE
ˇ uporabljamo tabeli idxZpriM [i, j] (indeks ˇzenske i na seznamu moˇskega j)
moˇza. Ce
ter idxMpriZ [i, j] (indeks moˇskega i na seznamu ˇzenske j), ki ju lahko izraˇcunamo
pred prvim klicem procedure poskus, imata zapisana predikata vrednost
∼ jeSamski [m]
&(idxZpriM [i, m] >
idxZpriM [zena[m], m])
in
7.5
z<i
&(idxMpriZ [j, z] >
idxMpriZ [moz [z], z])
Naˇ
cini za omejevanje pretiranega razraˇ
sˇ
canja
iskalnega drevesa
Omenili smo ˇze, da je sestopanje ponavadi ˇcasovno izredno potratno, zato je za doseganje praktiˇcno uporabnih rezultatov potrebno poskrbeti za ˇcim uˇcinkovitejˇso realizacjio posameznih operacij, oziroma za odpravljanje nepotrebnih. Na zaˇcetku smo ˇze
omenili, da si lahko predstavljamo delovanje procedure poskus z drevesno strukturo,
ki predstavlja zgodovino njenih klicev. Oˇcitno lahko prihranimo ˇcas, ˇce odkrijemo
ˇ
moˇznost za izpuˇsˇcanje doloˇcenih poddreves med postopkom iskanja. Ceprav
so taki
postopki zelo odvisni od posameznega problema, bomo na tem mestu opisali nekaj
ukrepov, ki imajo ˇsirˇsi pomen.
Preurejanje iskalnih korakov. V kolikor iˇsˇcemo neko posamezno reˇsitev, je moˇzno
znotraj procedure poskus izbiro korakov preurediti tako, da na zaˇcetek zaporedja postavimo alternative, za katere je moˇzno utemeljiti, da z veˇcjo verjetnostjo pripeljejo
do reˇsitve. Takrat, ko so koraki, ki vodijo do reˇsitve, neodvisni, je moˇzno preurejanje
uporabiti tudi na celotnem zaporedju korakov.
7.2 Primer Vzemimo za primer problem 0-1 nahrbtnika, ki ga spremenimo v toliko,
da iˇsˇcemo prvo reˇsitev z vrednostjo, ki je veˇcja od V . Seveda je ta primer s praktiˇcnega
staliˇsˇca nezanimiv, ker zanj obstajajo uˇcinkovitejˇse metode od sestopanja, vendar je
le primeren za ilustracijo pojmov, ki nas tu zanimajo. Problem reˇsimo s prilagojeno
obliko procedure poskus, ki je prikazana na sliki 7.10. Podatke o predmetih hranimo
v tabeli a z elementi, ki jim pripadata dve komponenti: .p predstavlja prostornino
predmeta, .v pa njegovo vrednost. Pri vsakem klicu procedure preverimo, ali smo
dosegli ˇzeleno vrednost in v primeru, ko nismo, ter ko vseh predmetov ˇse nismo
porabili, kakor tudi, ko je prostor ˇse na voljo, ponovno pokliˇcemo poskus z naslednjo
vrednostjo parametra ter s spremenjenima koliˇcinama p in v.
Proceduro smo preizkusili na primeru, ki je prikazan na sliki 7.11. Enkrat smo
zaporedje predmetov uredili na podlagi naraˇsˇcajoˇce vrednosti indeksov, drugiˇc pa
7.5
ˇ
OMEJEVANJE RAZRASˇCANJA
ISKALNEGA DREVESA
167
PROCEDURE poskus(i:index ;
VAR a:AObj ; (∗ predmeti ∗)
p, (∗ trenutna prostornina ∗)
v , (∗ trenutna vrednost ∗)
V , (∗ iskana vrednost ∗)
P , (∗ prostorninska omejitev ∗) :INTEGER;
VAR set (∗ trenutna mnoˇzica ∗):SET ) :BOOLEAN ;
(∗ Iˇsˇcemo prvo reˇsitev z vrednostjo ≥ cilj ∗)
BEGIN INC (stKlicev );
IF v ≥ V THEN RETURN TRUE
ELSIF i>n THEN RETURN FALSE
ELSE
(∗ najprej predmet i poskuˇsamo vkljuˇciti ∗)
IF p+a[i].p<=P THEN
INCL(s,i);
IF poskus(i+1,a,p+a[i].p,v +a[i].v ,V ,P ,s)
THEN RETURN TRUE
ELSE EXCL(s,i)
END
END ;
(∗ . . . nato izkljuˇciti ∗)
RETURN poskus(i+1,a,p,v ,V ,P ,s)
END
END poskus ;
Slika 7.10: Procedura poskus za spremenjeni problem 0-1 nahrbtnika
na podlagi padajoˇce vrednosti predmetov (in v primeru iste vrednosti na podlagi
padajoˇce prostornine). Elementi tabele na sliki 7.11, ki se nanaˇsajo na prvo urejenost,
imajo znak ∗, tisti, ki se nanaˇsajo na drugo urejenost, pa znak +. V tabeli je pri
hitrosti jasno razvidna rahla prednost druge urejenosti.
Glede na to, da postopek sestopanja iˇsˇce primerno reˇsitev problema s pregledovanjem
neke drevesne strukture, lahko ˇcas postopka skrajˇsamo, ˇce pred obiskom nekega poddrevesa ugotovimo, ali je neobetavno in se v takem primeru obisku izognemo. Metode
za odkrivanje neobetavnih poddreves so moˇcno odvisne od posameznega problema,
zato je teˇzko podati neka sploˇsno veljavna navodila, vendar lahko nekatere znaˇcilnosti
tega pristopa prikaˇzemo na primeru skakaˇcevega obhoda.
Na zaˇcetku poglavja smo razvili popoln program za skakaˇcev obhod (gl. program
7.1). Program deluje tako, da sistematiˇcno preizkuˇsa vse moˇzne poteze skakaˇca,
ˇ
dokler ne obiˇsˇce vseh polj ˇsahovnice (ali pa dokler ne izˇcrpa vseh moˇznosti). Ce
program dopolnimo tako, da iˇsˇce reˇsitve za vse moˇzne zaˇcetne poloˇzaje skakaˇca in
za vse velikosti ˇsahovnice do neke zgornje meje, dobimo pri vrednosti zgornje meje 6
rezultat, ki je prikazan na sliki 7.12. Iz slike je razvidno, da najveˇcje ˇstevilo klicev
procedure poskus (in z njim tudi ˇcas) strmo naraˇsˇca tako, da je za praktiˇcno zanimiv
168
POGLAVJE 7. SESTOPANJE
predmet ˇst.
vrednost
prostornina
1
7
4
2
6
5
ˇ
PORABA CASA
PRI DVEH
N
V
P
ˇst.:1
2
∗
+
3
4 11 10
+
+
5
4 22 20
+
+
7
5 33 30
+
+
8
6 44 40
+
+
9
8 55 50
+* +
11 10 66 60
+* +*
3
4
3
4
6
4
5
8
6
6
10
5
7
9
6
8
6
7
9
8
7
10
9
5
UREJENOSTIH ISKALNIH KORAKOV
3
4
5
6
7
8
9 10
pripadnost iskani mnoˇzici
*
*
+
+
*
*
*
+
+
+
+*
*
*
*
+
+
+* +* +*
*
*
+
+
+* +* +* +*
*
*
+
+* +* +* +* +* +* +*
N : ˇstevilo klicev procedure poskus;
V : minimalna iskana vrednost nahrbtnika;
P : prostorninska omejitev;
+ se nanaˇsa na urejenost 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
∗ pa na urejenost 6, 7, 10, 9, 5, 1, 8, 2, 4, 3
Slika 7.11: Rezultat delovanja procedure poskus na sliki 7.10
n
3
4
5
6
m
0
0
13
36
Nmax 15 2,223 1,829,421 5,224,517,158
Nmin
1 1,501
40
2,253
Navg
13 1,873
814,653
243,235,490
n, velikost ˇsahovnice
m, ˇstevilo zaˇcetnih poloˇzajev, pri katerih obstaja
reˇsitev
ˇstevilo klicev procedure poskus pri nekem zaˇcetnem
poloˇzaju:
Nmax , najveˇcje
Nmin , najmanjˇse
Navg , povpreˇcno
Slika 7.12: Podatki o delovanju programa za problem skakaˇcevega obhoda pri velikosti
ˇsahovnice med 3 in 6
7.5
ˇ
OMEJEVANJE RAZRASˇCANJA
ISKALNEGA DREVESA
1
2
3
4
5
6
7
8
9
10
11
12
13
15
15
17
18
18
19
20
169
PROCEDURE poskus(i: INTEGER);
VAR j : INTEGER; ch:CHAR;
BEGIN INC (stKlicev ); j :=0;
REPEAT INC (j );
IF stKlicev =preveri THEN stKlicev :=0; slpUl (n,slMeja) END;
IF (x +dx [j −1]≤n)&(x +dx [j −1]≥1)
&(y+dy[j −1]≤n)&(y+dy[j −1]≥1)
&(a[x +dx [j −1]−1,y+dy[j −1]−1]<0)
&(slMeja≥i−1)
THEN INC (x ,dx [j −1]); INC (y,dy[j −1]); a[x −1,y−1]:=i ;
IF i < n∗n−1 THEN poskus(i+1) ;
IF ∼uspeh THEN
a[x −1,y−1]:=−1; DEC (x ,dx [j −1]); DEC (y,dy[j −1])
END
ELSE uspeh:=TRUE
END
END
UNTIL uspeh OR (j =8);
IF slMeja=i−1 THEN slMeja:=MAX (INTEGER) END
END poskus ;
Slika 7.13: Procedura poskus, ki uporablja ugotavljanje slepih ulic
primer n = 8 ˇze zunaj dosega osebnega raˇcunalnika (danes, leta 1997).
Odkrivanje neobetavnih poddreves. Odkrivanja neobetavnih poddreves se lotimo tako, da razmislimo, kdaj v neki smeri ni moˇzno napredovati do
23
37
reˇsitve. En primer nastopi takrat, ko obstaja neza47
42
sedeno polje, iz katerega ni moˇzno priti s skakaˇcem
-1
do drugega nezasedenega polja, razen ko je v dosegu
35
11
skakaˇca neko polje, ki ima oznako n2 − 2, kar pomeni,
21
17
da je opazovano nezasedeno polje cilj zadnje poteze.
V kolikor na ta naˇcin ugotovimo, da je trenutna smer
napredovanja neobetavna, lahko reˇsitev podremo (se- Slika 7.14: Skakaˇcev obhod:
stopimo) vsaj do poteze z indeksom, ki je enak najviˇsji sestopimo lahko vsaj do pooznaki nekega polja v dosegu skakaˇca iz opazovanega teze 47
ˇ opisano analizo opravimo za
polja (gl. sliko 7.14). Ce
vsa nezasedena polja, lahko trenutno reˇsitev podremo do minimalnega indeksa, ki ga
dobimo s tem izraˇcunom.
Procedura poskus, ki je sestavljena po tem receptu, je prikazana na sliki 7.13.
Deluje tako, da na vsak preveri klic pokliˇce proceduro za ugotavljanje “slepe ulice”
ˇ je postopek v slepi ulici v opisanem pomenu, priredimo
(poddrevo je neobetavno). Ce
spremenljivki slMeja vrednost indeksa poteze, do katere je moˇzno trenutno reˇsitev
170
POGLAVJE 7. SESTOPANJE
1
2
3
4
5
6
7
8
9
11
11
12
13
15
16
17
17
18
20
21
22
23
23
PROCEDURE slpUl (n:INTEGER;VAR mm:INTEGER) ;
VAR h,i,j ,k ,m:INTEGER;
BEGIN mm:=MAX (INTEGER);
FOR i:=1 TO n DO
FOR j :=1 TO n DO
IF a[i−1,j −1]=−1 THEN h:=0; m:=−1;
FOR k :=1 TO 8 DO
IF (i+dx [k −1]≥1)&(i+dx [k −1]≤n)
&(j +dy[k −1]≥1)&(j +dy[k −1]≤n)
THEN
IF a[i+dx [k −1]−1,j +dy[k −1]−1]=−1 THEN INC (h)
ELSIF a[i+dx [k −1]−1,j +dy[k −1]−1]>m THEN
m:=a[i+dx [k −1]−1,j +dy[k −1]−1]
END
END
END
END;
IF (h=0)&(m # n∗n−2)&(mm > m) THEN mm:=m END
END
END
END
END
END slpUl ;
Slika 7.15: Procedura za ugotavljanje slepih ulic
n
3
4
5
6
Nmax 15 2,223 1,815,772 2,815,100,202
Nmin
1 1,501
40
2,253
Navg
13 1,873
797,527
131,451,996
NB
0
0
123
217,674
n, velikost ˇsahovnice
m, ˇstevilo zaˇcetnih poloˇzajev, pri katerih obstaja
reˇsitev
ˇstevilo klicev procedure poskus pri nekem zaˇcetnem
poloˇzaju:
Nmax , najveˇcje
Nmin , najmanjˇse
Navg , povpreˇcno
NB , najveˇcje ˇstevilo ugotovljenih slepih ulic
Slika 7.16: Rezultati poskusa z reˇsevanjem skakaˇcevega obhoda z ugotavljanjem slepih
ulic. Vrednost konstante preveri je 50,000
7.5
ˇ
OMEJEVANJE RAZRASˇCANJA
ISKALNEGA DREVESA
171
podreti. Na zaˇcetku je vrednost slMeja enaka MAX(INTEGER). To ima za posledico,
da se zaradi vrstice 9 na sliki 7.13 iskanje v globino ustavi in se opravi sestop do poteze
slMeja. Ko algoritem sestopi do poteze slMeja, se v vrstici 19 vrednost slMeja vrne
na MAX(INTEGER) in se postopek nadaljuje normalno. Procedura slpUl, ki odkriva
slepe ulice, je prikazana na sliki 7.15.
Kot se vidi iz primerjave tabel na slikah 7.12 in 7.16, rezultat, ki smo ga dosegli, ni
ˇ nam je cilj poiskati eno samo
zanemarljiv, vendar vseh moˇznosti ˇse nismo izˇcrpali! Ce
reˇsitev in ˇce so reˇsitve med vsemi primeri razmeroma “gosto posejane”, lahko z zanemarjanjem nekaterih reˇsitev hitrost postopka znatno izboljˇsamo. Do zanemarjanja
pride, ˇce proceduro slpUl sestavimo tako, da je nekoliko “prestroga” pri ocenjevanju poddreves in nekatera poddrevesa, ki vsebujejo reˇsitve, kljub temu razglasi za
slepe ulice. V primeru, ko je takˇsnih napaˇcno ocenjenih poddreves razmeroma malo,
njihova velikost (in s tem prihranek na hitrosti) pa velika, se to izplaˇca.
Opisano idejo bomo realizirali tako, da bomo razglasili za slepe ulice ne le poloˇzaje, ki vsebujejo nezasedena polja z niˇc sosednjimi nezasedenimi polji,
23 48 37
temveˇc tudi poloˇzaje, ki vsebujejo nezasedena polja
47
42
s samo enim nezasedenim sosedom. Na ta naˇcin si-1
cer lahko napravimo napako, kajti moˇzno je, da v
35
11
konˇcni reˇsitvi do opazovanega polja pridemo z zadnjo
17
potezo, do sosednjega (trenutno nezasedenega) polja
pa s predzadnjo, vendar je verjetnost tega majhna in
ˇce do tega pojava pride, se zanaˇsamo na eksistenco Slika 7.17: Skakaˇcev obhod:
drugih reˇsitev, pri katerih se s tem ne sreˇcujemo. To- sestopimo lahko vsaj do porej bomo sedaj v proceduri slpUl zamenjali vrstico 18 teze 48
z
IF (h=0)&(m#n∗n−2) THEN
IF mm > m THEN mm:=m END
ELSIF h=1 THEN
(7.2)
IF mm > m+1 THEN mm:=m+1 END
END
Pri ˇstevilu nezasedenih sosedov h = 1 razmiˇsljamo takole: iˇsˇcemo reˇsitev, ki zagotavlja
ˇ prekliˇcemo
obisk opazovanega polja in nato nadaljevanje do nezasedenega polja. Ce
korake, oziroma sestopimo do koraka z indeksom, ki je za ena veˇcji od najveˇcjega
indeksa nekega soseda opazovanega polja, pospeˇsimo na ta naˇcin preizkus alternative,
ki jo predstavlja poteza od najveˇcjega sosednjega indeksa do opazovanega polja (gl.
sliko 7.17). Torej je to vrednost, ki jo priredimo spremenljivki mm (v klicu procedure
slpUl je to spremenljivka slMeja).
Zapisali smo, da pri iskanju skakaˇcevega obhoda z uporabo stroˇzjega ugotavljanja
slepih ulic lahko pride do zanemarjanja doloˇcenih reˇsitev. Zaradi tega algoritma brez
ugotavljanja slepih ulic (program 7.1) ter z natanˇcnim ugotavljanjem slepih ulic (slika
7.13) v sploˇsnem poiˇsˇceta drugaˇcno reˇsitev od algoritma s stroˇzjim ugotavljanjem slepih ulic (slika 7.13 s spremembo (7.2)). Na primer, pri n = 6 in zaˇcetnih koordinatah
172
POGLAVJE 7. SESTOPANJE
n
3
4
5
6
Nmax 15 2,223 1,782,486 1,687,607
Nmin
1 1,501
40
2,253
Navg
13 1,873
706,281
492,011
NB
0
0
229
238
n, velikost ˇsahovnice
m, ˇstevilo zaˇcetnih poloˇzajev, pri katerih obstaja
reˇsitev
ˇstevilo klicev procedure poskus pri nekem zaˇcetnem
poloˇzaju:
Nmax , najveˇcje
Nmin , najmanjˇse
Navg , povpreˇcno
NB , najveˇcje ˇstevilo ugotovljenih slepih ulic
Slika 7.18: Rezultati poskusa z reˇsevanjem skakaˇcevega obhoda s stroˇzjim preverjanjem slepih ulic. Vrednost konstante preveri je 50,000
35
22
31
16
33
0
30
17
34
1
24
15
21
2
23
32
11
6
18
29
20
7
14
25
3
8
27
12
5
10
28
19
4
9
26
13
3
6
17
34
31
0
16
35
4
1
18
33
5
2
7
32
25
30
8
15
26
21
12
19
27
22
13
10
29
24
14
9
28
23
20
11
Slika 7.19: Dve razliˇcni reˇsitvi istega problema skakaˇcevega obhoda
h0, 0i poiˇsˇceta prva dva algoritma levo reˇsitev na sliki 7.19, medtem ko tretji algoritem
reˇsitvi najde desno reˇsitev.
Algoritmi z razvejitvijo in omejitvijo1 . Ta tehnika je primerna, ko s sestopanjem iˇsˇcemo optimalno mnoˇzico na podlagi neke numeriˇcne koliˇcine (torej najveˇcjo ali
najmanjˇso vrednost koliˇcine) in imamo pred vsakim klicem procedure poskus moˇznost
izraˇcunati neko zgornjo mejo za iskano koliˇcino po korakih, ki jih ˇse nismo opravili.
V kolikor je tako izraˇcunana zgornja meja manjˇsa od najveˇcje vrednosti, ki smo jo ˇze
dosegli, lahko naˇcrtovani klic procedure poskus opustimo.
7.3 Primer Kot primer bomo ponovno obravnavali 0-1 nahrbtnik, ki ga bomo reˇsevali
s sestopanjem, ˇceprav za to obstaja uˇcinkovitejˇsa metoda, ki smo jo razvili v poglavju
6. Problem bomo reˇsevali na dva naˇcina: prviˇc brez upoˇstevanja omejitve za najveˇcjo
1 Angleˇ
sko:
Branch and bound algorithms
7.6. POVZETEK OSNOVNIH POJMOV
173
PROCEDURE poskus(i:index ;
VAR a: AObj ;
p, (∗ trenutna prostornina ∗)
v , (∗ trenutna vrednost ∗)
P , (∗ prostorninska omejitev ∗)
zgM (∗ zgornja meja dodane vrednosti v bodoˇcih korakih ∗) :INTEGER);
VAR s, (∗ trenutna mnoˇzica predmetov ∗)
S , (∗ optimalna mnoˇzica predmetov ∗): SET ;
VAR V (∗ optimalna vrednost ∗) :INTEGER;
BEGIN
INC (stKlicev );
(∗ i poskuˇsamo vkljuˇciti v mnoˇzico s ∗)
IF p+a[i].p <= P THEN INCL(s,i);
IF (i < n) & (V <v +zgM ) THEN
poskus(i+1,a,p+a[i].p,v +a[i].v ,P ,zgM −a[i].v ,s,S ,V )
ELSIF v > V THEN V :=v ; S :=s
END; EXCL(s,i)
END;
(∗ . . . nato izkljuˇciti ∗)
IF (i < n) & (V <v +zgM −a[i].v ) THEN
poskus(i+1,a,p,v ,P ,zgM −a[i].v ,s,S ,V )
ELSIF v > V THEN V :=v ; S :=s
END
END poskus ;
Slika 7.20: Reˇsitev 0-1 nahrbtnika s sestopanjem
dosegljivo vrednost in drugiˇc z njenim upoˇstevanjem. Prvi program prepuˇsˇcamo
bralcu za vajo, procedura poskus za drugega pa je prikazanana sliki 7.20. Procedura je seveda v glavnih obrisih podobna proceduri poskus na sliki 7.10: a vsebuje
podatke o predmetih, p in v sta po vrsti, trenutni prostornina ter vrednost, P pa je
prostorninska omejitev. zgM je preprosto vsota vrednosti vseh predmetov z indeksi i . . . n, ki je oˇcitno zgornja meja za dodano vrednost v korakih od trenutnega do
konca. s je trenutno izbrana mnoˇzica predmetov, S je najboljˇsa mnoˇzica do danega
trenutka, medtem ko je V optimalna vrednost nahrbtnika.
Rezultati poskusa so prikazani na sliki 7.21
7.6
Povzetek osnovnih pojmov
1. Metoda sestopanja in iskalno drevo
2. Osnovna oblika procedure poskus
3. Prirejanje procedure poskus reˇsevanju problema skakaˇcevega obhoda
4. Prirejanje procedure poskus reˇsevanju problema osmih dam
174
POGLAVJE 7. SESTOPANJE
predmet ˇst.
vrednost
prostornina
1
7
4
2
6
5
3
4
3
4
6
4
5
8
6
6
10
5
7
9
6
8
6
7
9
8
7
10
9
5
ˇ
PRIMERJAVA PORABE CASA
ZA 0-1 NAHRBTNIK BREZ
IN Z UPORABO ZGORNJE MEJE ZA DOSEGLJIVO VREDNOST NAHRBTNIKA
N
1
138
532
899
1015
1023
1023
N:
1:
2:
P:
P
2
129
379
328
123
48
48
10
20
30
40
50
60
ˇst.:1
*
*
*
*
*
*
2 3 4 5 6 7 8 9
pripadnost optimalni mnoˇzici
*
*
* *
*
* * * *
* * * * * *
*
* * * * * * * *
* * * * * * * *
10
*
ˇstevilo klicev procedure poskus;
uporaba procedure brez upoˇstevanja zgornje meje;
z upoˇstevanjem zgornje meje;
prostorninska omejitev.
Slika 7.21: Rezultat delovanja procedure poskus na sliki 7.20
5. Prirejanje procedure poskus reˇsevanju problema trdnih zakonov
6. Naˇcini za omejevanje rasti iskalnega drevesa:
(a) s spremembo vrstnega reda poskusov in
(b) z ocenjevanjem obetavnosti poddreves
7. Algoritmi z razvejitvijo in omejitvijo.
7.7
Naloge
1. Spremenite programa za problema skakaˇcevega obhoda in osmih dam tako, da
se izpiˇsejo vse reˇsitve.
2. Problem skakaˇcevega obhoda je soroden tim. problemu Hamiltonovega cikla:
podan je usmerjen graf G = hV, Ei, pri ˇcemer je V = {v1 , v2 , . . . , vn } mnoˇzica
vozliˇsˇc, E pa mnoˇzica povezav in je potrebno najti tako permutacijo zaporedja
vozliˇsˇc, vi1 , vi2 , . . . , vin , da sta vij in vij+1 pri 1 ≤ j ≤ n − 1 povezana in prav
ˇ je podan primer problema skakaˇcevega obhoda (z vrednostjo
tako vin ter vi1 . Ce
n in zaˇcetnim poljem skakaˇca), definirajte graf, ki ima Hamiltonov cikel natanko
tedaj, ko obstaja reˇsitev problema skakaˇcevega obhoda.
7.7. NALOGE
175
3. V poglavju o maksimalnem pretoku in linearnem programiranju smo opisali
algoritem za iskanje maksimalnega pretoka skozi omreˇzje od izvora do ponora
(algoritem 5.3). Osnovni korak algoritma je iskanje nezasiˇcene poti od izvora
do ponora. Uresniˇcite ta postopek s sestopanjem.
4. Spremenite program 7.1 po navodilih iz odstavka “Odkrivanje neobetavnih poddreves” in poskuˇsajte ponoviti rezultate na slikah 7.12, 7.16 in 7.18.
176
POGLAVJE 7. SESTOPANJE
Poglavje 8
ISKANJE PO ZNAKOVNIH
ZAPOREDJIH
V tem poglavju gre podobno kot pri urejanju za enega izmed najbolj mnoˇziˇcno uporabljenih algoritmov (ali druˇzin algoritmov). Problem opiˇsemo takole: podani sta dve
znakovni zaporedji, T [1 . . . n] in P [1 . . . m] in je potrebno poiskati vsa mesta, kjer se
zaporedje P pojavlja kot podzaporedje v T . Z drugimi besedami, zanima nas, ali
obstaja k > 0 in zaporedje indeksov si , pri i = 1, . . . , k, tako da je T [si + j] = P [j]
pri j = 1, . . . , m. Vˇcasih nas zanima le s1 .
Najprej bomo predstavili terminologijo. Σ∗ oznaˇcuje mnoˇzico vseh znakovnih
zaporedij konˇcne dolˇzine, ki vsebujejo znake neke izbrane abecede Σ. Med taka zaporedja uvrˇsˇcamo tudi zaporedje niˇcelne dolˇzine (prazno zaporedje), ki ga oznaˇcujemo
z ε. Dolˇzino zaporedja x oznaˇcujemo z |x|. Stik zaporedij x in y (x podaljˇsano z y)
ˇ je u zaˇcetek zaporedja x (x = uy pri nekem y ∈ Σ∗ ), zapiˇsemo
oznaˇcujemo z xy. Ce
to kot u < x, ˇce pa u predstavlja konec zaporedja x (x = yu pri nekem y ∈ Σ∗ ),
zapiˇsemo to kot u = x. Bodimo pozorni, da za poljubno zaporedje x velja ε < x in
obenem ε = x.
8.1
Navadni algoritem za iskanje po znakovnih zaporedjih
Podobno kot pri urejanju izhajamo iz nekega zaˇcetnega, “navadnega” algoritma, ki
ga bomo nato izboljˇsali na dva naˇcina. Navadni algoritem za iskanje po znakovnih
zaporedjih je prikazan na sliki 8.1, deluje pa tako, da pri vsakem odmiku s preveri
ˇ
enakost P [1 . . . m] = T [s + 1 . . . s + m] in v primeru enakosti izpiˇse resultat. Ce
privzamemo, da je priˇcakovani ˇcas operacije P [1 . . . m] = T [s + 1 . . . s + m] enak
Θ(m) (gl. nalogo 1), se ni teˇzko prepriˇcati, da je poraba ˇcasa algoritma 8.1 enaka
Θ((n − m + 1) · m). V nadaljnjih razdelkih bomo pravkar zapisani rezultat izboljˇsali.
177
178
POGLAVJE 8. ISKANJE PO ZNAKOVNIH ZAPOREDJIH
Vhod Znakovni zaporedji T [1 . . . n] in P [1 . . . m]
Izhod Seznam odmikov s, pri katerih se P pojavlja
v T.
Postopek
n:=|T |; m:=|P |; s := 0;
WHILE s ≤ n−m DO
j := 1 ;
WHILE (j ≤ m) & (P [j ] = T [s + j ]) DO
INC (j )
END ;
IF j > m THEN
“P se pojavlja v T z odmikom s”
END;
INC (s)
END
Slika 8.1: Navadni algoritem za iskanje po znakovnih zaporedjih.
T :
b
a
c
b
P :
a
b
a
b
a
b
a
a
b
a
b
a
b
a
c
6=
b
b
a
b
Slika 8.2: Primer iskanja podzaporedja v zaporedju.
8.2
Knuth-Morris-Prattov algoritem
Najprej se bomo seznanili z algoritmom, ki v povpreˇcju porabi ˇcas Θ(n + m), kot
uvod pa bo rabil primer na sliki 8.2. Denimo, da uporabljamo algoritem na sliki 8.1
in preizkuˇsamo odmik s = 4. Pri tem smo odkrili neenakost znakov na nakazanem
mestu. Postavlja se vpraˇsanje, kateri je naslednji moˇzni kandidat za odmik? Vrednost
ˇ veˇc: to, da ne pride v poˇstev, je moˇzno ugotoviti
s + 1 zagotovo ne pride v poˇstev. Se
k
}|
z
s
s0
|
{
{z
k
}
0
Slika 8.3: Iskanje kandidata s0 za naslednji odmik.
179
8.2. KNUTH-MORRIS-PRATTOV ALGORITEM
k
}|
z
{
k}|00
z
s
s0
|
{
s00
{z
}
k0
Slika 8.4: Trije zaporedni kandidati za naslednji odmik.
z analizo zaporedja P , ker prvi znak P ni enak drugemu znaku. V naˇsem primeru
lahko kveˇcjemu upamo na uspeh pri novem odmiku s + 2 (ki pa se tudi izkaˇze za
neprimernega). V sploˇsnem denimo, da smo ugotovili, da velja P [1 . . . k] = T [s +
1 . . . s + k] in P [k + 1] 6= T [s + k + 1]. s + k + 1 naj bo tekoˇci indeks, k pa dolˇzina
vzorca P , na kateri smo ugotovili enakost med vzorcem in osnovnim zaporedjem.
Zanima nas naslednji kandidat za odmik. To je najmanjˇsa vrednost s0 > s, pri kateri
velja P [1 . . . k 0 ] = T [s0 + 1 . . . s0 + k 0 ] in s + k = s0 + k 0 (gl. sl. 8.3). V skrajnem
primeru se izkaˇze, da je s0 = s + k in k 0 = 0. Ta primer je seveda najugodnejˇsi s
staliˇsˇca porabe ˇcasa, ker pri iskanju zagotavlja najveˇcji pomik naprej. Oˇcitno velja
P [1 . . . k 0 ] = P [1 . . . k], torej iˇsˇcemo najdaljˇsi zaˇcetek zaporedja P [1 . . . k] (dolˇzine < k),
ki je obenem konec istega zaporedja. Namreˇc, v kolikor je pri novem odmiku k 0 > 0,
mora biti zaˇcetek zamaknjenega zaporedja P enak koncu zaporedja T [s + 1 . . . s + k],
oziroma P [1 . . . k]. (Potrebno je izbrati najdaljˇsi zaˇcetek, ki je obenem konec, ker
nam taka izbira zagotavlja prvi naslednji odmik s0 .)
Tisto, kar je pomembno pri postopku iskanja, je, da je velikost naslednjega moˇznega
odmika odvisna le od podzaporedja P in jo je potemtakem moˇzno izraˇcunati pred
zaˇcetkom postopka iskanja z nekakˇsnim “predprocesiranjem”. Odmik je odvisen od
“preskakovalne funkcije” π, ki jo na podlagi pravkar povedanega definiramo kot
π[q] = max{k | k < q&P [1 . . . k] = P [1 . . . q]}.
(8.1)
V tem primeru q predstavlja poljuben poloˇzaj znotraj podzaporedja P , do koder smo
ugotovili enakost med P in zaporedjem T , medtem ko se je pri indeksu q + 1 pojavila
neenakost. Razlika med trenutnim odmikom P in naslednjim moˇznim odmikom je
tedaj q − π[q]. Na primer potem ko smo pri odmiku s = 4 na sliki 8.2 ugotovili
neenakost pri indeksu q + 1 = 8, je naslednji moˇzen odmik dva znaka naprej, ker je
π[7] = 5.
Sedaj se bomo lotili naloge sestavljanja algoritma za izraˇcun π[q]. Izpeljali bomo
rekurzivno relacijo za π[q], ki jo bomo neposredno prevedli v algoritem. π[q] je najveˇcji
element v mnoˇzici
U [q] = {k | k < q & P [1 . . . k] = P [1 . . . q]},
(8.2)
180
POGLAVJE 8. ISKANJE PO ZNAKOVNIH ZAPOREDJIH
Vhod Znakovno zaporedje P [1 . . . m]
Izhod Vrednosti preskakovalne funkcije
π[1], π[2], . . . , π[m].
Postopek
m:=|P | ;
π[1]:=0 ;
k :=0 ;
FOR q:=2 TO m DO
(∗ zaˇ
cetna vrednost k je π[q − 1];
zanka, ki sledi, pregleduje elemente
U [q − 1] po padajoˇ
ci vrednosti in se
zakljuˇ
ci, ko je izpolnjen pogoj (8.4) ∗)
WHILE (k > 0) & (P [k +1] # P [q]) DO
k :=π[k]
END ;
IF P [k +1] = P [q] THEN INC (k ) END;
π[q]:=k
END
Slika 8.5: Izraˇcun preskakovalne funkcije π.
torej π[q] = max{U [q]}. Vsem mnoˇzicam U [q] bomo dodali ˇse element 0, ki je dolˇzina
praznega zaporedja. Na primer v primeru na sliki 8.2 je mnoˇzica U [7] = {0, 1, 3, 5}.
ˇ elemente U [q] uredimo po padajoˇci vrednosti, U [q]1 , U [q]2 , . . ., lahko ugotovimo
Ce
na podlagi slike 8.4, da velja
U [q]j+1 = π[U [q]j ].
(8.3)
Z besedami: naslednji element v U [q] dobimo tako, da uporabimo funkcijo π na
trenutnem elementu U [q]. Ugotovimo lahko, da je element 0 edini element mnoˇzice
U [1].
Kakˇsna pa je zveza med U [q] in U [q − 1]? Oˇcitno velja
U [q] = {k | k − 1 ∈ U [q − 1], P [k] = P [q]}.
(8.4)
Z besedami: element U [q] je dolˇzina j nekega zaˇcetka P , ˇcigar zadnji znak je enak
P [q], zaˇcetek do tega znaka pa ima dolˇzino, ki je element U [q − 1].
Algoritem za izraˇcun preskakovalne funkcije je prikazan na sl. 8.5. Po zaˇcetnem
prirejanju vrednosti π[1] algoritem vstopi v zanko, ki raˇcuna π[q]. Notranja zanka
pregleduje elemente U [q] in preverja pogoj P [k + 1] = P [q]. V primeru enakosti se
znotraj pogojnega stavka, pred koncem zunanje zanke, vrednost k poveˇca.
Zanimiv je tudi naˇcin izraˇcuna ˇcasa, ki ga porabi algoritem na sliki 8.5. Iz analize zunanje zanke FOR na sliki ugotovimo, da stavka zunaj notranje zanke WHILE
porabita konstanten ˇcas; torej je osnovni problem ugotoviti, kolikokrat se ponovi jedro notranje zanke. Pri vsakem njegovem izvajanju se vrednost k zmanjˇsa, ker velja
8.3. BOYER IN MOOREOV ALGORITEM
181
Vhod Znakovni zaporedji P [1 . . . m] in T [1 . . . n].
Izhod Seznam odmikov, s katerimi se P pojavlja
znotraj T .
Postopek
n:=|T | ;
m:=|P | ;
izraˇ
cun π ;
q:=0
FOR i:=1 TO n DO
WHILE (q > 0) & (P [q+1] # T [i]) DO
q:=π[q]
END ;
IF P [q+1] = T [i] THEN INC (q) END;
IF q = m THEN
“P se pojavlja z odmikom i − m”
q:=π[q]
END
END
Slika 8.6: KMP algoritem.
π(k) < k. Torej je ˇstevilo ponavljanj jedra notranje zanke odvisno od vsote prirastkov vrednosti k. In ker se k med celotnim delovanjem algoritma lahko poveˇca najveˇc
m − 1 krat, se tudi jedro notranje zanke med celotnim delovanjem algoritma ponovi
najveˇc m − 1 krat. Torej je ˇcas, ki ga porabi algoritem na sl. 8.5 O(m). Zelo podobna
analiza velja za algoritem iskanja podzaporedja P v T na sl. 8.6, tako da je skupna
poraba obeh algoritmov O(m + n). Pri opisani analizi si lahko predstavljamo, kot
da pogojni stavek znotraj zanke FOR v algoritmu na sliki 8.1 ustvarja nek “kapital”
(vrednost k), ki ga lahko zanka WHILE porabi in torej, ˇce nas zanima, koliko kapitala porabi WHILE, je to moˇzno izraˇcunati tako, da ugotovimo, kolikokrat se izvaja
pogojni stavek znotraj zanke FOR.
8.3
Boyer in Mooreov algoritem
Drugi algoritem, ki ga bomo opisali, uporablja za pospeˇsevanje iskanja dvoje hevristiˇcnih pravil in je posebno primeren, kadar je vzorec P razmeroma dolg in abeceda Σ
razmeroma velika. V takem primeru se pogosto izkaˇze, da je ta algoritem najhitrejˇsi.
Algoritem je prikazan na sliki 8.7 in pri njem predvsem opazimo precejˇsno podobˇ odstranimo vrstici 2 in 3 ter zamenjamo
nost z navadnim algoritmom na sliki 8.1. Ce
9–11 z
INC (s)
END,
182
POGLAVJE 8. ISKANJE PO ZNAKOVNIH ZAPOREDJIH
1
2
3
4
5
6
7
8
9
10
12
13
n := |T | ; m := |P | ; s := 0 ;
λ := Zadnji indeks znaka(P ,m,Σ) ;
γ := Zadnji indeks konca podzaporedja(P ,m) ;
WHILE s ≤ n − m DO
j := m ;
WHILE (j > 0) & (P [j ] = T [s + j ]) DO DEC (j ) END ;
IF j = 0 THEN
“Vzorec se pojavlja z odmikom s”
INC (s,γ[0])
ELSE INC (s,MAX (γ[j ],j −λ[T [s+j ]]))
END
END
Slika 8.7: Boyer in Mooreov algoritem
T :
t
P :
n
a
v
p
a
a
r
d
o
e
s
n
t
6=
o
s
t
s
t
e
r
e
(a) Prva neenaka znaka (od zadaj) v besedilu in vzorcu sta presledek in o
T :
t
P :
n
a
a
v
p
a
r
d
o
e
s
n
t
6=
o
s
t
s
t
e
r
e
(b) Hevristiˇ
cno pravilo “slabih znakov” predlaga pomik naprej za 6 mest
T :
P :
t
n
a
a
v
p
a
r
d
o
e
n
s t
s t
6=
o
s
e
r
e
t
(c) Hevristiˇ
cno pravilo “dobrih koncev podzaporedij” predlaga pomik naprej za 3 mest
Slika 8.8: Iskanje vzorca a prostost v besedilu t navaden stere z Boyer in Mooreovim
algoritmom
dobimo enak algoritem le, da se preizkus enakosti izvaja od zadaj. Oˇcitno sta funkciji
λ in γ bistveni za delovanje algoritma, zato se bomo lotili njune razlage. Prva realizira
hevristiˇcno pravilo “slabih znakov”, druga pa pravilo “dobrih koncev podzaporedij”.
Obe pravili sta zasnovani “varno” v pomenu, da Boyer in Mooreov algoritem nikoli
ne spregleda kakega moˇznega odmika vzorca v zaporedju, ki ga preiskujemo. Bistvo
algoritma je, da v primeru neuspele primerjave med vzorcem in besedilom pride do pomika vzorca naprej. Ker pa vˇcasih algoritem realizira pomik, ki v danih okoliˇsˇcinah ni
optimalen, pravimo, da sta pravili, na podlagi katerih se raˇcuna pomik, “hevristiˇcni”.
Delovanje algoritma na konkretnem primeru je prikazano na sliki 8.8. V vsakem
poloˇzaju primerjamo vzorec z ustreznim kosom zaporedja od desnega konca vzorca
proti zaˇcetku in se ustavimo na prvem mestu, kjer ugotovimo neenakost znakov ali pa
levo od zaˇcetka vzorca v primeru enakosti [gl. sliko 8.8(a)]. Nato vsako od omenjenih
183
8.3. BOYER IN MOOREOV ALGORITEM
j m−k
k
m
pomik
(a) Primer j ≤ m − k
k
m−k j
m
pomik
(b) Primer j > m − k
Slika 8.9: Delovanje pravila “dobrih koncev podzaporedij”
FOR a ∈ Σ DO λ[a] := 0 END ;
FOR j := 1 TO m DO
λ[P [j ]] := j
END ;
RETURN λ(P ,m,Σ)
Slika 8.10: Izraˇcun funkcije λ (zadnji indeks nekega znaka v vzorcu P )
pravil predlaga neko vrednost za dolˇzino pomika vzorca naprej, izbere pa se veˇcja.
Na primer, pravilo “slabih znakov” na sliki 8.8(b) predlaga pomik naprej za 6 mest,
oziroma za razdaljo do prvega znaka, ki je enak “slabemu znaku” v besedilu, ki ga
preiskujemo. To pravilo pravzaprav realiziramo v nekoliko spremenjeni obliki, ki
prispeva k uˇcinkovitosti: predlog za pomik naprej je j − λ(T [j]), ˇce je j mesto, kjer
smo ugotovili neenakost, vrednost funkcije λ(a) pa je enaka zadnjemu indeksu znaka
a v vzorcu P . Na ta naˇcin se lahko zgodi, da pravilo predlaga negativen pomik naprej
(v primeru, ko velja λ(T [j]) > j). Vendar, ker drugo pravilo vedno predlaga pozitiven
pomik, je dejanski pomik pozitiven. Pravilo “dobrih koncev podzaporedij” predlaga
pomik naprej za dolˇzino, ki zagotavlja, da so vsi znaki “dobrega konca podzaporedja”
P [j + 1], . . . , P [m] enaki istoleˇznim znakom zamaknjenega vzorca. To pa je,
najmanjˇsa vrednost m − k, kjer je k dolˇzina nekega zaˇcetka Pk , tako
da je bodisi j ≤ m − k in velja Pk = P [j + 1], . . . , P [m] ali pa
j > m − k in velja P [j + 1], . . . , P [m] = Pk ;
(8.5)
(gl. sliko 8.9, v obeh primerih sta enaka dela vzorca zasenˇcena). V konkretnem primeru na sliki 8.8(c) je predlog za pomik naprej 3, na podlagi zapisanega pa je dejanski
pomik M AX(6, 3) = 6.
Sedaj se najprej lotimo izraˇcuna funkcije λ. Algoritem je prikazan na sliki 8.10 in
ne potrebuje dodatnih pojasnil.
184
POGLAVJE 8. ISKANJE PO ZNAKOVNIH ZAPOREDJIH
P :
k
m−k j
m
(a) k je konec najdaljˇsega zaˇcetka P , ki se konˇca enako kot P
PR :
k
m − j = π R (l)
m−k
m
l =m−j+m−k
(b) Zrcalna slika P
Slika 8.11: Izraˇcun γ(j) v primeru j > m − k
1
2
3
4
5
6
7
8
9
10
12
12
13
π := Preskakovalna funkcija(P ,m) ;
P 0 := P R ; (∗ Zrcalna slika P ∗)
π R := Preskakovalna funkcija(P 0 ,m) ;
FOR j := 0 TO m DO
γ[j ] := m − π[m]
END ;
FOR l := 1 TO m DO
j := m − π R [l ] ;
IF γ[j ] > l − π R [l ] THEN
γ[j ] := l − π R [l ]
END
END ;
RETURN γ(P ,m)
Slika 8.12: Izraˇcun funkcije γ (zadnji indeks konca podzaporedja)
8.4. POVZETEK OSNOVNIH POJMOV
185
ˇ je j indeks, kjer
Algoritem za izraˇcun funkcije γ pa zahteva nekoliko veˇc truda. Ce
smo ugotovili neenakost, je γ(j) definirano s pravilom (8.5). Kadar je j ≤ m − k, je
oˇcitno k = π(m), kjer je π preskakovalna funkcija, ki jo poznamo iz algoritma KMP
[gl. (8.1) in sliko 8.9(a)]. Za primer j > m − k pa podaja obrazloˇzitev izraˇcuna γ(j)
slika 8.11: ˇce vzorec P zrcalimo, ugotovimo, da velja m − j = π R (l), pri ˇcemer je π R
preskakovalna funkcija zrcaljenega vzorca, za l pa velja l = m−j +m−k = 2m−j −k.
Algoritem za γ(j) je prikazan na sliki 8.12. Glede na to, da vnaprej ne vemo, ali
pri nekem j velja primer (a) oziroma (b) na sliki 8.9, izraˇcunamo obe vrednosti in
izberemo manjˇso. Prva vrednost se raˇcuna v vrsticah 4–6, druga pa v 7–12. Pri
drugem izraˇcunu pa prav tako vnaprej ne poznamo vrednosti l, ki ustreza nekemu
indeksu j. Zato sproˇzimo izraˇcun pri vseh vrednostih l v intervalu [1,m], pri vsaki
vrednosti izraˇcunamo π R (l), nato iz slednje vrednosti dobimo j in na podlagi tega
morebiti popravimo vrednost γ(j).
Kot zadnjo pripombo, ki se nanaˇsa na algoritem KMP ter Boyer in Mooreov algoritem, lahko zapiˇsemo, da v primerjavi s svojo majhno velikostjo zahtevajo razmeroma
veliko miselnega napora za to, da jih razumemo.
8.4
Povzetek osnovnih pojmov
1. Navadni algoritem in ocena njegove porabe ˇcasa
2. Algoritem Knutha, Morrisa in Pratta. Preskakovalna funkcija in njen izraˇcun. Ocena
porabe ˇcasa
3. Boyer in Mooreov algoritem. Hevristiˇcna pravila za israˇcun naslednjega odmika. Utemeljitev pravilnosti algoritma. Opis funkcij λ in γ.
8.5
Naloge
1. Ocenite najveˇcjo porabo ˇcasa navadnega algoritma za iskanje po znakovnih zaporedjih
ˇ ocenite s ˇstevilom primerjanj v izstopnem pogoju notranje zanke.
(slika 8.1). Cas
2. Naj bosta P [1 . . . m] in T [1 . . . n] niza, ki sta sestavljena iz nakljuˇcno izbranih znakov nekega znakovnega nabora, ki vsebuje d znakov. Dokaˇzite, da je povpreˇcno
(priˇcakovano) ˇstevilo operacij primerjanja znakov v izstopnem pogoju notranje zanke
navadnega algoritma na sliki 8.1 enako
(n − m + 1)
1 − d−m
≤ 2(n − m + 1).
1 − d−1
3. Izraˇcunajte preskakovalno funkcijo π KMP algoritma za vzorec
ababbabbababbababbabb.
4. Izraˇcunajte funkciji λ in γ za vzorec P = 0101101201 in znakovni nabor Σ = {0, 1, 2}.
186
POGLAVJE 8. ISKANJE PO ZNAKOVNIH ZAPOREDJIH
Poglavje 9
VZPOREDNI ALGORITMI
9.1
Uvod
Glede na hiter razvoj raˇcunalniˇske tehnologije, ki se med ostalim kaˇze v zmanjˇsevanju
izmer raˇcunalniˇskih sestavnih delov, postaja kot ˇcedalje zanimivejˇsa moˇznost za reˇsevanje
nekaterih nalog, uporaba veˇc sodelujoˇcih procesorjev, ki istoˇcasno obdelujejo vsak svoj
del naloge. Zato bomo v tem poglavju na kratko predstavili osnovne ideje vzporednega
raˇcunanja, kot pravimo taki uporabi raˇcunalniˇskih procesorjev. Vendar, preden lahko
smiselno govorimo o vzporednem raˇcunanju, se je potrebno dogovoriti o osnovnih
pojmih.
Predvsem je treba takoj poudariti, da “vzporedni
raˇcunalniki” ne predstavljajo enotnega, homogenega razreda,
P0
temveˇc se razliˇcni modeli in praktiˇcne realizacije precej razlikujejo po svojih lastnostih in parametrih, kakor tudi, da so le podP1
Skupen
druˇzina ˇsirˇse druˇzine veˇcprocesorskih raˇcunalniˇskih sistemov , ki
P2
pomtemelji na uporabi veˇc sodelujoˇcih procesorjev. Prva razlika se
nilnik
nanaˇsa na naravo povezave med procesorji. Imamo lahko pro..
cesorje, od katerih vsak izvaja svoj program in ki si le obˇcasno
.
poˇsiljajo sporoˇcila. Takim veˇcprocesorskim sistemom pravimo P
p−1
ˇsibko povezani veˇcprocesorski sistemi in pri zasnovi algoritmov
zanje naletimo na nekatere nove probleme, vendar se postopek
ne razlikuje bistveno od zasnove algoritmov za navadne eno- Slika 9.1: Raˇcunalprocesorske raˇcunalnike. Ta druˇzina veˇcprocesorskih sistemov niˇski model PRAM
nas na tem mestu ne bo zanimala. Po drugi strani pa imamo
veˇcprocesorske sisteme, kjer so izraˇcuni na razliˇcnih procesorjih tesno povezani med
seboj in takim pravimo krepko povezani veˇcprocesorski sistemi . To druˇzino bomo
enaˇcili s pojmom vzporednega raˇcunalnika, ki smo jo omenili na zaˇcetku.
Opisano druˇzino vzporednih raˇcunalnikov bomo enaˇcili z raˇcunalniˇskim modelom
PRAM, ki je shematiˇcno prikazan na sliki 9.1. Ime je angleˇska kratica za Parallel
187
188
POGLAVJE 9. VZPOREDNI ALGORITMI
Random Access Machine, oziroma stroj z vzporednim enakopravnim dostopom do pomnilnika, sestavljen pa je iz doloˇcenega ˇstevila procesorjev in osrednjega pomnilnika,
ki je povezan z vsemi procesorji. Vsak procesor lahko opravlja obiˇcajne operacije
danaˇsnjih raˇcunalnikov (aritmetiˇcne operacije, operacije nad biti, operacije, ki preusmerjajo izraˇcun) in ima enakopraven dostop do vseh celic pomnilnika. Osnovni
privzetek, ki ga bomo na tem mestu upoˇstevali, je, da so procesorji med seboj sinhronizirani, kar pomeni, da se ukazi na njih izvajajo istoˇcasno v taktu neke zunanje
ure.
Danes obstaja ˇze veˇc realizacij vzporednih raˇcunalnikov, ki pribliˇzno ustrezajo
takemu opisu, vendar se v podrobnostih precej razlikujejo. Elementi, v katerih se
razliˇcni stvarni vzporedni raˇcunalniki med seboj razlikujejo, so npr. ˇstevilo procesorjev (do nekaj tisoˇc), zmogljivost procesorjev (npr. ali ima lokalni pomnilnik) ipd.
Precejˇsna raznolikost na podroˇcju vzporednih raˇcunalnikov se tudi zrcali v teoretiˇcnih
ˇ pri opisanem modelu PRAM zasledimo najmanj ˇstiri podrazrede glede
modelih. Ze
na naˇcin branja iz pomnilnika in zapisovanja vanj: branje lahko poteka zaporedno,
ko iz neke celice lahko naenkrat bere le en procesor, in vzporedno, ko naenkrat lahko
bere veˇc procesorjev. Na podoben naˇcin razlikujemo med zaporednim in vzporednim
zapisom. Tako imamo naslednje ˇstiri razrede vzporednih raˇcunalnikov
zbzz zaporedno branje, zaporeden zapis;
zbvz zaporedno branje, vzporeden zapis;
vbzz vzporedno branje, zaporeden zapis;
vbvz vzporedno branje, vzporeden zapis.
Od teh razredov imamo najveˇckrat opravka z razredoma zbzz in vbvz. Oˇcitno
je glede praktiˇcne realizacije najenostavnejˇsi razred zbzz, s staliˇsˇca programiranja pa
vbvz. Pri vzporednem zapisu ni vnaprej oˇcitno, katera vrednost ostane zapisana v
celici, potem ko vsi procesorji operacijo zakljuˇcijo. Moˇznih je veˇc dogovorov: operacija je smiselna le takrat, ko so zapisane vrednosti enake; obvelja vrednost, ki jo
zapiˇse procesor z najmanjˇsim (najveˇcjim) indeksom ipd. V naˇsih primerih pa bomo
uporabljali le razred zbzz in nas opisane dileme ne bodo zanimale.
Naslednje pomembno vpraˇsanje pri vzporednih raˇcunalnikih je, kako jih programiramo. Z drugimi besedami, katere programske gradnike je potrebno dodati obiˇcajnim
programskim jezikom, da jih lahko uporabljamo na vzporednih raˇcunalnikih. Pri
tem so moˇzne razliˇcne reˇsitve, uporabili pa bomo najenostavnejˇso, ki zadoˇsˇca naˇsim
potrebam. Obiˇcajnim programskim jezikom dodamo stavek
PARALLEL DO(i) S1 ; S2 ; . . . ; Sn END,
katerega uˇcinek je, da se zaporedje stavkov S1 ; S2 ; . . . ; Sn izvaja vzporedno (istoˇcasno)
na vseh procesorjih, identiteta trenutnega procesorja pa je i. Nadalje potrebujemo
stavek, s katerim preverjamo nek globalni pogoj, ki je odvisen od veˇc celic pomnilnika
in ki ga je moˇzno izraˇcunati kot en ukaz:
PARALLEL WHILE P DO S1 ; S2 ; . . . ; Sn END,
189
9.2. METODA PRESTAVLJANJA KAZALCEV
(a) 1
1
1
1
1
(b)
2
2
2
2
1
/
0
/
(c) 4
4
3
(d) 5
4
/
/
0 /
/
2
/
1
/
0
/
3 /
2
/
1 /
0
/
Slika 9.2: Prestavljanje kazalcev
1
2
4
4
5
6
7
8
9
10
11
13
13
PROCEDURE ListRank (p:PNode);
VAR q:PNode; n,i :INTEGER;
BEGIN
q:=p; i :=0;
WHILE q # NIL DO
q.d := i ; INC (i ); q := q.next
END;
n := i ;
q := p;
WHILE q # NIL DO
q.d := n − q.d ; q := q.next
END
END ListRank ;
Slika 9.3: Zaporedni algoritem za problem razdalje do konca seznama
kjer je P opisane vrste pogoj. V kolikor nek stavek ni v obmoˇcju stavka PARALLEL
DO, privzamemo, da se izvaja na enem samem procesorju, ki ga (nakljuˇcno) izbere
operacijski sistem.
9.2
Metoda prestavljanja kazalcev
Kot prvi primer naloge, ki jo je primerno reˇsevati na vzporednem raˇcunalniku, bomo
opisali problem razdalje do konca seznama. Podan je seznam in pri vsakem elementu
ˇzelimo zapisati razdaljo do konca seznama [gl. sliko 9.2(a)]. Tako bo zadnji element
imel vsebino 0, predzadnji 1 itn. Obiˇcajen, zaporedni algoritem za to nalogo je prikazan na sliki 9.3 in se ni teˇzko prepriˇcati, da porabi ˇcas Θ(n). Algoritem uporablja
nek podatkovni tip Node, ki ima zgradbo,
190
POGLAVJE 9. VZPOREDNI ALGORITMI
1
2
3
4
6
6
7
8
9
10
12
13
14
14
PROCEDURE ParListRank ;
PARALLEL DO(i )
IF next[i ] = NIL THEN d [i ] :=0
ELSE d [i ] :=1
END
END ;
PARALLEL WHILE ∃i next[i ] 6= NIL DO
PARALLEL DO(i )
IF next[i ] 6= NIL THEN
INC (d [i ],d [next[i ]]) ; next[i ] := next[next[i ]]
END
END
END
END ParListRank ;
Slika 9.4: Vzporedni algoritem za izraˇcun razdalje do konca seznama
korak
1
2
3
4
5
6
opis izraˇcuna
branje next[i]
branje d[i]
branje d[next[i]]
zapis d[i] + d[next[i]] v d[i]
branje next[next[i]]
zapis next[next[i]] v next[i]
Slika 9.5: Podrobnosti izraˇcuna v vrsticah 8–12 na sliki 9.4
PNode = POINTER TO Node ;
Node = RECORD d : INTEGER ;
next: PNode
END
Nalogo pa je moˇzno reˇsiti tudi z mnogo uˇcinkovitejˇsim vzporednim algoritmom, ki je
prikazan na sliki 9.4. Za predstavitev seznama uporablja algoritem dve tabeli,
d , next: ARRAY n OF INTEGER;
Algoritem deluje tako, da na zaˇcetku priredi vsakemu elementu seznama na sliki
9.2(a) procesor in nato (istoˇcasno) zapiˇse v zadnji element seznama 0, v ostale pa
1 [vrstice 2–6 na sliki 9.4]. Nato zanka v vrsticah 7–13 na vsakem koraku opravi
vzporedni izraˇcun (vrstice 8–12), ki vsakemu elementu priˇsteje vsebino naslednjega in
obenem kazalec prestavi tako, da kaˇze do naslednika naslednika (vrstica 10). Izraˇcun
se zakljuˇci, ko je seznam popolnoma “razvezan”.
ˇ
9.3. ASOCIATIVNI PRODUKT ZACETNIH
ELEMENTOV SEZNAMA
191
Pri analizi algoritma naprej ugotovimo, da opisani algoritem pripada razredu zbzz.
V to se je moˇzno prepriˇcati na podlagi “smiselnega” prevoda slike 9.4 v nek niˇzji jezik,
ki je prikazan na sliki 9.5. Osnovna ugotovitev je, da ˇceprav iz neke celice bere veˇc
procesorjev (procesor i in njegov predhodnik), se to dogaja v zaporednih ˇcasovnih
trenutkih (na primer koraka 2 in 3), tako da ne pride do vzporednega branja, oziroma
zapisa.
Nadaljnji koraki algoritma za primer na sliki 9.2(a) so prikazani na slikah (b)-(d).
Kazalec iz prvega elementa, ki v sliki (a) kaˇze na drugega, se kot posledica stavka
v vrstici 10 prestavi tako, da kaˇze na tretjega. Obenem se vsebina d[1] poveˇca za
vsebino d[2]. Podobno pri drugih elementih. V konˇcnem koraku (d) so vrednosti
pri elementih enake razdalji do konca prvotnega seznama, seznam pa je popolnoma
“razvezan”.
Sedaj se bomo prepriˇcali v pravilnost algoritma. Uporabili bomo obiˇcajno tehniko
zanˇcnih invariant. Invarianta zanke v vrsticah 7–13 je, da je vsota elementov seznama,
ki se zaˇcne pri elementu i, enaka razdalji do konca prvotnega seznama. To oˇcitno velja
na zaˇcetku, ker smo v vsak element, razen zadnjega, zapisali vrednost 1. Invarianta
se ohranja zato, ker na vsakem koraku sicer prestavimo kazalec, vendar elementu i
dodamo vrednost elementa, ki smo ga na ta naˇcin izpustili. 2
V naslednjem koraku se lotimo izraˇcuna ˇstevila korakov, ki jih porabi algoritem
na sliki 9.4. Zanka v vrsticah 2–6 porabi en korak, oziroma dva, ˇce preizkus obravnavamo kot loˇcen korak, medtem ko zanka v vrsticah 7–13 porabi toliko korakov, koliko
je potrebno, da se prvotni seznam popolnoma “razveˇze” na posamezne elemente. Na
vsakem koraku se vsak obstojeˇci podseznam razdeli na dva podseznama: na podseznam, ki povezuje sode elemente prvotnega podseznama in podseznam, ki povezuje
lihe elemente. Torej je ˇstevilo korakov za to, da se seznam popolnoma razveˇze, enako
Θ(log2 n).
9.3
Asociativni produkt zaˇ
cetnih elementov seznama
V naslednjem primeru bomo uporabili tehniko prestavljanja kazalcev pri nekem drugem izraˇcunu. Podana sta asociativna operacija ◦ in seznam elementov1 ,
x1 , x2 , . . . , xn ,
ki pripadajo mnoˇzici, na kateri je operacija definirana. Naloga je sestaviti seznam
y1 , y2 , . . . , yn ,
tako da velja yi = x1 ◦ x2 ◦ . . . ◦ xi . Za vrednost xi ◦ xi+1 ◦ . . . ◦ xj bomo odslej
uporabljali nekoliko uˇcinkovitejˇsi zapis [i, j]. Oˇcitno velja [i, j − 1] ◦ [j, k] = [i, k].
1 Spomnimo se, da je neka operacija ◦ asociativna v primeru, ko velja x ◦ (y ◦ z) = (x ◦ y) ◦ z pri
vseh x, y, z. Z drugimi besedami, neka dvojiˇska operacija je asociativna, ko vrednost “produkta” veˇ
c
elementov ni odvisna od postavitve oklepajev.
192
POGLAVJE 9. VZPOREDNI ALGORITMI
1
2
3
4
5
6
7
8
9
11
12
13
13
PROCEDURE ParAssocPrefix ;
PARALLEL DO(i )
y[i ] :=x [i ]
END ;
PARALLEL WHILE ∃i next[i ] 6= NIL DO
PARALLEL DO(i )
IF next[i ] 6= NIL THEN
y[next[i ]] := y[i ] ◦ y[next[i ]] ;
next[i ] := next[next[i ]]
END
END
END
END ParAssocPrefix ;
Slika 9.6: Vzporedni algoritem za asociativni produkt zaˇcetnih elementov seznama
(a)
[1,1]
[2,2]
[3,3]
[4,4]
[5,5]
[6,6] /
(b)
[1,1]
[1,2]
[2,3]
[3,4]
[4,5] /
[5,6] /
(c)
[1,1]
[1,2]
[1,3] /
[1,4] /
[2,5] /
[3,6] /
(d)
[1,1] /
[1,2] /
[1,3] /
[1,4] /
[1,5] /
[1,6] /
Slika 9.7: Asociativni produkt zaˇcetnih elementov seznama
ˇ
ˇ DVOJISKEGA
ˇ
9.4. IZRACUN
GLOBINE VOZLISˇC
DREVESA
193
Nalogi pravimo asociativni produkt zaˇcetnih elementov seznama. Vzporedni algoritem zanjo je prikazan na sliki 9.6, medtem ko je primer njegovega delovanja na
sliki 9.7. Algoritem je presenetljivo podoben algoritmu za razdaljo do konca seznama
na sliki 9.4. Pravzaprav imata algoritma enaki zgradbi, razlikujeta se le po konˇcnih
stavkih, ki se izvajajo znotraj zank. Elementi seznama imajo tri komponente: x, y in
next, od katerih sta na sliki 9.7 prikazani le dve (y in next). Zopet privzemamo, da
so komponente elementov zapisane v ustreznih tabelah. Tudi v tem primeru vsakemu
elementu seznama priredimo nek procesor, nato pa algoritem deluje tako, da najprej
zanka v vrsticah 2–4 priredi elementom y[i] vrednost x[i], za tem pa se zanka v vrsticah 5–12 izvaja, dokler se seznam popolnoma ne “razveˇze”. Jedro notranje zanke
v vrsticah 8–9 se razlikuje od ustreznih stavkov v algoritmu na sliki 9.4 po tem, da
medtem ko v prvem algoritmu vsak procesor prebere komponento d naslednika in jo
priˇsteje k svoji komponenti d, v drugem algoritmu procesor vrednost komponente y
svojega elementa primnoˇzi k isti komponenti naslednika.
Podobno kot v primeru algoritma na sliki 9.4 poteka tudi dokaz pravilnosti in
izpeljava ˇstevila korakov. Dokaz pravilnosti sestavimo na podlagi zanˇcne invariante,
ki velja na zaˇcetku zanke v vrsticah 5–12: y[i] pred nekim korakom je enako [h + 1, i],
kjer je h indeks predhodnika v seznamu, kateremu pripada i, oziroma [1, i] v primeru,
ko i nima predhodnika. Na primer, na sliki 9.7(b) je indeks predhodnika elementa
i = 3, 1 in zato je y[3] = [2, 3].
Dokaz veljavnosti zanˇcne invariante: pred prvim izvajanjem jedra zanke je invarianta oˇcitno veljavna. Sedaj pa denimo, da invarianta velja pred nekim izvajanjem
jedra in bomo dokazali, da velja tudi potem, ko smo jedro izvrˇsili. Dokaz razpade na
tri primere: procesor i ima 0, 1, ali 2 (in veˇc) predhodnikov.
ˇ i nima predhodnikov, se mu komponenta y ne spremeni in torej invarianta
Ce
ostane v veljavi.
ˇ ima i enega predhodnika, h, ima y[h] na podlagi zanˇcne invariante vrednost
Ce
[1, h], medtem ko ima y[i] vrednost, [h + 1, i]. V vrstici 8 torej procesor h priredi komponenti y[i] vrednost [1, h] ◦ [h + 1, i] = [1, i], v vrstici 9 pa i ostane brez predhodnika,
kar pomeni, da invarianta ostane v veljavi.
ˇ ima i dva ali veˇc predhodnikov, naj bo neposredni predhodnik h, predhodnik
Ce
predhodnika pa g. V vrstici 8 priredi procesor h komponenti y[i] vrednost [g + 1, h] ◦
[h + 1, i] = [g + 1, i], medtem ko v vrstici 9 procesor g priredi komponenti next[g]
vrednost i. Ker s tem postane g predhodnik i, ostane invarianta za i veljavna. 2
9.4
Izraˇ
cun globine vozliˇ
sˇ
c dvojiˇ
skega drevesa
Na koncu poglavja o vzporednem raˇcunanju bomo opisali reˇsitev problema doloˇcanja
globine vozliˇsˇc dvojiˇskega drevesa. Podano je dvojiˇsko drevo in je potrebno pri vsakem
vozliˇsˇcu zapisati njegovo globino, ki jo v tem primeru definiramo kot ˇstevilo vozliˇsˇc
na poti do korena (gl. sliko 9.8). Glede na to, da se pri reˇsevanju naloge ne moremo
izogniti obiskovanju vseh vozliˇsˇc, je najmanjˇsi ˇcas za njeno reˇsevanje z zaporednim al-
194
POGLAVJE 9. VZPOREDNI ALGORITMI
1
2
2
3
3
4
4
5
3
4
5
Slika 9.8: Drevo z vpisanimi globinami vozliˇsˇc
+1
A
B
−1
Slika 9.9: Dva procesorja, prirejena enemu vozliˇsˇcu
goritmom Θ(n), kjer je n ˇstevilo vozliˇsˇc. Kot prvo misel za vzporedni algoritem za isto
nalogo si lahko predstavljamo algoritem, ki deluje tako, da vsakemu vozliˇsˇcu priredi
procesor, nato koren sebi priredi globino 1 ter poˇslje sporoˇcilo o svoji globini svojima
naslednikoma. Ostali procesorji delujejo tako, da ˇcakajo na sporoˇcilo od predhodnika,
ˇ vsak procesor za
nato vrednosti, ki jo dobijo, dodajo 1 in jo posredujejo naprej. Ce
svojo operacijo potrebuje konstanten ˇcas, je ˇcas, ki ga porabi algoritem, velikostnega
reda globine drevesa (dolˇzine najdaljˇse veje), kar pomeni v primeru uravnoteˇzenega
drevesa Θ(log2 n), v najslabˇsem primeru (ko se drevo izrodi v eno samo vejo) pa Θ(n).
Izkaˇze pa se, da je moˇzno uporabiti algoritem za asociativni produkt zaˇcetnih
elementov seznama za izraˇcun globine drevesa v najslabˇsem ˇcasu Θ(log2 n). Postopamo tako, da vsakemu vozliˇsˇcu priredimo dva procesorja (slika 9.9). Procesor A
opravi izraˇcun, ki ustreza vstopu v poddrevo, katerega koren je vozliˇsˇce, procesor B
pa opravi izstopni izraˇcun. Vrednost, ki je prirejena procesorju A je +1, procesorju
ˇ procesorje sklenemo v seznam, ki ustreza obisku vseh vozliˇsˇc drevesa od
B pa −1. Ce
zgoraj navzdol in od leve proti desni (gl. npr. sliko 9.10) in ˇce kot asociativno operacijo, ki se pojavlja v asociativnem produktu zaˇcetnih elementov seznama, doloˇcimo
seˇstevanje (+), je [1, iA ] prav globina vozliˇsˇca, kateremu je prirejen procesor iA . Natanˇcno pravilo, kako povezujemo procesorje, je naslednje:
Naj bo v neko vozliˇsˇce drevesa. Potem mu priredimo procesorja Av in Bv .
1. V primeru, ko ima v 0 naslednikov, je naslednik procesorja Av v
9.5. POVZETEK OSNOVNIH POJMOV
195
Slika 9.10: Povezanost procesorjev za primer na sliki 9.8
seznamu procesorjev, procesor Bv . V primeru pa, ko je ˇstevilo naslednikov razliˇcno od niˇc in je w prvi naslednik v (gledano z leve), je
naslednik procesorja Av v seznamu procesorjev, procesor Aw .
2. V primeru, ko je v koren drevesa, Bv nima naslednikov v seznamu
procesorjev, sicer pa imamo dva primera: v je drugi naslednik nekega vozliˇsˇca w (gledano z leve), ali pa je prvi naslednik. V prvem
primeru (v je drugi naslednik) je naslednik procesorja Bv v seznamu
procesorjev, Bw . V drugem primeru, ko je v prvi naslednik w, naj
bo drugi naslednik w, vozliˇsˇce v 0 . Tedaj je naslednik procesorja Bv
v seznamu procesorjev, Av0 .
9.5
Povzetek osnovnih pojmov
1. Vzporedno raˇcunanje. Model raˇcunalnika PRAM
2. Osnovni razredi vzporednih raˇcunalnikov
3. Osnovni stavki vzporednega raˇcunanja
4. Problem razdalje do konca seznama in tehnika prestavljanja kazalcev
5. Asociativni produkt zaˇcetnih elementov seznama
6. Globina drevesa.
9.6
Naloge
1. Opiˇsite algoritem vrste zbzz, ki porabi ˇcas Θ(log n) in za vsak element nekega linearnega seznama dolˇzine n ugotovi, ali je srednji element (ima indeks bn/2c).
2. Opiˇsite algoritem vrste zbzz, ki porabi ˇcas Θ(log n) in ki raˇcuna asociativni produkt
zaˇcetnih elementov neke tabele a[i] pri 1 ≤ i ≤ n. V tem primeru ne uporabljajte
kazalcev, temveˇc izvajajte izraˇcune neposredno nad indeksi.
196
POGLAVJE 9. VZPOREDNI ALGORITMI
3. V nekem linearnem seznamu pripadajo elementi dvema razredoma, A in B. Sestavite
uˇcinkovit algoritem vrste zbzz, ki seznam razdeli na dva seznama, od katerih vsak
vsebuje elemente le ene vrste.
Dodatek A
ˇ
KRATEK PRIROCNIK
JEZIKA OBERON-21
A.1
Uvod
Oberon-2 je sploˇsen programski jezik, ki nadaljuje tradicijo Pascala in Module-2. Njegove
najpomembnejˇse odlike so bloˇcna zgradba, modularnost, moˇznost loˇcenega prevajanja posameznih modulov, statiˇcno doloˇcanje tipov, krepko preverjanje tipov (celo preko mej modulov), moˇznost razˇsirjanja tipov ter moˇznost deklaracije procedur, ki so pridruˇzene tipom.
Moˇznost razˇsirjanja tipov pomeni, da je Oberon-2 objektno usmerjen jezik. Objekt
je spremenljivka, ki pripada nekemu abstraktnemu podatkovnemu tipu, in ki ji pripadajo
(katere vrednost se sestoji iz) doloˇceni podatki ter procedure, ki uporabljajo te podatke.
Abstraktni podatkovni tipi so deklarirani kot razˇsirljivi zapisi. Posebnost Oberona-2 je, da
je veˇcina pojmov, ki se pojavljajo v objektno usmerjenih jezikih, definirana z ustaljeno terminologijo imperativnih jezikov, kar ima za posledico manjˇse ˇstevilo poimenovanj za sorodne
pojme.
Razdelek A.12 definira nekatere pojme, ki so potrebni za pojasnilo pravil o preverjanju
tipov v Oberonu-2. Na mestih, kjer te pojme uporabljamo, jih piˇsemo v poˇsevnem tisku,
zato da nakaˇzemo njihov poseben pomen.
A.2
Sintaksa
Sintakso jezika Oberon-2 opisujemo s tim. razˇsirjenim Backus-Naurovim formalizmom
(EBNF). Osnovne lastnosti tega zapisa so, da nakazujemo alternative z navpiˇcno ˇcrto | ,
dele zapisa, ki niso obvezni (so pa dovoljeni) s pravokotnima oklepajema [ ter ], ponavljajoˇce
se dele zapisa (pri ˇcemer je ˇstevilo ponavljanj lahko tudi 0) pa z zavitima oklepajema { ter
}. Sintaktiˇcne zvrsti (oziroma nekonˇcne simbole) zapisujemo z velikimi zaˇcetnicami (npr.
1 Priˇ
cujoˇ
ci sestavek je prevod dela M¨
osenb¨
ock in N. Wirth [13]. Delo ni namenjeno kot uˇ
cbenik
jezika temveˇ
c le kot priroˇ
cnik. Torej je namenjeno bralcu, ki jezik ˇ
ze pozna in si ˇ
zeli le osveˇ
ziti in
natanˇ
cno priklicati v spomin razliˇ
cne pojme.
197
198
JEZIK OBERON-2
Statement), medtem ko simbole konˇcnega zapisa (oziroma konˇcne simbole) zapisujemo bodisi z malimi zaˇcetnicami, kadar gre za mnoˇzice (npr. ident), bodisi z znakovnimi zaporedji,
ki so sestavljena iz samih velikih ˇcrk (npr. BEGIN), bodisi jih zapisujemo v obliki poljubnih
znakovnih zaporedij v navednicah (npr. “:=”)2 .
A.3
Osnovni elementi jezika ter njihova predstavitev
Znakovna predstavitev konˇcnih simbolov jezika je definirana na podlagi znakovnega nabora
ASCII. Vrste konˇcnih simbolov so naslednje: imena, ˇstevila, znakovna zaporedja, operatorji
ter loˇcila. Poleg teh elementov program sestavljajo tudi ˇse komentarji. Vedno upoˇstevamo
tudi naslednji pravopisni pravili: presledek ter konec vrstice se ne sme pojavljati znotraj
simbola (razen pri komentarjih ter znakovnih zaporedjih). Ta dva elementa upoˇstevamo le
kot loˇcila med simboli. Drugo pravilo je, da razlikujemo med velikimi in malimi ˇcrkami.
1. Imena (angl. identifiers) so zaporedja ˇcrk in ˇstevk, pri ˇcemer mora biti prvi znak ˇcrka.
ident → letter { letter | digit }
Primeri:
x Scan Oberon2 GetSymbol firstLetter
ˇ
2. Stevila
(angl. Numbers) so nenegativna cela ˇstevila ali realne konstante. Tip celoˇstevilˇcne
konstante je minimalen tip, ki mu konstanta pripada (gl. A.6.1). Ko je konstanta zapisana
s konˇcnico H, je predstavitev ˇsestnajstiˇska, sicer desetiˇska.
Realno ˇstevilo je vedno zapisano z decimalno piko. Morebiti vsebuje tudi red velikost
ˇ
(angl. Scale Factor) v desetiˇskem zapisu. Crki
E ali D pomenita “krat 10 na potenco”.
Realno ˇstevilo pripada tipu REAL, razen v primeru, ko red velikosti vsebuje ˇcrko D. V tem
primeru pripada tipu LONGREAL.
number → integer | real
integer → digit { digit } | digit { hexDigit } “H”
real → digit{ digit } “.” { digit } [ScaleF actor]
ScaleFactor → ( “E” | “D” ) [ “ + ” | “ − ” ] digit { digit }
hexDigit → digit | “A” | “B” | “C” | “D” | “E” | “F”
digit → | “0” | “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9”
Primeri:
1991
0DH
12.3
4.567E8
0.57712566D − 6
INTEGER
SHORTINT
REAL
REAL
LONGREAL
1991
13
12.3
456700000
0.00000057712566
3. Znakovne konstante (angl. Character Constants) predstavljamo z zaporedno ˇstevilko
znaka, ki ji sledi znak X.
character → digit { hexDigit } “X”
2 Torej
bodimo pozorni: konˇ
cni simboli so lahko sestavljeni iz veˇ
cˇ
crk.
A.4. DEKLARACIJE TER PRAVILA O VELJAVNOSTI OBJEKTOV
199
4. Znakovna zaporedja (angl. strings) so zaporedja znakov v enojnih navednicah ’ ali dvojnih
navednicah ”. Zaˇcetna navednica mora biti enaka zakljuˇcni navednici in se ne sme pojavljati
ˇ
znotraj zaporedja. Stevilu
znakov v zaporedju pravimo tudi dolˇzina zaporedja. Znakovno
zaporedje dolˇzine 1 lahko uporabljamo povsod, kjer je dovoljena znakovna konstanta (in tudi
nasprotno).
string → “”” { char } “”” | “’” { char } “’”
Primeri:
”Oberon-2” ”Don’t worry!” ”x”
5. Operatorji in loˇcila (angl. Operators and Delimiters) so posebni znaki, pari znakov ali
rezervirane besede, ki so naˇsteti spodaj. Rezervirane besede piˇsemo izkljuˇcno z velikimi
ˇcrkami in jih ne smemo uporabljati kot imena.
+
−
∗
/
∼
&
.
,
;
|
(
[
{
:=
∧
=
#
<
>
<=
>=
..
:
)
]
}
ARRAY
BEGIN
BY
CASE
CONST
DIV
DO
ELSE
ELSIF
END
EXIT
FOR
IF
IMPORT
IN
IS
LOOP
MOD
MODULE
NIL
OF
OR
POINTER
PROCEDURE
RECORD
REPEAT
RETURN
THEN
TO
TYPE
UNTIL
VAR
WHILE
WITH
5. Komentarji (angl. Comments) so poljubna znakovna zaporedja, ki se priˇcenjajo z uvodnim
znakovnim parom (*, konˇcujejo pa z *) in ki jih lahko postavimo med poljubnima dvema
simboloma v programu. Komentarje lahko gnezdimo in ne vplivajo na pomen programa.
A.4
Deklaracije ter pravila o veljavnosti objektov
Vsako ime, ki se pojavlja v programu, moramo napovedati z ustrezno deklaracijo, razen, ko
gre za vnaprej deklarirana imena. Z deklaracijami prav tako doloˇcamo nekatere nespremenljive lastnosti objektov, kot so, ali je konstanta, tip, spremenljivka ali procedura. Nato ime
uporabljamo zato, da se sklicujemo na imenovani objekt.
Objekt x je veljaven od mesta deklaracije do konca bloka (modula, procedure ali zapisa),
ki mu deklaracija pripada. Pravimo, da je v tem bloku objekt x lokalen. Objekt x ni veljaven
v vgnezdenih blokih, ki vsebujejo objekte z istim imenom. Pravila o veljavnosti so naslednja:
1. Na poljubnem mestu v programu eno in isto ime ne more oznaˇcevati veˇc kot en objekt
(z drugimi besedami: v bloku ne moremo deklarirati nekega imena veˇckrat).
2. Na objekt se lahko sklicujemo le znotraj njegovega podroˇcja veljavnosti.
3. Nek tip T , ki ima obliko POINTER TO T1 (gl. A.6.3) lahko deklariramo pred veljavnostjo T1 , vendar mora biti T1 deklarirano kasneje v istem bloku (znotraj katerega je
T lokalen).
200
JEZIK OBERON-2
4. Ime, ki oznaˇcuje komponento zapisa (gl. A.6.3) ali proceduro, ki je pridruˇzena tipu
(gl. A.10.2), je veljavno le kot sestavni del oznaˇcevalca (angl. designator) zapisa.
Imenu, ki je deklarirano v nekem modulu, lahko v deklaraciji dodamo oznako za izvoz
(“∗” ali “−”), ki pove, da je ime izvoˇzeno (na voljo v drugih modulih). Ime x, ki ga izvaˇza
modul M lahko uporabljamo v drugih modulih, pod pogojem, da le-ti uvaˇzajo M (gl. razdelek
A.11). V modulih, ki uvaˇzajo x, se nanj sklicujemo z M.x in v takem primeru pravimo, da
je M.x kvalificirano ime. Spremenljivk z imeni, ki jim je v deklaraciji pripisano “−”, ne
moremo spreminjati v modulih, ki taka imena uvaˇzajo (take spremenljivke dovoljujejo le
branje).
Qualident → [ ident “.” ] ident
IdentDef → ident [ “ ∗ ” | “ − ” ]
Naslednja imena so vnaprej deklarirana, njihov pomen pa je opisan v oznaˇcenih razdelkih:
ABS
(A.10.3)
ASH
(A.10.3)
BOOLEAN (A.6.1)
CAP
(A.10.3)
CHAR
(A.6.1)
CHR
(A.10.3)
COPY
(A.10.3)
DEC
(A.10.3)
A.5
ENTIER (A.10.3)
EXCL
(A.10.3)
FALSE
(A.6.1)
HALT
(A.10.3)
INC
(A.10.3)
INCL
(A.10.3)
INTEGER (A.6.1)
LEN
(A.10.3)
LONG
(A.10.3)
LONGINT (A.10.3)
LONGREAL (A.6.1)
MAX
(A.10.3)
MIN
(A.10.3)
NEW
(A.10.3)
ODD
(A.10.3)
ORD
(A.10.3)
REAL
(A.6.1)
SET
(A.6.1)
SHORT
(A.10.3)
SHORTINT (A.6.1)
SIZE
(A.10.3)
TRUE
(A.6.1)
Deklaracije konstant
Deklaracija konstante pripiˇse nekemu imenu konstantno vrednost.
ConstantDeclaration → IdentDef “=” ConstExpression
ConstExpression → Expression
Konstanten izraz (ConstExpression) je nek izraz, ki ga lahko izraˇcunamo le z branjem
programa, ne da bi programa bilo potrebno izvajati. Operandi izraza so lahko konstante
(razdelek A.8) ali vnaprej deklarirane funkcije, ki jih je moˇzno izraˇcunati v ˇcasu prevajanja.
Sledijo primeri konstantnih izrazov:
N = 100
limit = 2 ∗ N − 1
f ullSet = {M IN (SET )..M AX(SET )}
A.6
Deklaracije tipov
Podatkovni tip doloˇca mnoˇzico vrednosti, kateri lahko pripadajo vrednosti spremenljivk tega
tipa, kakor tudi operatorje, ki so dovoljeni. Deklaracija tipa pripiˇse tipu ime, v primeru
strukturiranih tipov (tabel in zapisov) pa tudi doloˇca zgradbo spremenljivk.
TypeDeclaration → IdentDef “=” T ype
Type → Qualident | ArrayT ype | RecordT ype |
P ointerT ype | P rocedureT ype
Primeri:
Table = ARRAY N OF REAL
Tree = POINTER TO Node
A.6. DEKLARACIJE TIPOV
201
Node = RECORD
key: INTEGER;
left,right: Tree
END
CenterTree = POINTER TO CenterNode
CenterNode = RECORD (Node)
width: INTEGER;
subnode: Tree
END
Function = PROCEDURE(x : INTEGER):INTEGER
A.6.1
Osnovni tipi
Osnovne tipe oznaˇcujemo z vnaprej deklariranimi imeni. Ustrezni operatorji so definirani
v razdelku A.8.2, ustrezne vnaprej deklarirane procedure oziroma funkcija pa v razdelku
A.10.3. Elementi (vrednosti) osnovnih tipov so definirane takole:
1.
2.
3.
BOOLEAN
CHAR
SHORTINT
4.
INTEGER
5.
LONGINT
6.
7.
REAL
LONGREAL
8.
SET
logiˇcni vrednosti TRUE (resniˇcno) in FALSE (neresniˇcno)
znaki razˇsirjenega znakovnea nabora ASCII (0X..0FFX)
cela ˇstevila v mejah od MIN(SHORTINT) do
MAX(SHORTINT)
cela ˇstevila v mejah od MIN(INTEGER) do
MAX(INTEGER)
cela ˇstevila v mejah od MIN(LONGINT) do
MAX(LONGINT)
realna ˇstevila v mejah od MIN(REAL) do MAX(REAL)
realna ˇstevila v mejah od MIN(LONGREAL) do
MAX(LONGREAL)
podmnoˇzice ˇstevil v mejah od 0 do MAX(SET)
Tipi od 3 do 5 so celoˇstevilˇcni tipi, tipa 6 in 7 sta realna tipa, skupaj pa predstavljajo ˇstevilˇcne
tipe. Slednji tipi tvorijo hierarhijo, v smislu, da manjˇsi tipi predstavljajo podmnoˇzice veˇcjih:
LONGREAL ⊇ REAL ⊇ LONGINT ⊇ INTEGER ⊇ SHORTINT
A.6.2
Tabelariˇ
cni tipi
Tabela je struktura, ki je sestavljena iz elementov (komponent), ki pripadajo istemu tipu,
ˇ
ki mu pravimo tip elementa tabele. Stevilu
elementov v tabeli pravimo tudi dolˇzina tabele.
Elemente tabele oznaˇcujemo z indeksi, ki so ˇstevila od 0 do dolˇzina tabele minus 1.
ArrayType → “ARRAY” “[” Length { “, ” Length } “]” “OF” T ype
Length → ConstExpression
Zapis, ki ima obliko
ARRAY L0, L1, . . . , Ln OF T
pravzaprav prestavlja okrajˇsavo za
ARRAY L0 OF
ARRAY L1 OF
202
JEZIK OBERON-2
...
ARRAY Ln OF T
Tabelam, ki so deklarirane brez dolˇzine, pravimo odprte tabele. Uporabljamo jih lahko le na
mestu osnovnega tipa kazalca (gl. A.6.4), tipa elementa odprte tabele (gl. A.10.1) ali kot tip
formalnega parametra (gl. A.10.1). Primeri so naslednji:
ARRAY OF INTEGER
ARRAY OF CHAR
A.6.3
Tipi zapisov
Zapis3 je struktura, ki se sestoji iz vnaprej doloˇcenega ˇstevila elementov, ki jim pravimo
komponente (angl. field), ki pa lahko pripadajo razliˇcnim tipom. Deklaracija tipa zapisa
doloˇca ime in tip vsake komponente. Imena komponent so veljavna od mesta deklaracije
do konca deklaracije tipa zapisa, vendar jih je moˇzno uporabljati (“so vidna”) tudi kot
sestavne dele oznaˇcevalcev, ki oznaˇcujejo komponente spremenljivk zapisnega tipa (gl. A.8).
V primeru, ko se zapisni tip izvaˇza, se morajo komponente, ki naj bi bile vidne izven modula,
ki vsebuje deklaracijo zapisnega tipa, oznaˇciti. Takim komponentam pravimo, da so javno
dostopne, ostale so zasebne.
RecordType → “RECORD” [ “(” BaseT ype “)” ]F ieldList { “; ” F ieldList } “END”
BaseType → Qualident
FieldList → [IdentList “:” T ype]
Zapisni tipi so razˇsirljivi. Z drugimi besedami, nek tip lahko deklariramo kot razˇsiritev
oziroma podaljˇsek drugega tipa. V naslednjem primeru:
T0 = RECORD x : INTEGER END
T1 = RECORD (T0 ) y: REAL END
je T 1 (neposredna) razˇsiritev T 0, T 0 pa je (neposredni) osnovni tip za T 1 (gl. razdelek
A.12). Razˇsirjen tip T 1 se sestoji iz vseh komponent svojega osnovnega tipa, kakor tudi
iz komponent, ki so deklarirane v T 1 (gl. razdelek A.6). Vsa imena, ki so deklarirana
v razˇsirjenem zapisu morajo biti razliˇcna od imen v zapisih osnovnega tipa (ali osnovnih
tipov). Primeri deklaracij zapisnih tipov:
RECORD
day, month, year : INTEGER
END
RECORD
name, firstname: ARRAY 32 OF CHAR;
age: INTEGER;
salary: REAL
END
3 Opozarjamo na nevarnost dvoumnosti v slovenˇ
sˇ
cini, kjer uporabljamo besedo zapis tako za
prevod angleˇskega izraza record kot tudi za prevod angleˇskega izraza notation.
A.7. DEKLARACIJE SPREMENLJIVK
A.6.4
203
Tipi kazalcev
Vrednosti spremenljvik kazalˇcnega tipa P so kazalci na spremenljivke nekega tipa T . Tipu
T pravimo osnovni tip kazalˇcnega tipa P , mora pa biti bodisi tabelariˇcen ali zapisni tip. Na
kazalˇcne tipe se prenaˇsa relacija razˇsirjenosti osnovnega tipa: v primeru, ko je T1 razˇsiritev
tipa T , P1 pa je kazalec na T1 , je tudi P1 razˇsiritev P .
PointerType → “POINTER” “TO” T ype
ˇ je p spremenljivka tipa POINTER TO T , ima klic vnaprej deklarirane procedure
Ce
NEW(p) (gl. A.10.3) uˇcinek, da se nova spremenljivka tipa T generira v prostem delu pomnilnika. V primeru, ko p pripada zapisnemu ali tabelariˇcnemu tipu, ima klic obliko NEW(p),
ko pa p pripada tipu odprte tabele, ima klic obliko NEW(p, e0 , . . . , en−1 ), kjer so dolˇzine
generirane tabele po ustreznih dimenzijah enake vrednostim izrazov e0 , . . . , en−1 . V obeh
primerih se kazalec na novo spremenljivko priredi spremenljivki p, ki pripada tipu P . Spremenljivka p∧, na katero kaˇze p (izgovarja se kot “cilj kazalca p”), je tipa T . Spremenljivka
nekega poljubnega kazalˇcnega tipa ima lahko tudi vrednost NIL, ki predstavlja odsotnost
cilja (spremenljivka vsebuje prazen kazalec).
A.6.5
Tipi procedur
ˇ
Vrednosti spremenljivk, ki pripadajo tipom procedur, so bodisi procedure, bodisi NIL. Ce
spremenljivki procedurnega tipa T priredimo proceduro P , morata biti seznama formalnih
parametrov (gl. razdelek A.10.1) P in T skladna (gl. razdelek A.12). Za P velja tudi, da ne
more biti vnaprej deklarirana procedura, niti je lahko procedura, ki je lokalno deklarirana v
ˇ velja slednja lastnost pravimo, da je P globalna procedura.
drugi proceduri. Ce
ProcedureType → “PROCEDURE” [ F ormalP arameters ]
A.7
Deklaracije spremenljivk
Z deklaracijami spremenljivk izbiramo imena spremenljivk kakor tudi njihov podatkovni tip.
VariableDeclaration → IdentList “:” T ype
Spremenljivke zapisnega ali kazalˇcnega tipa imajo tako statiˇcni tip (tip, ki se pojavlja v
deklaraciji – pravimo mu tudi kar spremenljivkin tip), kakor tudi dinamiˇcni tip (tip kateremu
pripadajo v danem trenutku med izvajanjem). Pri spremenljivkah zapisnega ali kazalˇcnega
tipa je lahko dinamiˇcni tip razˇsiritev njihovega statiˇcnega tipa. Statiˇcni tip doloˇca, katere
komponente zapisa so dostopne. Dinamiˇcni tip pa se uporablja za klice procedur, ki so pridruˇzene tipom (gl. A.10.2). Sledijo primeri deklaracij spremenljivk (nanaˇsajo se na primere
iz razdelka A.6):
i, j , k : INTEGER
x , y: REAL
p, q: BOOLEAN
s: SET
F : Function
a: ARRAY 100 OF REAL
w : ARRAY 16 OF RECORD
name: ARRAY 32 OF CHAR;
ccount: INTEGER
END
204
JEZIK OBERON-2
t, c: Tree
A.8
Izrazi
Izrazi so jezikovne oblike, ki predstavljajo raˇcunska navodila, na podlagi katerih se uporabljajo operatorji ter funkcijske procedure s konstantami ter trenutnimi vrednostmi spremenljivk za izraˇcun novih vrednosti. Izrazi so sestavljeni iz operandov in operatorjev, uporabljamo pa lahko tudi oklepaja, da nakaˇzemo, katerim operatorjem so operandi pridruˇzeni.
A.8.1
Operandi
Z izjemo konstruktorjev mnoˇzic ter dobesednih konstant (ˇstevil, znakovnih konstant ter zankovnih zaporedij) se na operande sklicujemo z oznaˇcevalci (angl. designator). Oznaˇcevalec
ima za osnovo ime neke konstante, spremenljivke ali procedure, ki je morebiti kvalificirano
z imenom nekega modula (gl. razdelke A.4 in A.11), dodamo pa mu lahko ˇse selektorje v
primeru, ko je oznaˇceni objekt komponenta neke strukture.
Designator → Qualident { “.” ident | “[”ExpressionList “]” |
“∧” | “(”Qualident “)”}
ExpressionList → Expression { “, ” Expression }
V primeru, ko a oznaˇcuje tabelo, oznaˇcuje a[e] komponento tabele z indeksom, ki je
enak trenutni vrednosti izraza e. e mora pripadati celoˇstevilˇcnemu tipu. Oznaˇcevalec oblike
a[e0 , e1 , . . . , en ] predstavlja a[e0 ][e1 ] . . . [en ]. V primeru, ko je r zapis, oznaˇcuje r.f komponento f zapisa r ali proceduro f , ki je pridruˇzena dinamiˇcnemu tipu r (gl. A.10.2). V primeru,
ko p oznaˇcuje kazalec, oznaˇcuje p∧ spremenljivko, na katero kaˇze p (cilj spremenljivke p).
Oznaˇcevalca p∧.f in p∧[e] lahko skrajˇsamo v p.f in p[e], z drugimi besedami pri zapisnem
ali tabelariˇcnem selektorju je operacija premika do cilja (angl. dereferencing) privzeta. V
primeru, ko je a ali r dosegljivo le za branje, velja isto tudi za a[e] ter r.f .
Tipska zahteva v(T ) predstavlja zahtevo, naj bo dinamiˇcni tip v enak T (ali razˇsiritvi
T ), v nasprotnem se izvajanje programa nasilno prekine (angl. abort). V oznaˇcevalcu, kjer
se pojavlja v(T ), pa je privzeto, da ima v statiˇcni tip T . Tipsko zahtevo lahko uporabljamo
v primeru, ko je v
1. procedurni referenˇcni parameter ali, ko je kazalec ter je
2. T razˇsiritev statiˇcnega tipa v.
V primeru, ko je oznaˇceni objekt konstanta ali spremenljivka, se oznaˇcevalec nanaˇsa
na njeno trenutno vrednost. V primeru, ko je oznaˇceni objekt procedura, se oznaˇcevalec
nanaˇsa na proceduro, razen, ko mu sledi (morebiti prazen) seznam parametrov, kar pomeni
klic procedure in v takem primeru se oznaˇcevalec nanaˇsa na vrednost, ki je rezultat klica
procedure. Stvarni parametri v klicu procedure morajo ustrezati formalnim parametrom,
kot to velja pri klicih nefunkcijskih procedur (gl. A.10.1). Sledijo primeri oznaˇcevalcev (gl.
primere iz razdelka A.7):
i
a[i]
w[3].name[i]
t.lef t.right
t(CenterN ode).subnode
(INTEGER)
(REAL)
(CHAR)
(Tree)
(Tree)
205
A.8. IZRAZI
A.8.2
Operatorji
V izrazih razlikujemo ˇstiri skupine operatorjev na podlagi njihove prednosti (pri delovanju
na operande). Operator ∼ se izvaja prvi, nato sledijo operatorji podobni mnoˇzenju, nato
operatorji podobni seˇstevanju in konˇcno operatorji, ki predstavljajo relacije. Operatorji, ki
so enako postavljeni na prednostni lestvici, se izvajajo od leve proti desni. Na primer x−y−z
predstavlja (x − y) − z.
Expression → SimpleExpression [ Relation SimpleExpression ]
SimpleExpression → [ “ + ” | “ − ” ] T erm { AddOperator T erm }
Term → F actor { M ulOperator F actor }
Factor → Designator [ ActualP arameters ] | number | character |
string | NIL | Set | “(” Expression “)” | “∼” F actor
Set → “{” [ Element { “, ” Element}] “}”
Element → Expression [ “..” Expression ]
ActualParameters → “(” ExpressionList “)”
Relation → ““=”” | “#” | “ < ” | “ <= ” | “ > ” | “ >= ” | “IN” | “IS”
AddOperator → “ + ” | “ − ” | “OR”
MulOperator → “ ∗ ” | “/” | “DIV” | “MOD” | “&”
Razpoloˇzljivi operatorji so naˇsteti v tabelah, ki sledijo. Nekateri operatorji se lahko uporabljajo z veˇc tipi operandov, kar pomeni, da predstavljajo veˇc operacij. V takem primeru je
operacija doloˇcena ˇsele s tipom operanda. V vsakem primeru morajo biti operandi skladni
z operatorji za uporabo v izrazih (angl. expression compatible). Gl. razdelek A.12.
Logiˇ
cni operatorji
OR
logiˇcna disjunkcija
p OR q
&
logiˇcna konjunkcija
p&q
∼
logiˇcna negacija
∼p
“ˇce je p resniˇcno, je vrednost TRUE,
sicer je vrednost enaka q”
“ˇce je p resniˇcno, je vrednost q,
sicer je vrednost enaka FALSE”
“ˇce je p resniˇcno, je vrednost FALSE,
sicer je vrednost TRUE
Naˇsteti operatorji se uporabljajo z logiˇcnimi vrednostmi (tipa BOOLEAN) in dajejo tudi
vrednosti tipa BOOLEAN.
Aritmetiˇ
cni operatorji
+
−
∗
/
DIV
MOD
vsota
razlika
produkt
realni kvocient
celoˇstevilˇcni kvocient
ostanek po modulu
Operatorji +, −, ∗ in / delujejo na operande numeriˇcnih tipov. Tip rezultata je veˇcji
(obseˇznejˇsi) od tipov operandov, razen pri /, kjer je tip rezultata najmanjˇsi realen tip, ki
ˇ − ali + uporabljamo kot eniˇski operator, prvi uˇcinkuje kot zamevsebuje oba operanda. Ce
njava predznaka, drugi pa kot identiteta. Operanda DIV in MOD delujeta le na celoˇstevilˇcne
operande in sta povezana z naslednjima formulama, pri ˇcemer je x poljubno, y pa pozitivno:
206
JEZIK OBERON-2
x = (x DIV y) ∗ y + (x MOD y)
0 ≤ (x MOD y) < y
Primeri:
x
5
−5
y
3
3
x DIV y
1
−2
x MOD y
2
1
Operatorji na mnoˇ
zicah
+
−
∗
/
unija
razlika mnoˇzic (x − y = x ∩ y)
presek
simetriˇcna razlika mnoˇzic (x/y = (x − y) ∪ (y − x))
Operatorji na mnoˇzicah uporabljajo operande, ki pripadajo tipu SET, istemu tipu pa pripada tudi rezultat. Eniˇski minus oznaˇcuje komplement mnoˇzice x, torej je −x podmnoˇzica
elementov med 0 in MAX(SET), ki ne pripadajo mnoˇzici x. Operatorji na mnoˇzicah niso
asociativni ((a + b) − c 6= a + (b − c)).
Konstruktor mnoˇzice definira mnoˇzico tako, da naˇsteje njene elemente znotraj zavitih
oklepajev. Elementi so lahko cela ˇstevila v mejah med 0 in MAX(SET). Razpon a..b
predstavlja vsa cela ˇstevila v intervalu [a, b].
Relacije
=
#
<
<=
>
>=
IN
IS
enako
neenako
manjˇse od
manjˇse ali enako kot
veˇcje od
veˇcje ali enako kot
pripadnost mnoˇzici
preverjanje tipa
Rezultat uporabe relacije pripada tipu BOOLEAN. Relacije =, #, <, <=, > ter >= so
smiselne pri operandih, ki pripadajo numeriˇcnim tipom, tipu CHAR, ali tabelariˇcnim tipom
s tipom elementov CHAR, pod pogojem, da je znakovno zaporedje zakljuˇceno z znakom 0X.
Relaciji = ter # sta definirani tudi na tipih BOOLEAN ter SET, kakor tudi na kazalˇcnih
ter procedurnih tipih (ki vkljuˇcuje vrednost NIL). x IN s predstavlja predikat “x pripada
mnoˇzici s”, pri ˇcemer x pripada celoˇstevilˇcnemu tipu, s pa tipu SET. v IS T predstavlja
predikat “dinamiˇcni tip v je T (ali razˇsiritev T )” in mu pravimo preizkus tipa (angl. type
test). Uporabiti ga je moˇzno
1. kadar je v spremenljivka zapisnega ali kazalˇcnega tipa in je
2. T razˇsiritev statiˇcnega tipa v.
Primeri izrazov so naslednji (gl. primere iz razdelka 7):
207
A.9. STAVKI
1991
i DIV 3
∼p OR q
(i + j) ∗ (i − j)
s − {8, 9, 13}
i+x
a[i + j] ∗ a[i − j]
(0 <= i)&(i < 10)
t.key = 0
k IN {i..j − 1}
w[i].name <= ”John”
t IS CenterN ode
A.9
INTEGER
INTEGER
BOOLEAN
INTEGER
SET
REAL
REAL
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
Stavki
Stavki oznaˇcujejo dejanja. Razlikujemo med elementarnimi in sestavljenimi stavki. Elementarni stavki ne vsebujejo delov, ki bi sami bili stavki, so pa naslednji: prirejanje (angl.
assignment), klic procedure, vrnitev iz klica (angl. return) ter izhod iz bloka (angl. exit).
Sestavljeni stavki vsebujejo dele, ki so tudi sami stavki, uporabljamo pa jih za oznaˇcevanje
zaporedja dejanj ter za pogojno, izbirno in ponavljajoˇce se izvajanje dejanj. Stavek je lahko
tudi prazen, kar pomeni odsotnost dejanj. Prazen stavek se pojavlja za to, da doseˇzemo
veˇcjo enostavnost sintaksnih pravil za zaporedja stavkov.
Statement → [ Assignment | P rocedureCall | If Statement |
CaseStatementW hileStatement | RepeatStatement |
F orStatement | LoopStatementW ithStatement |
“EXIT” | “RETURN” [ Expression ] ]
A.9.1
Prirejanje
Prirejanje nadomesti trenutno vrednost spremenljivke z novo vrednostjo, ki jo doloˇca nek
izraz. Izraz mora biti skladen s spremenljivko za uporabo v prirejanju (gl. razdelek A.12).
Zapis za operator prirejanja je “:=”, izgovarjamo pa ga kot “postane”.
Assignment → Designator “ := ” Expression
Ko se izraz e, katerega vrednost pripada tipu Te , priredi spremenljivki v, ki pripada tipu
Tv , se zgodi naslednje:
1. v primeru, ko sta Tv in Te zapisna tipa, se priredijo le tiste komponente Te , ki pripadajo
tudi tipu Tv (projekcija). Dinamiˇcni tip v mora biti isti kot statiˇcni tip v in se ne
spremeni kot posledica prirejanja;
2. ko sta Tv in Te kazalˇcna tipa, postane dinamiˇcni tip v enak dinamiˇcnemu tipu e;
3. ko je Tv enak ARRAY n OF CHAR in je e znakovni niz dolˇzine m < n, postane v[i]
enako e[i], pri 0 ≤ i ≤ m − 1, v[m] pa postane enako 0X.
Sledijo primeri prirejanj (gl. primere iz razdelka A.7):
i := 0
p := i = j
x := i + 1
k := log2(i + j)
208
JEZIK OBERON-2
F := log2
s := {2, 3, 5, 7, 11, 13}
a[i] := (x + y) ∗ (x − y)
t.key := i
w[i + 1].name := ”John”
t := c
A.9.2
Klici procedur
Klic procedure sproˇzi njeno delovanje. Klic procedure morebiti vsebuje tudi seznam stvarnih
parametrov, ki nadomestijo ustrezne formalne parametre, ki jih doloˇca deklaracija procedure
(gl. razdelek A.6.5). Sovpadanje med stvarnimi in formalnimi parametri se ugotavlja na
podlagi njihovega poloˇzaja na seznamu stvarnih oziroma formalnih parametrov. Obstajata
dve vrsti parametrov: referenˇcni in vrednostni.
ˇ je nek formalni parameter referenˇcni, mora biti ustrezni stvarni parameter oznaˇcevalec
Ce
neke spremenljivke. V primeru, ko se oznaˇcevalec nanaˇsa na neko strukturirano spremenljivko, se ustrezni selektorji izraˇcunajo v trenutku, ko se opravi zamenjava formalnih parameˇ je nek formalni parameter vrednostni,
trov s stvarnimi, torej pred sproˇzitvijo procedure. Ce
mora biti ustrezni stvarni parameter nek izraz, ki se izraˇcuna pred sproˇzitvijo procedure,
vrednost izraza pa se priredi formalnemu parametru (gl. razdelek A.10.1).
ProcedureCall → Designator [ ActualP arameters ]
Primeri:
WriteInt(i ∗ 2 + 1)
INC(w[k].count)
t.Insert(”John”)
A.9.3
Stavˇ
cna zaporedja
Stavˇcna zaporedja nakazujejo zaporedje dejanj, ki jih doloˇcajo stavki, ki tvorijo zaporedje.
Meje med stavki nakazujemo s podpiˇcji.
StatementSequence → Statement { “; ” Statement }
A.9.4
Pogojni stavki
IfStatement → “IF” Expression “THEN” StatementSequence
{ “ELSIF” Expression “THEN” StatementSequence }
[ “ELSE” StatementSequence ]
Pogojni stavki doloˇcajo pogojno izvajanje stavˇcnih zaporedij v primeru, ko je izpolnjen
ustrezni pogoj. Pogoju, ki stoji pred stavˇcnim zaporedjem, pravimo kar pogoj za izvajanje
stavˇcnega zaporedja (angl. statement sequence guard). Pogoji stavˇcnih zaporedij se raˇcunajo
po vrsti, dokler ne pridemo do nekega z vrednostjo TRUE, po ˇcemer se izvaja ustrezno
stavˇcno zaporedje. V primeru, ko noben pogoj nima vrednosti TRUE, se izvaja stavˇcno
zaporedje, ki sledi loˇcilu ELSE (v kolikor se navedeno loˇcilo sploh pojavlja).
Primer:
IF (ch >= “A” & (ch <= “Z”) THEN ReadIdentifier
ELSIF (ch >= “0”) & (ch <= “9”) THEN ReadNumber
ELSIF (ch = 0 ”0 ) OR (ch = “0 ”) THEN ReadString
A.9. STAVKI
209
ELSE SpecialCharacter
END
A.9.5
Izbirni stavek
Izbirni stavek predpisuje izbiro ter izvajanje nekega stavˇcnega zaporedja na podlagi vrednosti
nekega izraza. Najprej se izraˇcuna vrednost izraza, nato pa se izvaja stavˇcno zaporedje,
katerega seznam oznak (angl. case label list) vsebuje vrednost izraza. Izbirni izraz pripada
bodisi celoˇstevilˇcnemu tipu, ki vsebuje vse vrednosti, ki se pojavljajo v seznamih oznak ali
pa morajo izbirni izraz in vrednosti v seznamih oznak pripadati tipu CHAR. Izbirne oznake
so konstante in vsaka se lahko pojavlja le enkrat v vseh seznamih oznak. V primeru, ko se
vrednost izbirnega izraza ne pojavlja v seznamih oznak, se izvaja stavˇcno zaporedje, ki sledi
loˇcilu ELSE, ˇce pa tega loˇcila ni, se program nasilno prekine.
CaseStatement → “CASE” Expression “OF” Case { “ | ” Case }
[ “ELSE” StatementSequence ]
“END”
Case → [ CaseLabelList “:” StatementSequence ]
CaseLabelList → CaseLabels { “, ” CaseLabels }
CaseLabels → ConstExpression [ “..” ConstExpression ]
Primer:
CASE ch OF
“A” .. “Z”: ReadIdentifier
| “0” .. “9”: ReadNumber
| “0 ” , 0 ”0 : ReadString
ELSE SpecialCharacter
END
A.9.6
Stavek While
Stavek While ali zanka s izstopnim pogojem na zaˇcetku, predpisuje ponavljanje izvajanja
nekega stavˇcnega zaporedja dokler ima nek pogoj v obliki logiˇcnega izraza, ki mu pravimo
pogoj stavka While, vrednost TRUE. Vrednost pogoja se izraˇcuna pred vsakim izvajanjem
stavˇcnega zaporedja.
WhileStatement → “WHILE” Expression “DO” StatementSequence “END”
Primeri:
WHILE i > 0 DO i:=i DIV 2 ; k :=k +1 END
WHILE (t # NIL) & (t.key # i) DO t:=t.left END
A.9.7
Stavek Repeat
Stavek Repeat ali zanka z izstopnim pogojem na koncu predpisuje ponavljanje izvajanja nekega stavˇcnega zaporedja do trenutka, ko postane vrednost nekega pogoja v obliki logiˇcnega
izraza, ki mu pravimo pogoj stavka Repeat, enaka TRUE. Stavˇcno zaporedje se izvaja najmanj enkrat.
210
JEZIK OBERON-2
RepeatStatement → “REPEAT” StatementSequence “UNTIL” Expression
A.9.8
Stavek For
Stavek For ali zanka s kontrolno spremenljivko predpisuje veˇckratno izvajanje nekega stavˇcnega
zaporedja, pri ˇcemer je ˇstevilo izvajanj vnaprej doloˇceno, neki celoˇstevilˇcni spremenljivki (ki
ji pravimo kontrolna spremenljivka stavka For) pa pri vsakem zvajanju priredimo novo vrednost, tako da se zaporedne vrednosti razlikujejo za enak prirastek.
ForStatement → “FOR” ident “ := ” Expression “TO” Expression
[ “BY” ConstExpression ] “DO” StatementSequence
“END”
Stavek
FOR v := beg TO end BY step DO statements END
ima isti uˇcinek kot
temp := end ; v := beg ;
IF step > 0 THEN
WHILE v <= temp DO statements ; v := v +step END
ELSE
WHILE v >= temp DO statements ; v := v +step END
END;
temp pripada istemu tipu kot v. step je neniˇcelen konstantni izraz. V primeru, ko je step
odsotno, je privzeta vrednost 1.
Primera:
FOR i := 0 TO 79 DO k := k + a[i] END
FOR i := 79 TO 1 BY −1 DO a[i] := a[i−1] END
A.9.9
Stavek Loop
Stavek Loop ali enostavna zanka predpisuje ponavljanje nekega stavˇcnega zaporedja, ki se
prekine po izvrˇsitvi nekega stavka Exit znotraj stavˇcnega zaporedja (gl. A.9.10).
LoopStatement → “LOOP” StatementSequence “END”
Primer:
LOOP
ReadInt(i);
IF i < 0 THEN EXIT END;
WriteInt(i)
END
Namen stavka For je zapis ponavljanj, ki vsebujejo veˇc izhodov ali pa je izhod postavljen
v sredi ponavljanja.
A.10. DEKLARACIJE PROCEDUR
A.9.10
211
Stavka Return ter Exit
Stavek Return ali izhod iz procedure nakazuje zakljuˇcek neke procedure. Oznaˇcuje ga simbol
RETURN, ki mu sledi izraz v primeru, ko gre za funkcijsko proceduro. Izraz mora pripadati
tipu, ki je skladen glede prirejanja (gl. razdelek A.12) s tipom rezultata funkcijske procedure,
kot je zapisan v naslovu procedure (gl. razdelek A.10).
Funkcijske procedure morajo vsebovati stavek Return, ki doloˇca vrednost procedure.
ˇ
Pri nefunkcijskih procedurah je obiˇcajni zakljuˇcek procedure na koncu jedra procedure. Ce
obstajajo dodatni stavki Return, le-ti nakazujejo dodatne (in verjetno izredne) zakljuˇcke
delovanja procedure.
Stavek Exit ali izhod iz zanke zapiˇsemo s simbolom EXIT, nakazuje pa prenehanje ponavljanj, ki jih doloˇca stavek Loop, znotraj katerega je postavljen stavek Exit, in nadaljevanje
programa s stavkom, ki sledi stavku Loop. Stavek Exit je povezan z vsebujoˇcim stavkom
Loop, ˇceprav slednji ne predpisuje kakega posebnega mesta, kjer naj se stavek Exit pojavlja.
A.9.11
Stavek With
Stavek With ali tipska kretnica predpisuje izraˇcun nekega stavˇcnega zaporedja, ki je odvisno
od rezultata nekega preizkusa tipa. Vsak primerek spremenljivke, katere tip reizkuˇsamo, je
opremljen z ustrezno tipsko zahtevo.
WithStatement → “WITH” Guard “DO” StatementSequence
{ “ | ” “DO” StatementSequence }
[ “ELSE” StatementSequence ]
“END
Guard → Qualident “:” Qualident
V primeru, ko je v spremenljivka zapisnega ali kazalˇcnega tipa in ˇce pripada statiˇcnemu
tipu T0 , ima stavek
WITH v : T1 DO S1 | v : T2 DO S2 ELSE S3 END
naslednji uˇcinek: ˇce je dinamiˇcni tip v enak T1 , se izvaja stavek S1 , pri ˇcemer se v obravnava,
kot da pripada statiˇcnemu tipu T1 , ˇce pa je dinamiˇcni tip v enak T2 , se izvaja stavek S2 , pri
ˇ nobeden od zapisanih pogojev
ˇcemer se v obravnava, kot da pripada statiˇcnemu tipu T2 . Ce
ˇ nobeno preverjanje tipa ne da rezultata resniˇcno, se program
ni izpoljnjen, se izvaja S3 . Ce
nasilno prekine.
Primer:
WITH t: CenterTree DO i:=t.width; c:=t.subnode END
A.10
Deklaracije procedur
Deklaracija procedure je sestavljena iz procedurinega naslova (angl. heading) in njenega
jedra. Naslov doloˇca ime procedure ter njene formalne parametre, v primeru procedur, ki
so pridruˇzene tipu, pa naslov doloˇca ˇse glavni parameter (angl. receiver). Jedro procedure
vsebuje deklaracije ter stavke, deklaracija procedure pa je zakljuˇcena s svojim imenom.
Imamo dve vrsti procedur: nefunkcijske ali prave procedure ter funkcijske procedure.
Slednje procedure sproˇzi funkcijski oznaˇcevalec, ki je del nekega izraza, imajo pa rezultat,
212
JEZIK OBERON-2
ki deluje kot operand izraza. Prave procedure pa se sproˇzijo s klicem procedure. Neka
procedura je funkcijska v kolikor njeni formalni parametri doloˇcajo tip rezultata. Jedro
funkcijske procedure mora vsebovati stavek Return, ki doloˇca rezultat klica procedure.
Vse konstante, tipi, spremenljivke ter procedure, ki so deklarirani znotraj procedure so
lokalni v proceduri. Ker lahko tudi druge procedure deklariramo kot lokalne objekte, imamo
lahko opravka z gnezdenimi procedurami. Klic neke procedure v lastnem jedru, povzroˇci
rekurzivno izvajanje.
Objekti, ki so deklarirani v procedurinem okolju, so veljavni v vseh delih procedure, kjer
njihova veljavnost ni bila izniˇcena z deklaracijo lokalnega objekta z istim imenom.
ProcedureDeclaration → P rocedureHeading “; ” P rocedureBody ident
ProcedureHeading → “PROCEDURE” [ Receiver ] IdentDef [ F ormalP arameters ]
ProcedureBody → DeclarationSequence [ “BEGIN” StatementSequence ] “END”
DeclarationSequence → { “CONST” { ConstantDeclaration “; ” } |
“TYPE” { T ypeDeclaration “; ” } |
“VAR” { V ariableDeclaration “; ” }
} |
{ P rocedureDeclaration “; ” | F orwardDeclaration “; ” }
ForwardDeclaractgion → “∧”“PROCEDURE”[Receiver]IdentDef [F ormalP arameters]
V kolikor ima procedura glavni parameter, se ˇsteje, da je pridruˇzena ustreznemu tipu
(gl. A.10.2). Predhodna deklaracija procedure (angl. forward declaraction) omogoˇca uporabo procedure pred mestom njene deklaracije. Seznama formalnih parametrov predhodne
deklaracije in procedurine deklaracije morata biti skladna (gl. razdelek A.12).
A.10.1
Formalni paramteri
Formalni parametri so imena, ki so deklarirana v procedurinem seznamu formalnih parametrov. Ti parametri ustrezajo stvarnim parametrom v procedurinem klicu. Povezava med
stvarnimi in formalnimi parametri se ugotovi ob procedurinem klicu. Obstajata dve vrsti
parametrov, vrednostni in referenˇcni parametri, ki se razlikujeta po odsotnosti ali prisotnosti loˇcila VAR. Vrednostni parametri so pravzaprav lokalne spremenljivke, ki se jim priredi
zaˇcetna vrednost enaka vrednosti stvarnega parametra. Referenˇcni parametri pa predstavljajo stvarne parametri, ki so spremenljivke. Podroˇcje veljavnosti formalnih parametrov
je do konca procedurinega bloka, v katerem je formalni parameter deklariran. Funkcijska
procedura brez parametrov ima obvezno prazen seznam parametrov (samo predklepaj in zaklepaj), kliˇce pa se prav tako s funkcijskim oznaˇcevalcem, ki ima prazen seznam parametrov.
Rezultat funkcijske procedure ne more biti niti zapis niti tabela.
FormalParameters → “(” [ F P Section { “; ” F P Section} ] “)” [ “:” Qualident ]
FPSection → “VAR” ident { “, ” ident } “:” T ype
Naj bo Tf tip nekega formalnega parametra f (privzemamo, da Tf ni odprta tabela) in
ˇ je f referenˇcni parameter, mora biti Ta
naj bo Ta tip ustreznega stvarnega parametra. Ce
ˇ je f vrednostni parameter,
isti tip kot Tf ali pa je Tf tip zapisa, Ta pa njegova razˇsiritev. Ce
mora biti a skladen z f glede prirejanja (gl. razdelek A.12). V primeru, ko pa je Tf odprta
tabela, mora biti a skladen z f kot tabela (gl. razdelek A.12). Dolˇzine f so enake ustreznim
dolˇzinam a.
Primeri deklaracij procedur:
PROCEDURE ReadInt(VAR x : INTEGER);
VAR i: INTEGER; ch: CHAR;
A.10. DEKLARACIJE PROCEDUR
BEGIN
i := 0;
Read (ch);
WHILE (“0” <= ch) & (ch <= “9”) DO
i:= 10∗i + (ORD(ch)−ORD(“0”));
Read (ch)
END;
x := i;
END ReadInt
PROCEDURE WriteInt(x : INTEGER);
(∗ 0 <= x <= 100000 ∗)
VAR i: INTEGER; buf : ARRAY 5 OF INTEGER;
BEGIN
i := 0;
REPEAT
buf [i] := x MOD 10;
x := x DIV 10;
INC (i)
UNTIL x = 0;
REPEAT
DEC (i);
Write(CHR(buf [i] + ORD(“0”))
UNTIL i = 0;
END WriteInt
PROCEDURE WriteString(s: ARRAY OF CHAR);
VAR i: INTEGER;
BEGIN
i := 0;
WHILE (i < LEN (s)) & (s[i] # 0X) DO
Write(s[i]);
INC (i)
END
END WriteString
PROCEDURE log2 (x : INTEGER): INTEGER;
VAR y: INTEGER; (∗ assume x >0 ∗)
BEGIN
y := 0;
WHILE x > 1 DO x := x DIV 2; INC (y) END;
RETURN y
END log2
213
214
JEZIK OBERON-2
A.10.2
Procedure, ki so pridruˇ
zene tipom
Globalne procedure (torej take, ki niso deklarirane lokalno znotraj druge procedure) lahko
pridruˇzimo nekemu tipu zapisa, ki je deklariran znotraj istega modula. Take procedure so
pridruˇzene temu tipu. Povezavo s tipom nakazuje tip glavnega parametra v naslovu deklaracije procedure. Glavni parameter (angl. receiver) je bodisi referenˇcni parameter zapisnega
tipa T ali vrednostni parameter, ki pripada tipu POINTER TO T , pri ˇcemer je T zapisnega
tipa. Procedura je pridruˇzena tipu T in se obravnava, kot da je lokalna temu tipu.
Receiver → “(” [ “VAR” ] ident “:” ident “)”
(sintaktiˇcna kategorija Receiver se uporablja v definiciji kategorije ProcedureHeading, ki je
zapisana na zaˇcetku razdelka A.10.)
V kolikor je procedura P pridruˇzena tipu T0 , je implicitno pridruˇzena tudi vsakemu
tipu T1 , ki je razˇsiritev T0 . Vendar lahko tipu T1 tudi izrecno pridruˇzimo proceduro P 0 ,
ki ima isto ime kot P , in tako prekliˇcema povezavo med P in T1 . Na ta naˇcin posane P 0
spremenjena definicija P za T1 . Formalni parametri P in P 0 morajo skladen (gl. razdelek
A.12). V primeru, ko se P in T1 izvaˇzata, se mora tudi P 0 izvaˇzati.
ˇ je v oznaˇcevalec in je P procedura, ki je pridruˇzena tipu, oznaˇcuje v.P tisto proceduro
Ce
P , ki je pridruˇzena dinamiˇcnemu tipu v (dinamiˇcna vezava). Pozorni bodimo, da je to lahko
razliˇcna procedura od procedure, ki je pridruˇzena statiˇcnemu tipu v. v se prenaˇsa kot glavni
parameter P po pravilih za prenos parametrov, ki so bili opisani v razdelku A.10.1.
ˇ je r glavni parameter, ki pripada statiˇcnemu tipu T , oznaˇcuje r.P ∧ (predefinirano)
Ce
proceduro P , ki je pridruˇzena osnovnemu tipu tipa T .
ˇ ima procedura, ki je pridruˇzena tipu, predhodno deklaracijo, mora biti glavni paCe
rameter v predhodni deklaraciji istega tipa kot glavni parameter v deklaraciji. Seznama
formalnih parametrov obeh deklaracij morata biti skladna (gl. razdelek A.12)).
Primeri:
PROCEDURE (t: Tree) Insert (node: Tree);
VAR p, father : Tree;
BEGIN
p := t;
REPEAT father := p;
IF node.key = p.key THEN RETURN END;
IF node.key < p.key THEN p := p.left
ELSE p := p.right
END
UNTIL p = NIL;
IF node.key < father .key THEN father .left := node
ELSE father .right := node
END
node.left := NIL;
node.right := NIL
END Insert;
PROCEDURE (t: CenterTree) Insert (node: Tree);
(∗ redefinition ∗)
BEGIN
WriteInt(node(CenterTree).width);
t.Insert↑(node)
215
A.10. DEKLARACIJE PROCEDUR
(∗ calls the Insert procedure bound to Tree ∗)
END Insert;
A.10.3
Vnaprej deklarirane procedure
Naslednji tabeli naˇstevata vse vnaprej deklarirane procedure. Nekatere izmed njih so generiˇcne, z drugimi besedami uporabne so z operandi veˇc tipov. v pomeni spremenljivko, x
in n izraz, T pa tip.
Funkcijske procedure
Ime
ABS(x)
ASH(x, n)
CAP(x)
tip argumenta
numeriˇcen tip
x, n : celoˇst. tip
CHAR
tip rezultata
isti kot x
LONGINT
CHAR
CHR(x)
ENTIER(x)
celoˇst. tip
realni tip
CHAR
LONGINT
LEN(v, n)
LONGINT
MAX(T )
v: tabela;
n: celoˇst. konst.
v: tabela
SHORTINT
INTEGER
REAL
T = osnovni tip
LONGINT
INTEGER
LONGINT
LONGREAL
T
MIN(T )
T = SET
T = osnovni tip
INTEGER
T
T = SET
celoˇst. tip
CHAR
LONGINT
INTEGER
LONGREAL
poljuben tip
INTEGER
BOOLEAN
INTEGER
INTEGER
SHORTINT
REAL
INTEGER
LEN(v)
LONG(x)
ODD(x)
ORD(x)
SHORT(x)
SIZE(T )
uˇ
cinek
absolutna vrednost
aritmetiˇcni pomik (x ∗ 2n )
x je ˇcrka: ustrezna velika
ˇcrka; sicer je vrednost x
x-ti znak po vrsti
najveˇcje celo ˇstevilo, ki
ne presega x
dolˇzina v po dimenziji n
prva dimenzija = 0
iskot kot LEN(v, 0)
identiteta
najveˇcja vrednost, ki pripada
tipu T
najveˇcji element mnoˇzice
najmanjˇsa vrednost, ki pripada
tipu T
0
x MOD 2 = 1
poloˇzaj znaka x
identiteta (moˇzna je
tudi izguba informacije)
ˇstevilo bajtov za
predstavitev T
216
JEZIK OBERON-2
Prave procedure
Ime
ASSERT(x)
tipi argumentov
x: izraz tipa BOOLEAN
ASSERT(x, n)
x: izraz tipa BOOLEAN
COPY(x, v)
x: znakovno zaporedje ali
tabela ;v: znakovna tabela
v: celoˇstevilˇcni tip
v, n: celoˇstevilˇcni tip
v: SET; x: celoˇst. tip
n: celoˇst. tip
v: celoˇstevilˇcni tip
v, n: celoˇstevilˇcni tip
v: SET; x: celoˇst. tip
v: kazalec na zapis ali
tabelo fiksne dolˇzine
kazalec na odprto tabelo
xi : celoˇst. tip
DEC(v)
DEC(v, n)
EXCL(v, x)
HALT(n)
INC(v)
INC(v, n)
INCL(v, x)
NEW(v)
NEW(v, x0 , . . . , xn )
uˇ
cinek
prekinitev programa,
ˇce x ni resniˇcno
prekinitev programa,
ˇce x ni resniˇcno
v := x
v := v − 1
v := v − n
v := v − x
program se konˇca
v := v + 1
v := v + n
v := v + x
nova spremenljivka v ∧
nova spremenljivka v ∧
z dolˇzinami x0 , . . . , xn
Procedura COPY omogoˇca prirejanje znakovnega zaporedja ali znakovne tabele, ki vseˇ je potrebno, se prirejena vrednost
buje zakljuˇcni znak 0X neki drugi znakovni tabeli. Ce
skrajˇsa na dolˇzino, ki je enaka dolˇzini ciljne tabele minus 1. Ciljna tabela bo vedno vsebovala zakljuˇcni znak 0X. Pri procedurah ASSERT(x, n) ter HALT(n) je interpretacija n
prepuˇsˇcena konkretnemu prevajalniku.
A.11
Moduli
Modul je zbirka deklaracij konstant, tipov, spremenljivk in procedur, skupaj z zaporedjem
stavkov, katerih namen je prirejanje zaˇcetnih vrednosti spremenljivkam. Modul predstavlja
neko besedilo (program), ki ga je moˇzno prevajati kot celoto, loˇceno od drugih programov.
Module → “MODULE” ident [ ImportList ]
DeclarationSequence [ “BEGIN” StatementSequence ] “END”
ImportList → “IMPORT” Import { “, ” Import } “; ”
Import → [ Ident “ := ” ] ident
Seznam uvoˇzenih modulov (ImportList) naˇsteva module, ki jih deklarirani modul uvaˇza.
ˇ modul M uvaˇza modul A in ˇce A izvaˇza ime x, se na x v M sklicujemo z A.x. Ce
ˇ pa je
Ce
navedba uvoˇzenega modula A v obliki B := A, ima oznaˇcevalec obliko B.x. Slednje omogoˇca
uporabo okrajˇsav za uvoˇzene module. Modul ne more uvaˇzati samega sebe. Imena, ki so
namenjena izvozu, morajo biti v svoji deklaraciji opremljena z izvozno oznako (gl. razdelek
A.4). Stavˇcno zaporedje, ki sledi simbolu BEGIN se izvaja v trenutku, ko je modul prikljuˇcen
k sistemu (ko se naloˇzi), kar se zgodi po tem, ko se prikljuˇcijo uvoˇzeni moduli. Iz tega sledi,
da cikliˇcni uvoz ni dovoljen. Posamezne (brezparametrske in izvoˇzene) procedure je moˇzno
sproˇziti iz operacijskega sistema, predstavljajo pa ukaze slednjega.
Primer:
MODULE Trees;
(∗ exports:
A.11. MODULI
Tree, Node, Insert, Search, Write, NewTree
∗)
(∗ exports read−only: Node.name ∗)
IMPORT Texts, Oberon;
TYPE
Tree∗ = POINTER TO Node;
Node∗ = RECORD
name−: POINTER TO ARRAY OF CHAR;
left, right: Tree
END;
VAR w : Texts.Write;
PROCEDURE (t: Tree) Insert∗ (name: ARRAY OF CHAR);
VAR p, father : Tree;
BEGIN
p := t;
REPEAT father := p;
IF name = p.name↑ THEN RETURN END;
IF name < p.name↑ THEN p := p.left
ELSE p := p.right
END
UNTIL p = NIL;
NEW (p); p.left := NIL ; p.right := NIL;
NEW (p.name,LEN (name)+1);
COPY (name,p.name↑);
IF name < father .name↑ THEN father .left := p
ELSE father .right := p
END;
END Insert;
PROCEDURE (t: Tree) Search∗ (name: ARRAY OF CHAR): Tree;
VAR p: Tree;
BEGIN
p := t;
WHILE (p # NIL) & (name # p.name↑) DO
IF name < p.name↑ THEN p := p.left
ELSE p := p.right
END
END;
RETURN p
END Search;
PROCEDURE (t: Tree) Write∗;
BEGIN
IF t.left # NIL THEN t.left.Write END;
Texts.WriteString(w , t.name↑);
217
218
JEZIK OBERON-2
Texts.WriteLn(w );
Texts.Append (Oberon.Log, w .buf );
IF t.right # NIL THEN t.right.Write END
END Write;
PROCEDURE NewTree∗ (): Tree;
VAR t: Tree;
BEGIN
NEW (t); NEW (t.name,1);
t.name[0] := 0X;
t.left := NIL; t.right := NIL
RETURN t
END NewTree;
BEGIN
Texts.OpenWriter (w )
END Trees.
A.12
Definicije pojmov
Celoˇ
stevilˇ
cni tipi: SHORTINT, INTEGER, LONGINT
Realni tipi: REAL, LONGREAL
ˇ
Stevilˇ
cni tipi: celoˇstevilˇcni in realni tipi
Istovetnost tipov
Dve spremenljivki, a in b, ki pripadata tipoma Ta in Tb , sta istega tipa, v kolikor
1. Ta in Tb predstavlja isto ime ali
2. je Ta deklarirano kot enako Tb z deklaracijo oblike Ta = Tb ali
3. a in b se pojavljata na istem seznamu imen v deklaraciji spremenljivke, komponente
zapisa ali formalnih parametrov, pri ˇcemer smeta biti odprti tabeli.
Enakost tipov
Tipa Ta in Tb sta enaka, v kolikor sta
1. Ta in Tb ista tipa ali sta
2. Ta in Tb tipa odprtih tabel in sta tipa njunih elementov enaka ali sta
3. Ta in Tb procedurna tipa, katerih formalni parametri si ustrezajo.
Vsebovanost tipov
ˇ
Stevilˇ
cni tipi vsebujejo (vrednosti) manjˇsih ˇstevilˇcnih tipv na podlagi naslednje hierarhije:
LONGREAL ⊇ REAL ⊇ LONGINT ⊇ INTEGER ⊇ SHORTINT
A.12. DEFINICIJE POJMOV
219
Razˇ
siritev tipov (osnovni tip)
Pri deklaraciji tipa Tb = RECORD (Ta ) . . . END pravimo, da je Tb neposredna razˇsiritev tipa
Ta , Tb pa je neposredni osnovni tip tipa Tb . Nek tip Tb je razˇsiritev tipa Ta (Ta je osnovni
tip tipa Tb ), v kolikor
1. sta Ta in Tb ista tipa ali pa
2. je Tb neposredna razˇsiritev neke razˇsiritve Ta .
ˇ je Pa = POINTER TO Ta in Pb = POINTER TO Tb pravimo, da je Pb razˇsiritev Pa
Ce
(Pa je osnovni tip za Pb ), v primeru, ko je Tb razˇsiritev Ta .
Skladnost glede prirejanja
Nek izraz e, ki pripada tipu Te , je skladen glede prirejanja s spremenljivko v, ki pripada tipu
Tv , ˇce je resniˇcen vsaj en od naslednjih pogojev:
1. Te in Tv sta ista tipa;
2. Te in Tv sta ˇstevilˇcna tipa in Tv vsebuje Te ;
3. Te in Tv sta zapisna tipa, Te je razˇsiritev Tv in dinamiˇcni tip v je Tv ;
4. Tv je kazalˇcni ali procedurni tip, e pa ima vrednost NIL;
5. Tv je enak ARRAY n OF CHAR, e je znakovno zaporedje dolˇzine m in velja m < n;
6. Tv je procedurni tip, e pa je ime procedure, ˇcigar formalni parametri ustrezajo formalnim parametrom Tv .
Tabelariˇ
cna skladnost
Stvarni parameter a tipa Ta je tabelariˇcno skladen s formalnim parametrom f tipa Tf , kadar
1. sta Tf in Ta ista tipa ali
2. Tf je odprta tabela, Ta je poljubna tabela, njuna tipa elementov pa sa tabelariˇcno
skladen ali
3. Tf je enak ARRAY OF CHAR, a pa je znakovno zaporedje.
Skladnost glede uporabe v izrazih
Za podani operator sta tipa njegovih operandov skladen glede uporabe v izrazih, kadar ustrezajo naslednji tabeli (ki dodatno prikazuje tip vrednosti izraza). Znakovne tabele, ki jih
primerjamo, morajo imeti zakljuˇcni znak 0X. V vseh primerih mora biti T1 razˇsiritev T0 .
220
JEZIK OBERON-2
operator
+−∗
prvi operand
ˇstevilˇcni
drugi operand
ˇstevilˇcni
/
ˇstevilˇcni
ˇstevilˇcni
+-*/
DIV MOD
SET
celoˇstev.
SET
celoˇstev.
OR & ∼
= # <<=>>=
BOOLEAN
ˇstevilˇcni
CHAR
znakovna tabela
ali zn. zaporedje
BOOLEAN
SET
NIL, POINTER
TO T0 ali T1
proced. tip T
ali NIL
INTEGER
kazalec
zapis
BOOLEAN
ˇstevilˇcni
CHAR
znakovna tabela
ali zn. zaporedje
BOOLEAN
SET
NIL, POINTER
TO T0 ali T1
proced. tip T
ali NIL
SET
kazalec
zapis
=#
IN
IS
A.12.1
tip rezultata
najmanjˇsi ˇstevilˇcni tip,
ki vsebuje oba operanda
najmanjˇsi realen tip,
ki vsebuje oba operanda
SET
najmanjˇsi celoˇstev. tip,
ki vsebuje oba operanda
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
BOOLEAN
Skladnost seznamov formalnih parametrov
Dva seznama formalnih parametrov sta skladna v kolikor
1. vsebujeta isto ˇstevilo parametrov in
2. imata isti tip rezultata ali nimata rezultata in
3. so istoleˇzni parametri enakih tipov in
4. so istoleˇzni parametri bodisi oboji referenˇcnega tipa ali oboji vrednostnega tipa.
A.13
Sintaksa jezika Oberon-2
Module → “MODULE” ident [ ImportList ]
DeclSeq [ “BEGIN” StatementSeq ] “END”
ImportList → “IMPORT” [ Ident “ := ” ] { “, ” [ Ident “ := ” ] } “; ”
DeclSeq → { “CONST” { ConstDecl “; ” } |
“TYPE” { T ypeDecl “; ” } |
“VAR” { V arDecl “; ” }
}|
{ P rocDecl “; ” | F orwardDecl “; ” }
ConstDecl → IdentDef “=” ConstExpr
TypeDecl → IdentDef “=” T ype
VarDecl → IdentList “:” T ype
ProcDecl → “PROCEDURE” [ Receiver ] IdentDef [ F ormalP ars ] “; ”
DeclSeq [ “BEGIN” StatementSeq ] “END” ident
A.13. SINTAKSA JEZIKA OBERON-2
ForwardDecl → “∧” “PROCEDURE” [ Receiver ] IdentDef [ F ormalP ars ]
FormalPars → “(” [ F P Section { “; ” F P Section} ] “)” [ “:” Qualident ]
FPSection → “VAR” ident { “, ” ident } “:” T ype
Receiver → “(” [ “VAR” ] ident “:” ident “)”
Type → Qualident |
“ARRAY” “[” ConstExpr { “, ” ConstExpr } “]” “OF” T ype |
“RECORD” [ “(” Qualident “)” ] F ieldList { “; ” F ieldList } “END” |
“POINTER” “TO” T ype |
“PROCEDURE” [ F ormalP ars ]
FieldList → [IdentList “:” T ype]
StatementSeq → Statement { “; ” Statement }
Statement → [ Designator “ := ” Expression |
Designator [ “(” ExprList “)” ] |
“IF” Expr “THEN” StatementSeq
{ “ELSIF” Expr “THEN” StatementSeq }
[ “ELSE” StatementSeq ] “END” |
“CASE” Expr “OF” Case { “ | ” Case }
[ “ELSE” StatementSeq ] “END” |
“WHILE” Expr “DO” StatementSeq “END” |
“REPEAT” StatementSeq “UNTIL” Expr |
“FOR” ident “ := ” Expr “TO” Expr
[ “BY” ConstExpr ] “DO” StatementSeq
“END” |
“LOOP” StatementSeq “END” |
“WITH” Guard “DO” StatementSeq
{ “ | ” “DO” StatementSeq }
[ “ELSE” StatementSeq ] “END” |
“EXIT” |
“RETURN” [ Expression ] ]
Case → [ CaseLabels { “, ” CaseLabels } “:” StatementSeq ]
CaseLabels → ConstExpr [ “..” ConstExpr ]
Guard → Qualident “:” Qualident
ConstExpr → Expr
Expr → SimpleExpr [ Relation SimpleExpr ]
SimpleExpr → [ “ + ” | “ − ” ] T erm {AddOp T erm }
Term → F actor { M ulOp F actor }
Factor → Designator [ “(” [ ExprList ] “)” ] |
number | character | string | “NIL” |
set | “(” Expr “)” | “∼” F actor
Set → “{” [ Element { “, ” Element } ] “}”
Element → Expr [ “..” Expr ]
Relation → “ = ” | “#” | “ < ” | “ <= ” | “ > ” | “ >= ” | “IN” | “IS”
AddOp → “ + ” | “ − ” | “OR”
MulOp → “ ∗ ” | “/” | “DIV” | “MOD” | “&”
Designator → Qualident { “.” ident | “[” ExprList “]” |
“∧” | “(” Qualident “)” }
ExprList → Expr { “, ” Expr }
221
222
JEZIK OBERON-2
IdentList → IdentDef { “, ” IdentDef }
Qualident → [ ident “.” ] ident
IdentDef → ident [ “ ∗ ” | “ − ” ]
A.14
Modul SYSTEM
Modul z imenom SYSTEM vsebuje doloˇcene tipe in procedure, ki so potrebni za realizacijo
niskoravenskih operacij, ki so lastne posameznemu raˇcunalniku ali prevajalniku. S takimi elementi na primer omogoˇcamo naslavljanje razliˇcnih naprav, ki so prikljuˇcene na raˇcunalnik,
kakor tudi ne upoˇstevanje pravil skladnosti tipov, ki jih predpisuje definicija jezika. Priporoˇcljivo je, da se uporaba teh zmogljivosti omeji le na doloˇcene module (ki jim pravimo
niskoravenski moduli). Taki moduli po svoji naravi niso prenosljivi med raˇcunalniˇskimi sistemi in med razliˇcnimi izvedbami prevajalnikov za Oberon-2, so pa enostavno razpoznavni
zaradi naziva modula SYSTEM v svojem seznamu uvoˇzenih modulov. Naslednje specifikacije
veljajo za realizacijo Oberona-2 na raˇcunalniku Ceres.
Modul SYSTEM izvaˇza tip BYTE, ki ima naslednje lasnosti: Spremenljivkam tipa BYTE
lahko prirejamo vrednosti tipov CHAR ali SHORTINT. V primeru, ko je formalni parameter
tipa ARRAY OF BYTE, je lahko ustrezni stvarni parameter poljubnega tipa.
Modul SYSTEM izvaˇza tudi tip PTR. Spremenljivkam tega tipa lahko prirejamo vrednosti poljubnega kazalˇcnega tipa. V primeru, ko je formalni parameter tipa PTR, je lahko
ustrezni stvarni parameter poljubnega kazalˇcnega tipa.
Procedure modula SYSTEM so naˇstete v naslednih tabelah. Veˇcina je realizirana z
enim samim strojnim ukazom, ki je postavljen v ukazno zaporedje, brez dejanskega klica
procedure. Podrobnosti lahko bralec izve v priroˇcniku za ustrezni procesor. V tabelah
predstavlja v spremenljivko, x, y, a in n predstavljajo izraze in T predstavlja tip.
Funkcijske procedure
Ime
ADR(v)
BIT(a, n)
CC(n
LSH(x, n)
ROT(x, n)
VAL(T, x)
tipi argumentov
poljuben
a: LONGINT
n: celo ˇst.
celoˇst. konst.
x: celoˇst. tip,
CHAR, BYTE
n: celoˇst. tip
x: celoˇst. tip,
CHAR, BYTE
n: celoˇst. tip
T, x: polubna tipa
tip rezultata
LONGINT
BOOLEAN
opis
naslov v
n-ti bit Mem[a]
BOOLEAN
isti tip kot x
pogoj n (0 ≤ n ≤ 15)
logiˇcni pomik
isti tip kot x
rotacija
T
vrednost x
interpretirana
kot, da pripada T
223
A.14. MODUL SYSTEM
Prave procedure
Ime
GET(a, v)
PUT(a, x)
GETREG(n, v)
PUTREG(n, x)
MOVE(a0 , a1 , n)
NEW(v, n)
tipi argumentov
a: LONGINT ;
v: poljubnega osnovnega,
procedurnega ali kazal. tipa
a: LONGINT ;
v: poljubnega osnovnega,
procedurnega ali kazal. tipa
n: celoˇst. tip ;
v: poljubnega osnovnega,
procedurnega ali kazal. tipa
n: celoˇst. tip ;
v: poljubnega osnovnega,
procedurnega ali kazal. tipa
a0 , a1 : LONGINT
n: INTEGER
v: poljuben kazal. tip
n: celoˇstev. tip
opis
v := Mem[a]
Mem[a] := v
v := Register n
Register n := v
Mem[a1 . . . a1 + n − 1] :=
Mem[a0 . . . a0 + n − 1]
dodeli se blok celic
dolˇzine n bajtov,
naslov se priredi v
224
JEZIK OBERON-2
Dodatek B
ˇ
PREDIKATNI RACUN
PRVEGA REDA
V priˇcujoˇcem delu privzemamo, da je bralec seznanjem s predikatnim raˇcunom prvega reda,
namen tega kratkega poglavja pa je le ponovitev osnovnih pojmov. Snov je v glavnem
sestavljena na podlagi dela Mendelson [12], je pa dostopna tudi iz ˇstevilnih drugih virov (gl.
tudi Batagelj [2]).
Logiˇcnim trditvam v predikatnem raˇcunu prvega reda pravimo stavki. Vsak stavek predikatnega raˇcuna prvega reda je zapis, ki je sestavljen po natanˇcnih pravilih. Pravimo, da
ima predikatni raˇcun prvega reda natanˇcno doloˇceno sintakso. Simboli, ki jih uporabljamo
za sestavljanje stavkov, pa so:
1. ˇstevno neskonˇcno ˇstevilo znakov za spremenljivke (x1 , x2 , x3 . . .); seveda je vsaka posamezna trditev konˇcne dolˇzine in lahko vsebuje le konˇcno ˇstevilo spremenljivk. V
praktiˇcnih primerih ponavadi uporabljamo razliˇcne simbole za razliˇcne spremenljivke,
npr. x, y, . . .;
2. konˇcno ali ˇstevno neskonˇcno ˇstevilo znakov za predikate (npr. An
j , n, j > 0, kjer n
predstavlja ˇstevilo argumentov predikata, j pa njegov indeks). V praktiˇcnih primerih
najpogosteje opuˇsˇcamo zapis ˇstevila argumentov in prav tako kot v primeru spremenljivk uporabljamo razliˇcne znake za razliˇcne predikate, namesto da bi jih razlikovali z
indeksi;
3. ˇstevno neskonˇcno ali konˇcno ˇstevilo (vˇstevˇsi niˇc) znakov za funkcije (npr. fjn , n, j > 0)
(n in j imata podoben pomen kot pri predikatih in prav tako velja pripomba, da se
izogibamo uporabi indeksov ter raje uporabljamo razliˇcne simbole za razliˇcne funkcije);
4. ˇstevno neskonˇcno ali konˇcno ˇstevilo (vˇstevˇsi ˇstevilo niˇc) znakov za posamezne konstante (npr. ai , i > 0);
5. sintaktiˇcna simbola ( in ), logiˇcna znaka ⊃ in ¬ ter univerzalnostni kvantifikator ∀.
Neki stavek predikatnega raˇcuna prvega reda je sestavljen iz izrazov in elementarnih stavkov .
1. Izraz je posamezna konstanta ali spremenljivka, ali
2. izraz je fjn (e1 , e2 , . . . , en ), pri ˇcemer je fjn funkcijski znak, e1 , e2 , . . . , en pa so izrazi;
225
226
ˇ
DODATEK B. PREDIKATNI RACUN
PRVEGA REDA
3. izraz lahko pridobimo le na podlagi toˇck 1 in 2.
ˇ sta a1 in a2 posamezni konstanti, x, y in z spremenljivke in f 2 , g 3 znaka
B.1 Primer Ce
za funkciji, so
a1 , f 2 (a2 , f 2 (a1 , y)), g 3 (a1 , x, z),
(B.1)
izrazi.
Elementarni stavki so zgrajeni iz izrazov in znakov za predikate. Torej ima elementaren stavek
obliko
An
kjer
je
An
znak
za
predikat,
e1 , e2 ,
j (e1 , e2 , . . . , en ),
j
. . . , en pa so izrazi.
ˇ uporabljamo simbole iz primera B.1 ter simbol A3 za predikat, sta elemenB.2 Primer Ce
tarna stavka:
A3 (x, y, z), A3 (a1 , f 2 (a2 , f 2 (a1 , y)), g 3 (a1 , x, z))
(B.2)
In konˇcno so stavki predikatnega raˇcuna prvega reda1 zgrajeni iz elementarnih stavkov na
podlagi naslednjih pravil:
1. vsak elementaren stavek je stavek predikatnega raˇcuna;
2. naj bosta A in B stavka predikatnega raˇcuna, x pa spremenljivka. Tedaj so ¬A, A ⊃ B
in ∀xA stavki predikatnega raˇcuna;
3. stavki predikatnega raˇcuna so sestavljeni le na podlagi toˇck 1 in 2.
B.3 Primer Stavek predikatnega raˇcuna je ∀y(∀xA21 (x, y) ⊃ A12 (y)).
Pri zapisovanju stavkov predikatnega raˇcuna pogosto uporabljamo doloˇcene okrajˇsave in
spremembe v zapisu. Na primer, funkcije in predikate pogosto raje zapisujemo v infiksnem
zapisu namesto v nekoliko manj preglednem funkcijskem zapisu. Denimo, da A2 predstavlja
dobro znani predikat enakosti. Tedaj ustrezni elementarni stavek raje piˇsemo kot t1 = t2
namesto A2 (t1 , t2 ). Podobno piˇsemo x + y namesto f 2 (x, y) v primeru, ko f 2 predstavlja
seˇstevanje (in podobno za druge funkcije). Naslednja pomembna okrajˇsava je uporaba eksistenˇcnega kvantifikatorja. Namesto ¬(∀x¬A(x)) piˇsemo ∃xA(x) (torej “Ni resniˇcno, da pri
vseh x velja negacija A(x)” je enakovredno “eksistira tak x, da velja A(x)”).
Predikatni raˇcun rabi za opisovanje trditev o elementih neke poljubne mnoˇzice, vendar
nas bo tu zanimala predvsem mnoˇzica celih ˇstevil . Torej moramo sedaj opisati, kako nekemu
stavku predikatnega raˇcuna pripiˇsemo pomen.
Najprej opiˇsemo pojem mnoˇzice prostih spremenljivk , ki pripada nekemu izrazu in nato
ˇ je X bodisi izraz ali stavek, ki ne vsebuje kvantifikatorja
stavku predikatnega raˇcuna. Ce
∀, je njegova mnoˇzica prostih spremenljivk, V (X), definirana povsem obiˇcajno kot mnoˇzica
ˇ pa je X stavek in ima obliko ∀xA, je V (∀xA) =
spremenljivk, ki se pojavljajo v X. Ce
V (A)−{x}. Z drugimi besedami, uˇcinek kvantifikatorja ∀ je, da spremenljivko, ki jo imenuje,
izloˇci iz mnoˇzice prostih spremenljivk izraza, v katerem se pojavlja. Pravimo tudi, da ∀x
veˇze spremenljivko x (in torej ni veˇc prosta). Pri stavku ∀xA moramo upoˇstevati, da se
kvantifikator ∀ vedno nanaˇsa na stavek A in da se znotraj svojega obmoˇcja nanaˇsa na tiste
primerke spremenljivke x, ki niso v obmoˇcju nekega drugega kvantifikatorja znotraj A.
1 Prilastek “prvega reda” se nanaˇ
sa na dejstvo, da izraz, ki je argument predikata, predstavlja le
posamezne elemente mnoˇ
zic in ne more predstavljati nekega drugega predikata ali funkcije. Odslej
bomo prilastek “prvega reda” veˇ
cinoma opustili.
227
L1.
L2.
L3.
L4.
L5.
A ⊃ (B ⊃ A)
(A ⊃ (B ⊃ C)) ⊃ ((A ⊃ B) ⊃ (A ⊃ C))
(¬B ⊃ ¬A) ⊃ ((¬B ⊃ A) ⊃ B)
∀xA(x) ⊃ A(t) pri pogoju, da je spremenljivka x v
stavku A(x) zamenljiva s t2 . Ta pogoj je izpolnjen
med ostalim tudi pri t = x, s ˇcimer dobimo aksiom
∀xA(x) ⊃ A(t).
∀x(A ⊃ B) ⊃ (A ⊃ ∀xB) v primeru, ko je A stavek
brez proste spremenljivke x.
Slika B.1: Logiˇcni aksiomi predikatnega raˇcuna
B.4 Primer V stavku ∀x∀z(A(x, y) ⊃ ∀x(B(x, z))) se prvi kvantifikator nanaˇsa na argument predikata A, ne pa na argument predikata B.
Spremenljivke z istim imenom, na katere delujejo razliˇcni kvantifikatorji, ˇstejemo za razliˇcne
spremenljivke. V zgornjem primeru sta spremenljivki x v predikatih A in B razliˇcni. Spremenljivki, na katero deluje neki kvantifikator, pravimo, da je vezana, sicer je prosta. V
zgornjem primeru sta x in z vezani spremenljivki, y pa je prosta spremenljivka.
Stavke predikatnega raˇcuna lahko interpretiramo kot stavke, ki se nanaˇsanjo na cela
ˇstevila, tako da vsem konstantam, funkcijskim simbolom in predikatnim simbolom pripiˇsemo
ustrezen pomen, nato pa logiˇcna simbola ¬ in ⊃ interpretiramo na obiˇcajen naˇcin. Na primer,
ˇce pri stavku
∀x∀y∀z[A(x, y) ⊃ (A(y, z) ⊃ A(x, z))]
interpretiramo A kot predikat enakosti =, se zapisani stavek spremeni v obiˇcajno pravilo
tranzitivnosti. V primeru, ko stavek vsebuje proste spremenljivke, je stavek resniˇcen ali
neresniˇcen, odvisno od vrednosti, ki jih pripiˇsemo prostim spremenljivkam. Na primer:
stavek ∀x[x · y = 0] je resniˇcen pri y = 0 in neresniˇcen sicer.
B.5 Primer Omenili smo ˇze, da predikatni raˇcun uporabljamo za izraˇzanje trditev ali lastnosti, ki se nanaˇsajo na cela ˇstevila (ali poljubno drugo mnoˇzico). Kot primer vzemimo:
“r je ostanek po deljenju x z y.” To lastnost izrazimo z naslednjim stavkom predikatnega
raˇcuna:
∃q[x = y · q + r ∧ 0 ≤ r < y],
pri ˇcemer simbol ∧ predstavlja logiˇcno operacijo konjunkcije, oziroma, ˇce jo izrazimo z osnovnima simboloma ¬ in ⊃, ¬(A ⊃ ¬B).
Osnovna lastnost predikatnega raˇcuna je, da omogoˇca dokazovanje izpeljanih resnic iz
preprostejˇsih, osnovnih resnic, ki jim pravimo aksiomi. Aksiome delimo na logiˇcne, ki se
nanaˇsajo na predikatni raˇcun, ne glede na podroˇcje uporabe, in posebne, ki upoˇstevajo neko
posebno podroˇcje uporabe. Logiˇcni aksiomi predikatnega raˇcuna so prikazani na sliki B.1,
medtem ko sta posebna aksioma, ki se nanaˇsata na predikat enakosti, prikazana na sl. B.2.
2 Spremenljivka x v stavku A je zamenljiva s t, v primeru, ko noben prost primerek x v A ni v
obmoˇ
cju nekega kvantifikatorja s spremenljivko y, ki se pojavlja v t.
ˇ
DODATEK B. PREDIKATNI RACUN
PRVEGA REDA
228
E1.
E2.
∀x[x = x]
(refleksivnost enakosti)
x = y ⊃ [A(x, x) ⊃ A(x, y)] (zamenljivost nekaterih, ne pa
nujno vseh, prostih primerkov enakih spremenljivk)
Slika B.2: Posebna aksioma za predikat enakosti
S1.
S2.
iz A in A ⊃ B sledi B
(pravilo modus ponens)
iz A sledi ∀xA (pravilo posploˇsitve)
Slika B.3: Pravila sklepanja za predikatni raˇcun
1.
2.
3.
4.
5.
(A ⊃ ((A ⊃ A) ⊃ A)) ⊃ ((A ⊃ (A ⊃ A)) ⊃ (A ⊃
A))
(primerek aksioma L2)
A ⊃ ((A ⊃ A) ⊃ A)
(primerek L1)
(A ⊃ (A ⊃ A)) ⊃ (A ⊃ A)(iz 1 in 2 na podlagi S1)
A ⊃ (A ⊃ A)
(primerek L1)
A⊃A
(iz 3 in 4 na podlagi S1)
Slika B.4: Dokaz stavka A ⊃ A
ˇ imamo neko zaporedje stavkov S, katerega zadnji
Naj bo Γ neka mnoˇzica stavkov. Ce
element je A, in ki ima lastnost, da vsak element zaporedja bodisi pripada Γ ali pa sledi iz
predhodnih elementov zaporedja na podlagi pravil sklepanja (slika B.3), pravimo, da smo A
izpeljali iz Γ. S simboli to zapiˇsemo kot Γ |−A. Za stavek A pravimo, da smo ga dokazali, ko
velja Λ |−A, pri ˇcemer je Λ mnoˇzica aksiomov, ki vsebuje tako logiˇcne aksiome (slika B.1) kot
morebitne posebne aksiome. Obiˇcajno simbola Λ ne piˇsemo in ima predhodni zapis obliko
kar |−A. Na sliki B.4 je prikazan primer dokaza oˇcitnega stavka A ⊃ A, z drugimi besedami
utemeljitev zapisa |−A ⊃ A.
Naj na tem mestu povzamemo osnovne ideje, ki se nanaˇsajo na predikatni raˇcun in
dokazovanje:
1. trditve zapisujemo z nizi simbolov, ki so zgrajeni po natanˇcno doloˇceni sintaksi;
2. izhajamo iz nekega konˇcnega nabora trditev, za katere privzemamo, da so resniˇcne
(aksiomi);
3. pri neki doloˇceni izibiri aksiomov lahko trditve interpretiramo kot trditve, ki se nanaˇsajo
na ustrezne strukture, kot je npr. kolobar celih ˇstevil;
4. obstaja mehaniˇcen postopek, ki preverja, ali neka trditev sledi iz predhodnih3 ;
5. ˇce zadnja trditev posredno sledi iz aksiomov, pravimo, da smo jo “dokazali”.
Spuˇsˇcanje v podrobnosti predikatnega raˇcuna (prvega reda) daleˇc presega okvir te knjige.
Naˇs namen pri predhodnem izvajanju je bil le obuditi spomin na doloˇceno terminologijo in
3 Neki
postopek je mehaniˇ
cen, ko si lahko predstavljamo, da ga je sposoben izvajati raˇ
cunalnik.
ˇ
B.1. DODATNI PRIMERI UPORABE PREDIKATNEGA RACUNA
229
priklicati bralcu v spomin pojem dokaza ter idejo, kako s predikatnim raˇcunom izraˇzamo
matematiˇcne resnice. Za bralca, ki ga to zanima, pa je v dodatku B.1 prikazanih nekaj
dodatnih primerov izpeljav in dokazov.
B.1
Dodatni primeri uporabe predikatnega raˇ
cuna
V poglavju 1.2 smo opisali osnovne pojme predikatnega raˇcuna in dokazovanja stavkov. Vsak
dokaz je zaporedje stavkov, pri ˇcemer je vsak element zaporedja bodisi aksiom ali pa sledi iz
predhodnih stavkov na podlagi pravil sklepanja B.3. V praksi pa je potrebno osnovna pravila
sklepanja dopolniti z novimi, izpeljanimi pravili zato, da se izognemo pretirano dolgim in
zapletenim izpeljavam.
Kot elementaren primer izpeljanega pravila navajamo naslednji izrek
B.6 Izrek Naj velja |−A1 ⊃ (A2 ⊃ (. . . ⊃ An ) . . .)) in |−A1 , . . . |−An−1 . V tem primeru
velja tudi |−An .
Dokaz. (Vaja).
V matematiˇcnem razmiˇsljanju pogosto postopamo tako, da privzamemo resniˇcnost nekega stavka A, nato izpeljemo iz stavka A drug stavek B in konˇcno povzamemo, da “iz A
sledi B”, oziroma “ˇce velja A, velja tudi B”. Ta naˇcin razmiˇsljanja povzema naslednji izrek.
B.7 Izrek (Izrek o implikaciji) Naj bo Γ mnoˇzica stavkov, A, B sta stavka in naj velja
Γ, A |−B. V tem primeru velja tudi Γ |−A ⊃ B.
Dokaz. Naj bo B1 , B2 , . . . , Bn izpeljava B iz Γ ∪ {A}, pri ˇcemer je Bn = B. Z indukcijo po i
bomo dokazali, da velja Γ |−A ⊃ Bi pri 1 ≤ i ≤ n. Najprej primer i = 1. B1 pripada mnoˇzici
Γ, ali je logiˇcni aksiom ali pa je A. B1 ⊃ (A ⊃ B1 ) je primerek L1 in Γ |−A ⊃ B1 velja v prvih
dveh primerih na podlagi pravila modus ponens. V tretjem primeru (B1 = A) velja |−A ⊃ B1
na podlagi A ⊃ A (gl. sl. B.4 ) in torej velja tudi Γ |−A ⊃ B1 . S tem smo opravili s primerom
i = 1. Denimo sedaj, da velja Γ |−A ⊃ Bk , pri k < i. Bi je bodisi aksiom, ali pripada mnoˇzici
Γ ali je enako A ali pa Bi sledi na podlagi modus ponens iz nekih stavkov Bj in Bm , pri j, m < i
in ko ima Bm obliko Bj ⊃ Bi . V prvih treh primerih razmiˇsljamo kot v primeru i = 1 zgoraj.
V zadnjem primeru velja na podlagi induktivne hipoteze Γ |−A ⊃ Bj ter Γ |−A ⊃ (Bj ⊃ Bi ).
Vendar imamo na podlagi aksioma L2 (sl. B.1) |−(A ⊃ (Bj ⊃ Bi )) ⊃ ((A ⊃ Bj ) ⊃ (A ⊃ Bi )).
Torej imamo, na podlagi modus ponens Γ |−(A ⊃ Bj ) ⊃ (A ⊃ Bi ) in (zopet na podlagi modus
ˇ
ponens, Γ |−A ⊃ Bi ). S tem je induktivni dokaz konˇcan. Zeleni
rezultat ustreza primeru
i = n. 2
Na tem mestu bomo za vajo prikazali izpeljavo treh preprostih posledic aksiomov E1 in
E2 (sl. B.2).
B.8 Trditev V vsaki teoriji prve stopnje z enakostjo veljajo
1. ˇce je t poljuben izraz, velja |−t = t (refleksivnost);
2. |−x = y ⊃ y = x (simetrija);
3. |−x = y ⊃ (y = z ⊃ x = z) (tranzitivnost).
230
ˇ
DODATEK B. PREDIKATNI RACUN
PRVEGA REDA
Dokaz. (1) Na podlagi E1 velja |−∀x1 [x1 = x1 ], nato pa na podlagi L4 (sl. B.1), |−t = t.
(2) Naj bo stavek A(x, x) enak x = x, A(x, y) pa x = y. V tem primeru velja na podlagi
E2 |−x = y ⊃ (x = x =⊃ y = x). Ker pa iz 1 sledi x = x, je 2 posledica tavtologije
B ⊃ ((A ⊃ (B ⊃ C)) ⊃ (A ⊃ C)). (3) Naj bo stavek A(y, y) enak y = z, A(y, x) pa x = z.
Iz E2 (pri zamenjanima x in y) izpeljemo |−y = x ⊃ (y = z ⊃ x = z). Vendar na podlagi
(2) |−x = y ⊃ y = x. Sedaj pa s pomoˇcjo tavtologije (A ⊃ B) ⊃ ((B ⊃ C) ⊃ (A ⊃ C))
pridobimo |−x = y ⊃ (y = z ⊃ x = z). 2
Literatura
[1] Alfred V. Aho, John E. Hopcroft, and Jeffrey D. Ullman. The Design and Analysis of
Computer Algorithms. Computer Science and Information Processing. Addison-Wesley,
1974. ISBN 0-07-039910-7.
[2] Vladimir Batagelj. Diskretne Strukture, zapiski predavanj, 1. zvezek. V. Batagelj, samozaloz;ba, Ljubljana, 1995.
[3] I. N. Bronstein, K. A. Semendjajew, G. Musiol, and H. M¨
uhlig. Matematiˇcni priroˇcnik
(prevod iz nemˇsˇcine). Tehniˇska zaloˇzba Slovenije, 1997. ISBN 86-365-0216-0.
[4] Viljan Mahniˇc. Programiranje v Oberonu. BI–TIM d.o.o., Ljubljana, 1996. ISBN 9616046-04-7.
[5] Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest. Introduction to Algorithms. The MIT Press and McGraw-Hill Book Company, 1992. Eighth Printing, ISBN
0-262-03141-8.
[6] LLC Excelsior. Native xds-x86. Version 2.45,
http://www.excelsior-usa.com/xdsx86.html
[7] John G. Kemeny, J. Laurie Snell, and Gerald L. Thompson. Introduction to Finite
Mathematics. Prentice-Hall, Inc., 1974. Third Edition.
[8] Donald E. Knuth. The Art of Computer Programming, Vol. 3. Computer Science and
Information Processing. Addison-Wesley, 1973.
[9] Igor Kononenko. Naˇcrtovanje podatkovnih struktur in algoritmov. Zaloˇzba FER in FRI,
Ljubljana, 1996. ISBN 961-6209-02-7.
[10] Jernej Kozak. Podatkovne strukture in algoritmi. Druˇstvo matematikov, fizikov in
astronomov SRS, Ljubljana, 1986.
[11] Zohar Manna. Mathematical Theory of Computation. McGraw-Hill Computer Science
Series. McGraw-Hill, 1974.
[12] Elliott Mendelson. Introduction to Mathematical Logic. D. Van Nostrand Company,
Inc., Princeton, New Jersey, U.S.A., 1964.
[13] H. M¨
osenb¨
ock and N. Wirth. The programming language oberon-2. Technical report,
Institut f¨
ur Computersysteme, ETH Z¨
urich, October 1993.
[14] Martin Reiser and Niklaus Wirth. Programming in Oberon — Steps Beyond Pascal and
Modula. ACM Press, Addison-Wesley Publishing Company, 1992.
[15] Ivan Vidav. Viˇsja matematika II. Drˇzavna zaloˇzba Slovenije, Ljubljana, 1979.
231
232
LITERATURA
[16] Niklaus Wirth. Systematic Programming: An Introduction. Prentice-Hall, 1973.
[17] Niklaus Wirth. Raˇcunalniˇsko programiranje, 1. del. DMFA SRS, Ljubljana, 1979.
[18] Niklaus Wirth. Programming in Modula-2. Springer-Verlag, third, corrected edition,
1985.
[19] Niklaus Wirth. Raˇcunalniˇsko programiranje, 2. del. DMFA SRS, Ljubljana, 1985.
[20] Niklaus Wirth. Algorithms & Data Structures. Prentice/Hall International, 1986.
Stvarno kazalo
Ω, 20
⇒, 7
Σ∗ , 177
Θ, 20
⊃, 7
λ, 184
dxe, 43, 150
bxc, 43
¬, 7
ω, 84
π, 179
≺, 27, 29, 142
<, 177
=, 177
ε, 177
∨, 7
∧, 7
a ∗ b, 88
a ⊗ b, 88
a2b, 90
a3b, 90
a ◦ b, 87
O, 19
Dijkstrov, 145, 147
dvojiˇskega iskanja, 2, 14
rekurzivni, 23
dvojiˇskega vstavljanja, 35
Floyd-Warshallov, 150
iskanja k-tega elementa, 54
izmeniˇcnih zamenjav, 38
KMP, 178, 181
Knutha, Morrisa in Pratta (gl. tudi algoritem, KMP), 178, 181
leksikografskega urejanja, 30
navadnega izbiranja, 36
navadnega vstavljanja, 33
navadnega zlivanja, 57
navadnih zamenjav, 37
pogrezanja, 44
porazdeljevanja, 47, 57
poˇzreˇsni, 101, 102
Shellov, 42
simpleksni, 125, 128
urejanja
izboljˇsani, 30
navadni, 30
tabel, 38
urejanja s kopico, 44
urejanja s porazdelitvami, 47
vstavljanja s ˇcuvajem, 34
vzporedni, 187
z razvejitvijo in omejitvijo, 172
z rekurzivnim razcepom, 81
za 0-1 hahrbtnik, 135
za deljenje, 9, 10
za DFT
iterativni, 92, 98
rekurzivni, 91
za iskanje po znakovnih zaporedjih
navadni, 177, 178
za maksimalni pretok, 115, 116
ABS, 214
aksiom, 7
za pogojni stavek, 7, 8
za prirejanje, 8
za stekaliˇsˇce, 7
AL, 56
algebra
linearna, 81
sploˇsna, 81
Algol, 2
algoritem, 1
Bellman-Fordov, 147
posploˇseni, 149
Boyer in Mooreov, 181, 182
233
234
za mnoˇzenje, 14
za mnoˇzenje dveh ˇstevil, 8, 9
za mnoˇzenje matrik
po Strassenu, 83
po Winogradu, 82
za najveˇcjo skupno mero, 17, 18
za razvrˇsˇcanje
poslov v delavnici z enim strojem, 108
za topoloˇsko urejanje, 145
antecedens, 7, 12
APItem, 32, 56
ArrSort, 32
ASH, 214
asimptotiˇcna rast, 19
avtomat
konˇcni, 1
Bellman, 141
beseda
pomnilniˇska, 2
BinaryIns, 35
BinSearch, 3
BubbleSort, 37
CAP, 214
cena, 101
CHR, 214
cikel, 141
negativni, 141
CompareStr, 30
COPY, 215
CopyKseq, 58, 59
CopyRun, 56, 73, 76, 77
CopyRunCoroutine, 73, 76, 77
CrCoroutine, 73, 76
ˇcas, 33
povpreˇcni, 49
ˇceta, 57
navidezna, 67
datoteka, 30
zaporedna, 30
DEC, 215
deljenje, 81
DFT, 84, 86
diagram poteka, 6
dinamiˇcno zaseganje prostora, 19
STVARNO KAZALO
diskretna Fourierjeva transformacija (gl. tudi
DFT), 84
Distribute, 57, 60, 68
dokaz, 5
dokazovanje pravilnosti, 6, 12
dokumentacija programa, 14
dopustnost, 101
drevo
neobetavno, 167
sledi, 3, 40
Empty, 52
enaˇcba
Bellmanova, 132
enaˇcbe
Bellmanove, 141
ENTIER, 214
Exch, 38
EXCL, 215
FCmpType, 28
FCompareType, 29
FCpyRun, 56
FCrCoroutine, 73
FileSort, 56, 73, 76
FinalSwitch, 73, 76, 77
Find, 54
FNoParam, 56
FOR, 20
FPPSort, 56, 76
FRdItem, 56
FSeqInit, 56
funkcija, 19
ciljna, 118
odsekoma konstantna, nepadajoˇca, 133
OKN, 133
preskakovalna, 179, 180
FWrItem, 56
generiranje
spremenljivke, 202
globina
vozliˇsˇc dvojiˇskega drevesa, 193
goto, 39
graf, 111, 140
acikliˇcen, 143
usmerjen, 140
z uteˇzenimi povezavami, 140
235
STVARNO KAZALO
HALT, 215
halt, 39
HeapPS, 73, 76
HeapSort, 44
hiperravnina, 119
mejna, 119
if a[i]Ra[j] then S, 39
INC, 215
INCL, 215
Init, 52, 74
InitInnerLoop, 69
InitLoop, 57, 63
InitProg, 60, 62, 68
InitRd, 56, 73
InitWr, 56, 73
InsertionSort, 33
IntSort, 56, 73
invarianta, 32
zanˇcna, 11, 14
inverz, 85
iskanje
k-tega elementa, 53
po zaporedjih
znakovnih, 177
Item, 28, 29
izbiranje
navadno, 36
izhod, 1
izraˇcun, 40
izraz, 223
izrek
o celoˇstevilˇcnosti maksimalnega pretoka,
115
o lokalnem pogoju za globalni maksimum ciljne funkcije na KPM, 124
o maksimumu ciljne funkcije na KPM,
122
o max pretoku pri min prerezu, 115
o zasiˇcenih poteh, 114
o zgornji meji za vrednost pretoka, 113
izvor, 111
jedro, 32
jezik
formalne logike, 5
programski, 12
kapaciteta, 111
prereza, 113
karakteristika, 85
kljuˇc, 29
kolobar, 86
komutativnost, 82, 83
konsekvens, 7, 12
konstanta
procedurna, 51
konveksnost, 120
konvolucija, 87
negativna ovita, 90
pozitivna ovita, 90
kopica, 45
KPM, 120
neomejena, 120
omejena, 120
kvantifikator
eksistenˇcni, 224
univerzalnostni, 223
LastRun, 75, 77
LEN, 214
ListRank, 190
LONG, 214
MakeCoroutine, 76
matrika, 118
MAX, 214
meja
spodnja, 37
Mendelson, 223
Merge, 58
MergeNonEmptyRuns, 69
MergeRun, 58, 60, 63
MergeSort, 57
metoda
prestavljanja kazalcev, 189
MIN, 215
mnoˇzenje, 81
matrik
spremenjeno, 150
mnoˇzenje matrik, 81
po Strassenu, 83
po Winogradu, 82
mnoˇzica
konveksna
poliedrska (gl. tudi KMP), 119
236
modul, 28, 55
ArrSort, 32
FileSort, 76
HeapPS, 76
NRQuickSort, 51
Skakac, 160
Sort, 28, 29
Modula-2, 2
n-ti primitivni koren enote, 84
najcenejˇsa pot
med vsemi pari vozliˇsˇc, 141, 149
od zaˇcetnega vozliˇsˇca, 141
NatBal2MergeSort, 60
NatBalMultiMergeSort, 62
negacija, 224
nesingularnost, 121
NEW, 215
NextToLastRun, 75, 77
NonEmptyInput, 74, 77
NRQuickSort, 51, 52
Oberon, 2
obseg, 84, 118
ocenjevanje vrst, 21
ODD, 215
odˇstevanje, 81
omreˇzje, 111
operacija
osnovna, 39
ORD, 215
PAL, 56
PAPItem, 56
PARALLEL DO, 188
PARALLEL WHILE, 188
parameter, 32
ParListRank, 190
Partition, 47, 49, 54
Pascal, 2
permutacija, 40
PItem, 28, 32, 44, 60
podatki, 1
pogoj
izstopni, 15
pogrezanje, 45
polieder, 119
polinom, 86
STVARNO KAZALO
polprostor
odprt, 119
zaprt, 119
poltrak, 120
PolyphaseSort, 68
pomnilnik, 2
notranji, 30
zunanji, 30
ponor, 111
Pop, 52
poraba
ˇcasa, 2, 17
najmanjˇsa, 33
najveˇcja, 33
povpreˇcna, 33
prostora, 2, 17
porazdeljevanje, 47
poskus, 158
pot, 112
neusmerjena, 112
zasiˇcena, 112
pot (v grafu), 141
povezava, 111
negativna, 112
pozitivna, 112
zasiˇcena, 112
PRAM, 187
pravilnost, 16
pravilo
dobrih koncev podzaporedij, 183
hevristiˇcno, 181, 183
sklepanja, 11
“slabih znakov”, 183
predikatni raˇcun prvega reda, 5, 223
predstavitev polinoma
koeficientna, 86
vrednostna, 86
prerez, 113
prestavljanje kazalcev, 189
pretok, 111
prevedba, 151
0-1 nahrbtnika na najcenejˇse poti, 151
preverjanje pravilnosti, 3, 4
s poskusi, 4
z logiˇcno analizo, 4, 5
prirejanje, 12
problem
237
STVARNO KAZALO
0-1 nahrbtnika, 132, 172
maksimalnega pretoka, 111
najcenejˇsih poti, 140
optimizacijski, 101, 111, 131
osmih dam, 161
razdalje do konca seznama, 189
skakaˇcevega obhoda, 158
trdnih zakonov, 164
procedura
samostojna, 73
procesor, 1
zaporedni, 17
produkt
asociativni
zaˇcetnih elementov seznama, 191
skalarni, 118
program
raˇcunalniˇski, 1
programiranje
dinamiˇcno, 131, 140
linearno, 111, 117
prostor
pomnilni, 33, 51
vektorski, 84, 118
PSeq, 56, 60, 62
PStack, 52
Push, 52
QuickSort, 47
raˇcunalnik, 1
veˇcprocesorski, 187
vzporedni, 187
raˇcunanje
vzporedno, 187
RAM, 17
razcep
na podprobleme, 132
rekurzivni, 131
razvrˇsˇcanje
poslov v delavnici z enim strojem, 105
zapisov na magnetnem traku, 102
Rd, 56, 73
recept
za izraˇcun, 1
rekurzija, 51
relacija
rekurenˇcna, 22
REPEAT, 11–13
rezultat, 1
Select, 68, 70, 71
SelectionSort, 36
Seq, 56
sestopanje, 157
seˇstevanje, 81
ShakerSort, 38
Shellovo urejanje, 41
ShellSort, 42
SHORT, 215
Sift, 44, 73
SimpleCopyRun, 59
sintaksa, 223
sistem
veˇcprocesorski
krepko povezan, 187
ˇsibko povezan, 187
SIZE, 215
Skakac, 160
sklad, 19, 51
sled, 3
Sort, 28, 29, 47, 52, 76
SortStruc, 52
SpecInit, 56, 76
spremenljivka
prosta, 8, 224
vezana, 224
Stack, 52
StackRec, 52
stavek, 223
elementarni, 223
pogojni, 13
sestavljeni, 13
stopnica, 133
Strassen V., 83
stroj
abstrakten, 1
Turingov, 1
z enakopravnim dosegom do pomnilnika,
1
SwitchCoroutine, 73, 75–77
SwitchTapes, 64
SYSTEM
ADR, 221
BIT, 221
CC, 221
238
GET, 222
GETREG, 222
LSH, 221
MOVE, 222
NEW, 222
PUT, 222
PUTREG, 222
ROT, 221
VAL, 221
ˇsahovnica, 158
ˇstevilo
celo, 224
Fibonaccijevo, 66
kompleksno, 85
racionalno, 85
tabela, 30
teoretiˇcni pripomoˇcek, 39
TermLoop, 69
tip
tabelariˇcni, 32
toˇcka
ekstremna, 120
trak (gl. tudi datoteka, zaporedna), 30
transformacija
linearna, 85
trditev, 5
izhodna, 14
logiˇcna, 223
urejanje, 27
drevesno, 43
leksikografsko, 30
notranje, 30, 32
polifazno, 64
s predurejanjem, 71, 76
s kopico, 43
s porazdelitvami, 47, 131
zunanje, 30, 55
urejenost
topoloˇska, 145
ustavljivost, 16
vbvz, 188
vbzz, 188
vhod, 1
vhodne in izhodne enote, 2
vir
STVARNO KAZALO
raˇcunski, 3
vnaprej deklarirane procedure, 214
vozliˇsˇce, 111
vrednost, 101
vrsta
aritmetiˇcna, 20
geometriˇcna, 21
vstavljanje
dvojiˇsko, 35
navadno, 32, 33
s ˇcuvajem, 34
WHILE, 11, 13
Winograd S., 82
Wirth, 2
Wr, 56, 73
zahtevnost
ˇcasovna, 49
zakon
o ohranjanju pretoka, 112
zamenjave
izmeniˇcne, 38
navadne, 36, 37, 40
zanka, 20
zaokroˇzanje ˇstevil, 2
zaporedje
znakovno, 177
zaporedno izvajanje operacij, 2
zbvz, 188
zbzz, 188
zlivanje
naravno, 57
navadno, 55
uravnoteˇzeno, 57
dvosmerno, 59
veˇcsmerno, 61
veˇcsmerno, 57