23
Univerzitet u Novom Sadu Prirodno-matematički fakultet Departman za matematiku i informatiku Vladimir Kurbalija, [email protected] Miloš Radovanović, [email protected] Doni Pracner, [email protected] Skripta za vežbe iz predmeta Strukture podataka i algoritmi 1 ver 14c-dk – April 2014, Novi Sad Programi u ovoj skripti su testirani sa kompajlerom ’Native XDS Modula 2’. Za verzije pre 2.60 je neophodno dodatno instalirati i TSCP (Top Speed Compatibility Pack), pošto je potreban za neke od modula koji se ne nalaze u ISO standardu Module 2. U novijim verzijama su i ovi moduli uključeni u standardnu instalaciju. Sav sadržaj se može koristiti u skladu sa CC-BY-NC-SA licencom. http://creativecommons.org/licenses/by-nc-sa/3.0/

Skripta Spa1 Dk

Embed Size (px)

DESCRIPTION

.

Citation preview

Page 1: Skripta Spa1 Dk

Univerzitet u Novom SaduPrirodno-matematički fakultet

Departman za matematiku i informatiku

Vladimir Kurbalija, [email protected]š Radovanović, [email protected] Pracner, [email protected]

Skripta za vežbe iz predmetaStrukture podataka i algoritmi 1

ver 14c-dk – April 2014, Novi Sad

Programi u ovoj skripti su testirani sa kompajlerom ’Native XDS Modula 2’. Za verzije pre 2.60 je neophodno dodatnoinstalirati i TSCP (Top Speed Compatibility Pack), pošto je potreban za neke od modula koji se ne nalaze u ISO standarduModule 2. U novijim verzijama su i ovi moduli uključeni u standardnu instalaciju.

Sav sadržaj se može koristiti u skladu sa CC-BY-NC-SA licencom.http://creativecommons.org/licenses/by-nc-sa/3.0/

Page 2: Skripta Spa1 Dk

2 Strukture podataka i algoritmi 1 – skripta

Sadržaj1 Ilustracija efikasnosti algoritma 2

1.1 Zadatak: Pronaći sve pitagorine trojke do zadate granice . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.2 Zadatak: Maksimalna suma susednih elemenata u nizu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Stringovi 4

3 Rad sa fajlovima 53.1 Modul FIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53.2 Zadatak: ispis sadržaja fajla na ekran . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63.3 Zadatak: spisak studenata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

4 Liste i pokazivači 74.1 Zadatak: Formiranje, štampanje i brisanje listi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74.2 Zadatak: Prikaz osnovih operacija nad listama . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84.3 Zadatak: Prikaz operacija nad listama sa jedinstvenim ključem . . . . . . . . . . . . . . . . . . . . . . . . 104.4 Zadatak: Dve liste osoba sa istim sadržajem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

5 Polinomi preko listi 125.1 Moduli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125.2 Zadatak: Sabiranje sa unapred određenim polinomom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155.3 Zadatak: Suma k polinoma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

6 Stek i red opsluživanja 156.1 Primer: osnovno korišćenje steka i reda opsluživanja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156.2 Zadatak: Ilustracija pisanja u fajl uz pomoć bafera . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166.3 Zadatak: Ispitivanje da li reč pripada gramatici wcw+ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176.4 Zadatak: Kalkulator za izračunavanje postfiksnih izraza . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

7 Simulacija rekurzije 187.1 Primer 1 – faktorijel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187.2 Primer 2 – stepenovanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187.3 Primer 3 – Fibonači . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197.4 Primer 4 – faktorijel 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197.5 Primer 5 (ispitni) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207.6 Primer 6 (ispitni) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

A Native XDS Modula 2 – kratko uputstvo IA.1 Mogući problemi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . II

B XDS modula 2 - rad iz komandne linije IIB.1 Prednosti (ili “Zašto ovo raditi?”) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . IIB.2 Podešavanje sistemske putanje (ili "OK, odakle početi?") . . . . . . . . . . . . . . . . . . . . . . . . . . . IIB.3 Kompajliranje programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . IIB.4 Linux i drugi slobodni sistemi (ili "Who needs windows anyway?") . . . . . . . . . . . . . . . . . . . . . . III

1 Ilustracija efikasnosti algoritma

1.1 Zadatak: Pronaći sve pitagorine trojkedo zadate granice

Pitagorina trojka su tri broja a, b, c za koje važi a2 +b2 =c2

MODULE Trojke1;(* Pitagorine trojke koriscenjem "Brute-force" *)FROM InOut IMPORT WriteString, WriteLn, WriteCard;CONSTGr = 100;

VARa, b, c : [1 .. Gr];

BEGINFOR a := 1 TO Gr DOFOR b := 1 TO Gr DOFOR c := 1 TO Gr DOIF a*a + b*b = c*c THENWriteLn;

WriteString(’a = ’);WriteCard(a,2);WriteString(’, b = ’);WriteCard(b,2);WriteString(’, c = ’);WriteCard(c,2)

ENDEND

ENDEND

END Trojke1.

MODULE Trojke2;(*Pitagorine trojke koriscenjem zaokrugljivanja*)FROM InOut IMPORT WriteString, WriteLn, WriteCard;FROM MathLib0 IMPORT sqrt;CONSTGr = 100;

VARa, b, c : CARDINAL;creal : REAL;

BEGINFOR a := 1 TO Gr DOFOR b := 1 TO Gr DO

Page 3: Skripta Spa1 Dk

1.2 Zadatak: Maksimalna suma susednih elemenata u nizu 3

creal := FLOAT(a*a) + FLOAT(b*b);creal := sqrt(creal);c := TRUNC(creal);IF creal = FLOAT(c) THENWriteLn;WriteString(’ a = ’);WriteCard(a,2);WriteString(’, b = ’);WriteCard(b,2);WriteString(’, c = ’);WriteCard(c,2)

ENDEND

ENDEND Trojke2.

Sledeći primer koristi Euklidovu teoremu i malo druga-čiji pristup. Ako uzmemo neka dva prirodna broja m i n,tada se iz njih može izvesti jedna Pitagorina trojka koja lakozadovoljava potrebne uslove:

a = 2mnb = m2 − n2

c = m2 + n2

Odnosno kad probamo da proverimo da li je ovo Pitagorinatrojka dobijamo:

a2 + b2=c2

(2mn)2 + (m2 − n2)2=(m2 + n2)2

MODULE Trojke3;(* Pitagorine trojke koriscenjem teoreme *)FROM InOut IMPORT WriteString, WriteLn, WriteCard;CONSTGr = 10;

VARa, b, c, m, n : CARDINAL;

BEGINFOR m := 1 TO Gr DOFOR n := 1 TO m-1 DOa := 2*m*n;b := m*m - n*n;c := m*m + n*n;WriteLn;WriteString(’a = ’);WriteCard(a,2);WriteString(’, b = ’);WriteCard(b,2);WriteString(’, c = ’);WriteCard(c,2)

ENDEND

END Trojke3.

Sledeća dva metoda traže trojke sa nekim specifičnim oso-binama.MODULE Trojke4;(* Pitagorine trojke kod kojih je razlika

izmedju katete i hipotenuze tacno 1 *)FROM InOut IMPORT WriteString, WriteLn, WriteCard;CONSTGr = 10;

VARa, b, c, m, n : CARDINAL;

BEGINFOR m := 2 TO Gr DOn := m - 1;a := 2*m*n;b := m*m - n*n;c := m*m + n*n;WriteLn;WriteString(’a = ’);WriteCard(a,2);WriteString(’, b = ’);WriteCard(b,2);WriteString(’, c = ’);

WriteCard(c,2)END

END Trojke4.

MODULE Trojke5;(* Pitagorine trojke kod kojih je razlika

izmedju kateta jedan *)FROM InOut IMPORT WriteString, WriteLn, WriteCard;CONSTGr = 7;

VARa, b, c, m, n, w, i, temp : CARDINAL;

BEGINw := 1;n := 0;FOR i := 1 TO Gr DOm := n + w;a := 2*m*n;b := m*m - n*n;c := m*m + n*n;WriteLn;WriteString(’a = ’);WriteCard(a,2);WriteString(’, b = ’);WriteCard(b,2);WriteString(’, c = ’);WriteCard(c,2);temp := w;w := 3*w + 4*n;n := 2*temp + 3*n

ENDEND Trojke5.

1.2 Zadatak: Maksimalna suma proizvoljnogbroja susednih elemenata u nizu celihbrojeva

MODULE MaxNiza1;(* Prvo resenje. Brute Force: O(n^3) *)FROM InOut IMPORT WriteString,ReadInt,

WriteInt,WriteCard,WriteLn;CONSTN = 10;

TYPEInterval = [1..N];

VARMax, Suma : INTEGER;d,g,i,Ood,Doo : Interval;X : ARRAY Interval OF INTEGER;

BEGINWriteString(’ Unesite niz X ’);WriteLn;FOR i := 1 TO N DOReadInt(X[i]);WriteLn

END;Max := 0;FOR d := 1 TO N DOFOR g := 1 TO N DOSuma := 0;FOR i := d TO g DOSuma := Suma + X[i]

END;IF Suma > Max THENMax := Suma;Ood := d;Doo := g

ENDEND

END;WriteLn;WriteString(’ Maksimum je ’);WriteInt(Max,3);WriteString(’ u intervalu od ’);WriteCard(Ood,3);WriteString(’ do ’);WriteCard(Doo,3)

END MaxNiza1.

Page 4: Skripta Spa1 Dk

4 Strukture podataka i algoritmi 1 – skripta

MODULE MaxNiza2;(* Drugo resenje: O(n^2).

Koristi se cinjenica da je suma X[d..g]izracunljiva iz X[d..g-1]. *)

FROM InOut IMPORT WriteString,ReadInt,WriteInt,WriteCard,WriteLn;

CONSTN = 10;

TYPEInterval = [1..N];

VARMax, Suma : INTEGER;d,g,i,Ood,Doo : Interval;X : ARRAY Interval OF INTEGER;

BEGINWriteString(’ Unesite niz X ’);WriteLn;FOR i := 1 TO N DOReadInt(X[i]);WriteLn

END;Max := 0;FOR d := 1 TO N DOSuma := 0;FOR g := d TO N DOSuma := Suma + X[g];IF Suma > Max THENMax := Suma;Ood := d;Doo := g

ENDEND

END;WriteLn;WriteString(’ Maksimum je ’);WriteInt(Max,3);WriteString(’ u intervalu od ’);WriteCard(Ood,3);WriteString(’ do ’);WriteCard(Doo,3)

END MaxNiza2.

MODULE MaxNiza3;(* Trece resenje: O(n^2).

Koristi pomocni niz u kome je na i-tom mestusuma podniza x[1..i] *)

FROM InOut IMPORT WriteString,ReadInt,WriteInt,WriteCard,WriteLn;

CONSTN = 10;

TYPEInterval = [1..N];

VARMax, Suma : INTEGER;d,g,i,Ood,Doo : Interval;X : ARRAY Interval OF INTEGER;Pom : ARRAY [0..N] OF INTEGER;

BEGINWriteString(’ Unesite niz X ’);WriteLn;FOR i := 1 TO N DOReadInt(X[i]);WriteLn

END;Pom[0] := 0;FOR i := 1 TO N DOPom[i] := Pom[i-1] + X[i]

END;Max := 0;FOR d := 1 TO N DOFOR g := d TO N DOSuma := Pom[g] - Pom[d-1];IF Suma > Max THENMax := Suma;Ood := d;Doo := g

ENDEND

END;WriteLn;

WriteString(’ Maksimum je ’);WriteInt(Max,3);WriteString(’ u intervalu od ’);WriteCard(Ood,3);WriteString(’ do ’);WriteCard(Doo,3)

END MaxNiza3.

MODULE MaxNiza4;(* Cetvrto resenje. Najbolje moguce: O(n) *)FROM InOut IMPORT WriteString,ReadInt,

WriteInt,WriteCard,WriteLn;CONSTN = 10;

TYPEInterval = [1..N];

VARMax, MaxDovde : INTEGER;i,d,Ood,Doo : Interval;X : ARRAY Interval OF INTEGER;

BEGINWriteString(’ Unesite niz X ’);WriteLn;FOR i := 1 TO N DOReadInt(X[i]);WriteLn

END;Max := 0;MaxDovde := 0;FOR i := 1 TO N DOIF MaxDovde = 0 THENd := i

END;MaxDovde := MaxDovde + X[i];IF MaxDovde < 0 THENMaxDovde := 0

END;IF MaxDovde > Max THENOod := d;Doo := i;Max := MaxDovde

ENDEND;WriteLn;WriteString(’ Maksimum je ’);WriteInt(Max,3);WriteString(’ u intervalu od ’);WriteCard(Ood,3);WriteString(’ do ’);WriteCard(Doo,3)

END MaxNiza4.

2 StringoviStringovi – odnosno nizovi znakova – ne postoje kao ugra-

đeni tip u jeziku Modula 2. Ovo daje slobodu da se niz zna-kova definiše na dužinu najadekvatniju za konkretnu primenu.U opštem slučaju definišemo npr:TYPE

String = ARRAY [1..30] OF CHAR;

Budući da Modula 2 definiše mogućnost korišćenja otvo-renih nizova, lako je moguće definisati procedure koje kaoparametre primaju bilo koji tip koji je definisan kao niz zna-kova.

PROCEDURE ObradaStringa(str: ARRAY OF CHAR);

Konkretne promenljive u programu moraju biti definisanedužine.

Operacije nad stringovima se najčešće uvoze iz modulaStr i one su sve definisane da prihvataju otvorene nizoveznakova kao što je malopre objašnjeno.

Određivanje stvarne dužine stringa (tj koliko od mak-simalnog kapaciteta niza je zapravo zauzeto sadržajem) semože izvesti na sledeći način:

duzina := Length(str)

Page 5: Skripta Spa1 Dk

3 Rad sa fajlovima 5

Leksikografsko poređenje dva stringa se ne može vršitistandardnim operatorima kao što su < > =. Ovo je delomzato što se radi o nizovima, ali značajnije i zato što se ne vididirektno koji deo niza je popunjen “stvarnim” sadržajem. Zaovo se koristi komanda Compare, koja prihvata dva stringakao parametre, a vraća broj koji predstavlja njihov odnos.Taj broj će biti 0 ako su stringovi jednaki, veći od nule ako jeprvi string “veći”, i manji od nule ako je prvi string “manji”.IF Compare(str1, str2) > 0 THEN

WriteString("Prvi string je veci");ELSIF Compare(str1, str2) < 0 THEN

WriteString("Prvi string je manji");ELSE (* moraju biti jednaki *)

WriteString("Jednaki su");END;

Ovo se lako pamti kad primetimo da je odnos izmeđuCompare i 0 isti kao i između prvog i drugog stringa.

Postoji i modul Strings koji ima nešto drugačije defini-sane procedure, no na njih se sada nećemo fokusirati.

3 Rad sa fajlovimaZa rad sa fajlovima je bitno razumeti da su oni u suštini

niz znakova, pri čemu neki imaju posebna značenja. Na pri-mer novi red u tekstualnom fajlu ne postoji u istom smislu kaona ekranu ili na papiru, budući da svi znakovi dolaze jedanposle drugog u jednom nizu. Umesto toga postoje specijalodefinisani kodovi u ASCII tabeli znakova koji predstavljajuprelome:

• Kod 10 – Line feed – red dole na štampaču• Kod 13 – Carriage return – povratak na početak reda

Različiti operativni sistemi koriste različite kombinacijeovih znakova da označe prelome redova – Windows koristioba jedan za drugim, Linux i drugi srodni operativni sistemitipično koriste samo LF, dok je Apple definisao da je sam CRprelom reda. Kvalitetni tekstualni editori uglavnom mogusami da prepoznaju prelom koji je korišćen u fajlu i da seadekvatno prilagode.

Pri radu sa fajlom se on tipično otvara preko neke po-moćne strukture koja potom pamti poziciju u fajlu odakletreba nastaviti čitanje ili gde će biti nastavljeno pisanje.

R e d 1 LF CR 2 . . .

V

Primer: tekstualni fajl u kome u prvom redu piše “Red 1”, adrugi počinje znakom “2”. Pozicija prikazuje da smo

pročitali prvi red.Bitno je i napomenuti da ukoliko pišemo u postojeći fajl

novi sadržaj zamenjuje stari – odnosno biće pisano prekostarog teksta. Tipično ne postoje opcije da se novi sadržajumeće u sredinu postojećeg fajla.

3.1 Modul FIOU ovom modulu je definisan tip File, koji predstavlja je-

dan fajl sa kojim radimo. Da bi ga koristili moramo ga uvestiu program (isto kao što uvozimo i komande).

U primerima se pretpostavlja da je “f” tipa File, “str”niz znakova, “i” tipa INTEGER, “c” tipa CARDINAL i “ch”tipa CHAR. Dodatna promenljiva “n” tipa INTEGER služi zaformatiranje slično kao u modulu InOut, odnosno za ispis ćebiti zauzeto bar “n” znakova.

Ako otvaramo već postojeći fajl, poželjno je prvo proveritida li on postoji – u suprotnom naš program će se srušiti priizvršavanju. Funkcija Exists(str) vraća da li fajl postoji.

Promenljiva tipa File se mora vezati za neki fajl jednomod sledećih komandi:

• f := Open(str); – otvara se postojeci fajl za čitanje• f := Create(str); – kreira se fajl za pisanje; ako

je već postojao, biće zamenjen• f := Append(str); – otvara se postojeći fajl za do-

pisivanje na kraj

Po završetku rada fajl se mora zatvoriti, u našem primeruto bi bilo:

• Close(f);

Procedure za čitanje i pisanje su vrlo slične onima iz mo-dula IO, osim što imaju dodatni parametar „f“ koji označavafajl sa kojim se radi.

• RdStr(f,str) – učitava ceo red u string str• RdItem(f,str) – učitava jednu reč u string str (uči-

tava znakove iz fajla dok ne naiđe na separator)• i:= RdInt(f); c:= RdCard(f) – učitava broj, koji

se dobija kao rezultat procedure• ch:= RdChar(f) – vraća jedan znak iz fajla

Bitno je obratiti pažnju na specifičnost da postoje dvekomande za čitanje stringova iz fajla i da se one ponašajurazličito. Budući da razmak spada u separatore to znači dase korišćenjem RdItem ne može učitati string koji ima u sebirazmake.

Analogne su i procedure za pisanje različitih tipova u fajl:

• WrStr(f,str);• WrInt(f,i,n);• WrCard(f,c,n);• WrChar(f,ch);

Treba primetiti da ne postoje dve komande za ispis stringau fajl – potpuno je svejedno da li on ima razmake u sebi iline.

Prelom reda se eksplicitno upisuje u fajl komandom

• WrLn(f);.

Da bi odredili da li smo stigli do kraja fajla možemo ko-ristiti EOF. U pitanju je logička promenljiva koja se uvozi izmodula FIO kao bilo kakva normalna komanda. Ona ozna-čava da li smo poslednjom operacijom čitanja stigli do krajafajla. Ne menja joj se vrednost pri operacijama otvaranja izatvaranja fajlova, odnosno neće se pri tome resetovati naFALSE, pa na ovo treba obratiti pažnju pri radu.

Mogući problemi

U ovoj glavi će biti navedeni neki česti problemi koji semogu desiti pri korišćenju FIO modula, a koji su vezani zakonkretnu implementaciju u XDS distribuciji kompajlera.

RdStr i drugi pozivi Prilikom čitanja iz fajlova može doćido neobičnih rezultata ako se kombinuju pozivi RdStr sadrugima. Problem je u različitom tretiranju separatora. Ko-manda RdStr uvek čita do kraja reda i pri tome premestipoziciju za čitanje odmah iza znaka za razdvajanje redova.Ostale komande prvo preskaču separatore i čitaju sadržaj dok

Page 6: Skripta Spa1 Dk

6 Strukture podataka i algoritmi 1 – skripta

ne naiđu na novi separator (što može biti novi red, a možebiti i razmak, tabulator i neki drugi znaci) i staju sa čitanjempre tog separatora. Kombinovanje ova dva pristupa možedovesti do toga da RdStr nakon neke druge komande učitasamo kraj trenutnog reda, a ne sledeći red kao što bi biloočekivano.

EOF i prazan red na kraju fajla Svako čitanje iz fajlapostavlja EOF u skladu sa tim da li je komanda stigla dokraja fajla ili ne. Nažalost kod svih komandi za čitanje (osimRdStr) postoji problem ukoliko je na kraju prazan red ili nekidodatni separator. Tada učitavanje poslednjeg elementa nijezapravo došlo do kraja fajla. Ako se nakon toga proba jošjedno učitavanje sa takvom komandom ona će probati da pre-skoči separator i da učita neki sadržaj, ali će se zaglaviti jer nemože da ga nađe. Ovo ponašanje je greška u implementacijiFIO modula u okviru XDS distribucije.

3.2 Zadatak: ispis sadržaja fajla na ekranPotrebno je sve redove iz fajla učitati i ispisati ih na ekran.

MODULE ispis;FROM FIO IMPORT File, Exists, Open, Close, EOF,

RdStr;FROM InOut IMPORT WriteString, WriteLn, ReadString;

PROCEDURE ispisF(ime: ARRAY OF CHAR);VARf:File;s : ARRAY[1..100] OF CHAR;

BEGINIF Exists(ime) THENf:=Open(ime);EOF := FALSE;WHILE NOT EOF DO

RdStr(f,s);WriteString(s);WriteLn;

END;Close(f);

ELSEWriteString("-- fajl ne postoji --");WriteLn;

END;END ispisF;

VARime: ARRAY[1..100] OF CHAR;

BEGINWriteString("unesite ime fajla:");ReadString(ime);ispisF(ime);

END ispis.

3.3 Zadatak: spisak studenataNapraviti program koji iz fajla učitava podatke o studen-

tima, dodaje novog studenta u spisak i snima fajl. U fajluse u svakom redu nalazi podatak o jednom studentu, redomprezime, ime i godina rođenja, razdvojeni razmacima.MODULE nizslog;FROM InOut IMPORT WriteString, WriteLn, WriteCard,

ReadCard, ReadString;FROM FIO IMPORT File, Exists, Open, Create, Close,

EOF,RdItem, RdCard, WrStr, WrCard, WrLn;

FROM Str IMPORT Compare;

CONSTMaxStud = 100;radnifajl = "studenti.txt";

TYPE

String = ARRAY[1..30] OF CHAR;Student = RECORD

ime, prez: String;god: CARDINAL;

END;Studenti = ARRAY[1..MaxStud] OF Student;

PROCEDURE UcitajF(fajl:String;VAR spisak: Studenti; VAR n:CARDINAL);

VARf:File;

BEGINn:=0;IF Exists(fajl) THEN

f:= Open(fajl);EOF := FALSE;WHILE NOT EOF DO

INC(n);RdItem(f, spisak[n].prez);RdItem(f, spisak[n].ime);spisak[n].god := RdCard(f);

END;Close(f);

END;END UcitajF;

PROCEDURE Ispisi(spisak:Studenti; n:CARDINAL);VAR

i: CARDINAL;BEGIN

FOR i:=1 TO n DOWriteString(spisak[i].prez);WriteString(" ");WriteString(spisak[i].ime);WriteString(" ");WriteCard(spisak[i].god,1);WriteLn;

END;END Ispisi;

PROCEDURE IspisiF(fajl:String;spisak:Studenti; n:CARDINAL);

VARf:File;i: CARDINAL;

BEGINIF (n>0) AND (n<=MaxStud) THEN

f:=Create(fajl);(* pravimo takav fajl da ne

postoji zadnji prazan red *)FOR i:=1 TO n-1 DO

WrStr(f,spisak[i].prez);WrStr(f," ");WrStr(f,spisak[i].ime);WrStr(f," ");WrCard(f,spisak[i].god,1);WrLn(f);

END;WrStr(f,spisak[n].prez);WrStr(f," ");WrStr(f,spisak[n].ime);WrStr(f," ");WrCard(f,spisak[n].god,1);Close(f);

END;END IspisiF;

PROCEDURE NoviStudent(VAR spisak:Studenti; VARn:CARDINAL);

VARstud,temp:Student;i:CARDINAL;dodaj:BOOLEAN;

BEGINIF n<MaxStud THEN

WriteString("Prezime novog studenta?");ReadString(stud.prez);WriteString("Ime novog studenta?");ReadString(stud.ime);WriteString("God. rodj. novog studenta?");ReadCard(stud.god);

Page 7: Skripta Spa1 Dk

4 Liste i pokazivači 7

(* proverimo da li vec postoji *)i:=1;dodaj := TRUE;WHILE (i<=n) AND dodaj DO

temp := spisak[i];IF (temp.god = stud.god) &(Compare(temp.prez,stud.prez)=0) &(Compare(temp.ime,stud.ime)=0) THENdodaj:=FALSE;

END;INC(i);

END;IF dodaj THEN

INC(n);spisak[n]:=stud;

ELSEWriteString("podaci vec postoje!");

END;ELSE

WriteString("popunjen kapacitet!");END;

END NoviStudent;

VARspisak : Studenti;n:CARDINAL;

BEGINUcitajF(radnifajl, spisak, n);Ispisi(spisak, n);NoviStudent(spisak,n);IspisiF(radnifajl, spisak, n);

END nizslog.

4 Liste i pokazivačiZa rad sa pokazivačima je potrebno iz modula Storage

uvesti procedure za dinamičko zauzimanje i oslobađanje me-morije ALLOCATE i DEALLOCATE.

U kodu se mogu koristiti i skraćeni oblici NEW i DISPOSEkoji se direktno prevode u prethodno pomenute procedure.ALLOCATE(point, SIZE(point)); (* isto kao

NEW(point) *)DEALLOCATE(point, SIZE(point)); (* isto kao

DISPOSE(point) *)

4.1 Zadatak: Formiranje, štampanje i brisa-nje listi

MODULE liste;FROM InOut IMPORT WriteString, WriteLn, WriteInt,

ReadInt, ReadCard;FROM Storage IMPORT ALLOCATE, DEALLOCATE;TYPEbrojevi = POINTER TO brojSlog;brojSlog = RECORD

info:INTEGER;veza:brojevi;

END;VARn,i:CARDINAL;lista : brojevi;br:INTEGER;

PROCEDURE DodajPoc(VAR lista:brojevi; br:INTEGER);(* dodaje broj br na pocetak liste *)VARtemp:brojevi;

BEGINNEW(temp);temp^.info := br;temp^.veza := lista;lista := temp;

END DodajPoc;

PROCEDURE Stampaj(lista:brojevi);

VARtemp:brojevi;

BEGINtemp:=lista;WHILE temp # NIL DO

WriteInt(temp^.info,0);WriteLn;temp := temp^.veza;

END;END Stampaj;

PROCEDURE Unisti(VAR lista:brojevi);VARtemp:brojevi;

BEGINtemp:=lista;WHILE temp # NIL DO

lista:=lista^.veza;DISPOSE(temp);temp:=lista;

END;END Unisti;

BEGINlista := NIL;WriteString(’unesite n (broj brojeva): ’);ReadCard(n);WriteString(’unesite brojeve: ’);WriteLn;FOR i:= 1 TO n DO

ReadInt(br);DodajPoc(lista,br);

END;WriteString(’sadrzaj liste:’);WriteLn;Stampaj(lista);Unisti(lista);WriteString(’memorija je oslobodjena’);WriteLn;

END liste.

Alternativno je poziv DodajPoc moguće zameniti pozi-vom jedne od sledeće dve procedure čime se dobija dodavanjeelementa na kraj liste, ili kreiranje sortirane liste:PROCEDURE DodajKraj(VAR lista:brojevi; br:INTEGER);(* dodaje element na kraj liste *)VARtekuci, temp :brojevi;

BEGINNEW(temp);temp^.info := br;temp^.veza := NIL;IF lista = NIL THEN

(* prazna lista *)lista:=temp;

ELSEtekuci := lista;WHILE tekuci^.veza#NIL DO

tekuci:=tekuci^.veza;END;tekuci^.veza := temp;

END;END DodajKraj;

PROCEDURE DodajSort(VAR lista:brojevi; br:INTEGER);(* dodaje broj tako da lista ostane sortirana

(podrazumeva se da je vec sortirana) *)VARtemp, tekuci : brojevi;

BEGINNEW(temp);temp^.info:=br;temp^.veza:=NIL;IF (lista = NIL) OR (lista^.info>=br) THEN(*prazna lista ili na pocetak*)temp^.veza:=lista;lista := temp;

ELSE(*negde u listi*)tekuci:= lista;

Page 8: Skripta Spa1 Dk

8 Strukture podataka i algoritmi 1 – skripta

WHILE (tekuci^.veza # NIL) AND(tekuci^.veza^.info<=br) DO

tekuci:=tekuci^.veza;END;temp^.veza := tekuci^.veza;tekuci^.veza:=temp;

END;END DodajSort;

Kod svih procedura se mogu primeniti i rekurzivne vari-jante. Sledi primer za kreiranje sortirane liste.PROCEDURE DodajSortRek(VAR lista:brojevi;

br:INTEGER);(* Koristi se cinjenica da prosledjujemo pokazivacpo referenci, tj. da ga mozemo menjati unutar

procedure *)VARtemp : brojevi;

BEGINIF (lista = NIL) OR (lista^.info>=br) THEN(* Izlaz iz rekurzije. Ubacivanje u praznu

listu,na kraj liste ili na odgovarajuce mesto *)NEW(temp);temp^.info:=br;temp^.veza:=lista;lista:=temp;

ELSEDodajSortRek(lista^.veza, br);

END;END DodajSortRek;

4.2 Zadatak: Prikaz osnovih operacija nadlistama

MODULE liste2;FROM InOut IMPORT WriteString, WriteLn,

WriteCard, ReadCard;FROM IO IMPORT RdKey;FROM Storage IMPORT ALLOCATE, DEALLOCATE;TYPEskupZn = SET OF CHAR;brojevi = POINTER TO brojSlog;brojSlog = RECORD

info:CARDINAL;veza:brojevi;

END;VARlista : brojevi;menu,prazno:CHAR;

PROCEDURE DodajPoc(VAR lista:brojevi; br:INTEGER);(* dodaje broj pom na pocetak liste *)VARtemp:brojevi;

BEGIN(* kreiramo novi element *)NEW(temp);temp^.info := br;(* treba da pokazuje na ostatak liste *)temp^.veza := lista;(* pocetak liste je novi element *)lista := temp;

END DodajPoc;

PROCEDURE Unos(VAR lista:brojevi);(* dodaje n brojeva u listu *)VARn,i,br:CARDINAL;

BEGINWriteString(’unesite n (broj brojeva): ’);ReadCard(n);FOR i:= 1 TO n DO

WriteString("unesite broj ");WriteCard(i,0);WriteString(": ");ReadCard(br);DodajPoc(lista,br);

END;END Unos;

(* -- procedure za stampu -- *)

PROCEDURE Stampaj(lista:brojevi);(* stampa sadrzaj liste na ekran *)VARtemp:brojevi;

BEGINWriteLn;WriteString("Sadrzaj liste:");WriteLn;temp:=lista;WHILE temp # NIL DO

WriteCard(temp^.info,0);WriteLn;temp := temp^.veza;

END;END Stampaj;

PROCEDURE StampajK(VAR lista:brojevi);(* stampa k-ti element (k unosi korisnik) *)VARtemp:brojevi;k,brojac:CARDINAL;

BEGINWriteString("unesite redni broj elementa:");ReadCard(k);temp:=lista;brojac := 1;WHILE (temp# NIL) AND (k>brojac) DOtemp:=temp^.veza;INC(brojac);

END;IF (temp#NIL) THENWriteCard(temp^.info,2);

ELSEWriteString("greska! - ne postoji element");WriteString(" u listi sa rednim brojem ");WriteCard(k,2);

END;WriteLn();

END StampajK;

PROCEDURE StampajMinimum(VAR lista:brojevi);(* nalazi i stampa minimalni element liste *)VARtemp:brojevi;min:CARDINAL;

BEGINIF (lista=NIL) THENWriteString("prazna lista!");

ELSEmin:=lista^.info;temp:=lista^.veza;WHILE temp # NIL DOIF temp^.info < min THENmin := temp^.info;

END;temp := temp^.veza;

END;WriteString("Minimalni element liste je ");WriteCard(min,0);

END;WriteLn;

END StampajMinimum;

(* -- pomocne procedure, bez ispisa -- *)

PROCEDURE UListi(lista:brojevi;br: CARDINAL):BOOLEAN;

(* vraca da li se ’br’ nalazi u listi ’lista’ *)VARtemp:brojevi;

BEGINtemp:=lista;WHILE (temp # NIL) AND (temp^.info # br) DO(* dok ne dodjemo do kraja liste

ili ne nadjemo broj *)temp := temp^.veza;

END;IF temp#NIL THEN

Page 9: Skripta Spa1 Dk

4.2 Zadatak: Prikaz osnovih operacija nad listama 9

(* znaci da nismo na kraju liste,tj da je nadjen broj *)

RETURN TRUE;ELSE (* temp = NIL *)RETURN FALSE;

END;END UListi;

PROCEDURE IzbaciIzListe(VAR lista:brojevi;br: CARDINAL):BOOLEAN;

(* izbacuje broj ’br’ iz liste, naravno akopostoji i vraca da li je operacija uspesnoobavljena *)

VARtemp,prethodni:brojevi;

BEGIN(* proverimo da li je prvi element *)IF (lista # NIL) AND (lista^.info = br) THENtemp:=lista;lista :=lista^.veza;DISPOSE(temp);RETURN TRUE;

ELSE(* trazimo u ostatku liste *)temp:=lista;prethodni:=NIL;WHILE (temp # NIL) AND (temp^.info # br) DO

(* dok ne dodjemo do kraja listeili ne nadjemo broj *)

prethodni:=temp;temp := temp^.veza;

END;IF temp#NIL THEN(* znaci da nismo na kraju liste,

odnosno da smo nasli broj *)(* prevezemo listu oko elementa *)prethodni^.veza:=temp^.veza;DISPOSE(temp);RETURN TRUE;

ELSERETURN FALSE;

END;END;

END IzbaciIzListe;

PROCEDURE IzbaciIzListeSve(VAR lista:brojevi;br: CARDINAL):CARDINAL;

(* izbacuje sve brojeve ’br’ iz liste, naravno akopostoje i vraca koliko ih je bilo *)

VARtemp,prethodni:brojevi;brojac : CARDINAL;

BEGINbrojac := 0;(* uklanjamo sa pocetka koliko je potrebno *)WHILE (lista # NIL) AND (lista^.info = br) DOtemp:=lista;lista :=lista^.veza;DISPOSE(temp);INC(brojac);

END;(* trazimo u ostatku liste *)IF (lista # NIL) THENtemp:=lista;WHILE (temp^.veza # NIL) DO

(* idemo do poslednjeg elementa liste *)prethodni:=temp;temp := temp^.veza;IF temp^.info = br THEN(* prevezemo listu oko elementa *)prethodni^.veza:=temp^.veza;DISPOSE(temp);INC(brojac);(* vracamo se jedan korak da biu novom krugu proverili i ovaj element *)temp := prethodni;

END;END;

END;RETURN brojac;

END IzbaciIzListeSve;

(* - procedure sa interakcijom sa korisnikom - *)

PROCEDURE IzbacivanjeEl(VAR lista:brojevi);(* izbacuje uneti broj iz liste koristeci proceduru

IzbaciIzListe *)VARbr:CARDINAL;

BEGINWriteString("unesite broj za izbacivanje: ");ReadCard(br);IF IzbaciIzListe(lista,br) THENWriteString("broj je izbacen iz liste");

ELSEWriteString("greska! - broj ne postoji");

END;WriteLn;

END IzbacivanjeEl;

PROCEDURE IzbacivanjeElSvi(VAR lista:brojevi);(* izbacuje sve primeke unetog broj iz liste

koristeci proceduru IzbaciIzListeSve *)VARbr, ukupno:CARDINAL;

BEGINWriteString("unesite broj za izbacivanje: ");ReadCard(br);ukupno := IzbaciIzListeSve(lista,br);WriteString("Iz liste je izbaceno ");WriteCard(ukupno,3);WriteString(" el.");WriteLn;

END IzbacivanjeElSvi;

PROCEDURE IzbacivanjeK(VAR lista:brojevi);(* izbacuje k-ti element iz liste *)VARtemp,tekuci:brojevi;k,brojac:CARDINAL;

BEGINIF lista=NIL THENWriteString("lista je prazna, nema ");WriteString("elemenata za izbacivanje");

ELSEWriteString("unesite redni broj elementa");WriteString(" koji zelite izbaciti:");ReadCard(k);IF k=1 THEN (*izbacivanje prvog *)temp:=lista;lista := lista^.veza;DISPOSE(temp);

ELSEtekuci := lista;brojac := 2; (*gledamo jedan unapred*)WHILE (tekuci^.veza# NIL) AND (k>brojac) DO(* idemo kroz listu do k-tog el *)tekuci:=tekuci^.veza;INC(brojac);

END;IF (tekuci^.veza#NIL) THEN

(* pamtimo element za brisanje *)temp:=tekuci^.veza;(* prevezujemo listu oko njega*)tekuci^.veza:=tekuci^.veza^.veza;DISPOSE(temp);

ELSEWriteString("greska! - ne postoji el ");WriteString("u listi sa rednim brojem ");WriteCard(k,2);

END;WriteLn();

END;END;

END IzbacivanjeK;

PROCEDURE Pretraga(lista:brojevi);(* provera da li se uneti broj nalazi u listi *)VARbr:CARDINAL;

BEGINWriteString("unesite trazeni broj");

Page 10: Skripta Spa1 Dk

10 Strukture podataka i algoritmi 1 – skripta

ReadCard(br);IF UListi(lista,br) THENWriteString("broj postoji u listi");

ELSEWriteString("broj ne postoji u listi");

END;WriteLn;

END Pretraga;

(* -- oslobadjanje memorije -- *)

PROCEDURE Unisti(VAR lista:brojevi);VARtemp:brojevi;

BEGINtemp:=lista;WHILE temp # NIL DO

lista:=lista^.veza;DISPOSE(temp);temp:=lista;

END;END Unisti;

BEGIN(* pocinjemo od prazne liste *)lista := NIL;REPEAT

WriteLn;WriteString("Ilustracija rada sa");WriteString(" listama brojeva");WriteLn;WriteString("=============================");WriteLn;WriteString("s - Stampa");WriteLn;WriteString("u - Unos");WriteLn;WriteString("i - Izbacivanje br iz liste");WriteLn;WriteString("v - izbacivanje svih br iz

liste");WriteLn;WriteString("e - izbacivanje k-tog El.");WriteLn;WriteString("k - stampanje k-tog elementa");WriteLn;WriteString("m - Minimalni broj u listi");WriteLn;WriteString("p - Pretraga el. u listi");WriteLn;WriteLn;WriteString("q - kraj rada (Quit)");WriteLn;REPEATmenu := CAP(RdKey());

UNTIL menu IN skupZn{’S’,’U’,’E’,’I’,’V’,’M’,’K’,’P’,’Q’};

IF menu#’Q’ THENCASE menu OF’S’ : Stampaj(lista);|’U’ : Unos(lista);|’I’ : IzbacivanjeEl(lista);|’V’ : IzbacivanjeElSvi(lista);|’E’ : IzbacivanjeK(lista);|’K’ : StampajK(lista); |’M’ : StampajMinimum(lista); |’P’ : Pretraga(lista);|END;WriteLn;WriteString("--- pritisnite bilo koji ");WriteString("taster za povratak u meni");prazno:=RdKey();

ELSEWriteString("Kraj rada")

END;WriteLn;

UNTIL menu=’Q’;Unisti(lista);

END liste2.

4.3 Zadatak: Prikaz operacija nad listama sajedinstvenim ključem

MODULE Radnici;

FROM InOut IMPORT WriteString, ReadString,WriteLn, WriteCard, ReadCard, Done;

FROM IO IMPORT RdKey;FROM Storage IMPORT ALLOCATE, DEALLOCATE;

TYPEskupZn = SET OF CHAR;str = ARRAY [1..20] OF CHAR;radnici = POINTER TO slog;slog = RECORD

ime, prez : str;broj : CARDINAL;sled : radnici

END;VARmeni, pom : CHAR;rad : radnici;

PROCEDURE Clear();VARbr: CARDINAL;

BEGINFOR br:=1 TO 100 DOWriteLn;

END;END Clear;

PROCEDURE Spisak(rad : radnici);BEGINWHILE rad # NIL DOWriteString(rad^.ime);WriteString(’ ’);WriteString(rad^.prez);WriteCard(rad^.broj, 8);WriteLn;rad := rad^.sled

ENDEND Spisak;

PROCEDURE Zaposli(VAR rad : radnici);VARnovi, tek : radnici;nadjen : BOOLEAN;

BEGINNEW(novi);REPEATWriteString(’Ime, prezime i jedinstveni’);WriteString(’ broj novog radnika: ’);WriteLn;ReadString(novi^.ime);ReadString(novi^.prez);ReadCard(novi^.broj);nadjen := FALSE;tek := rad;WHILE NOT nadjen AND (tek # NIL) AND

(tek^.broj <= novi^.broj) DOIF novi^.broj = tek^.broj THENnadjen := TRUE

ELSEtek := tek^.sled

ENDEND

UNTIL Done AND NOT nadjen;IF (rad = NIL) OR (novi^.broj<rad^.broj) THENnovi^.sled := rad;rad := novi

ELSEtek := rad;WHILE (tek^.sled # NIL) AND

(tek^.sled^.broj < novi^.broj) DOtek := tek^.sled

END;novi^.sled := tek^.sled;tek^.sled := novi

ENDEND Zaposli;

PROCEDURE Otpusti(VAR rad : radnici);VAR

Page 11: Skripta Spa1 Dk

4.4 Zadatak: Dve liste osoba sa istim sadržajem 11

tek, pom : radnici;br : CARDINAL;

BEGINREPEATWriteLn;WriteString(’Unesite redni broj radnika:’);ReadCard(br)

UNTIL Done;WriteLn;IF rad = NIL THENWriteString(’Greska.’)

ELSIF br = rad^.broj THENpom := rad;rad := rad^.sled;DISPOSE(pom)

ELSEtek := rad;WHILE (tek^.sled # NIL) AND

(tek^.sled^.broj < br) DOtek := tek^.sled

END;IF (tek^.sled = NIL) OR

(tek^.sled^.broj > br) THENWriteString(’Greska.’)

ELSEpom := tek^.sled;tek^.sled := tek^.sled^.sled;DISPOSE(pom)

ENDEND

END Otpusti;

PROCEDURE Inform(rad : radnici);VARbr : CARDINAL;

BEGINREPEATWriteLn;WriteString(’Unesite redni broj radnika:’);ReadCard(br)

UNTIL Done;WriteLn;WHILE (rad # NIL) AND (rad^.broj < br) DOrad := rad^.sled

END;IF (rad = NIL) OR (rad^.broj # br) THENWriteString(’Greska.’)

ELSEWriteString(rad^.ime);WriteString(’ ’);WriteString(rad^.prez)

ENDEND Inform;

PROCEDURE Bankrot(VAR rad : radnici);VARpom : radnici;

BEGINWHILE rad # NIL DOpom := rad;rad := rad^.sled;DISPOSE(pom)

ENDEND Bankrot;

BEGINrad := NIL;REPEATClear;WriteString(’s - spisak svih zaposlenih’);WriteLn;WriteString(’z - zaposljavanje radnika’);WriteLn;WriteString(’o - otpustanje radnika’);WriteLn;WriteString(’i - informacije o radniku’);WriteLn;WriteString(’b - bankrot firme’);WriteLn;WriteString(’k - kraj rada’);WriteLn;

REPEATmeni := RdKey();

UNTIL CAP(meni) IN skupZn{’S’, ’Z’, ’O’,’I’, ’B’, ’K’};

Clear;IF CAP(meni) # ’K’ THENCASE CAP(meni) OF’S’ : Spisak(rad)|’Z’ : Zaposli(rad)|’O’ : Otpusti(rad)|’I’ : Inform(rad)|’B’ : Bankrot(rad)

END;WriteLn;WriteString(’-- pritisnite bilo koji ’);WriteString(’taster za nastavak --’);pom := RdKey()

ENDUNTIL CAP(meni) = ’K’

END Radnici.

Procedura Spisak se može realizovati i u rekurzivnoj ver-ziji:PROCEDURE Spisak(rad : radnici);BEGINIF rad # NIL THENWriteString(rad^.ime);WriteString(’ ’);WriteString(rad^.prez);WriteCard(rad^.broj, 8);WriteLn;Spisak(rad^.sled)

ENDEND Spisak;

4.4 Zadatak: Dve liste osoba koje dele sa-držaj, jedna sortirana po visini, druga potežini

Sa tastature učitavati po dva broja koji opisuju osobu (vi-sina i težina) i smeštati ih u povezane listu, tako da postojineopadajuće uređenje i po visini i po težini.MODULE VisTez;FROM Storage IMPORT ALLOCATE, DEALLOCATE;FROM IO IMPORT WrLn, WrStr, RdCard, WrCard;FROM SYSTEM IMPORT TSIZE;TYPEpok = POINTER TO element;element = RECORD

visina, tezina : CARDINAL;Vveza, Tveza : pok

END;VARpocV, pocT : pok;vis, tez : CARDINAL;

PROCEDURE Ispisi(pocV, pocT : pok);VARtek : pok;

BEGINtek := pocV;WrStr(’Po visini:’);WrLn;WHILE tek # NIL DOWrCard(tek^.visina, 6);tek := tek^.Vveza

END;WrLn;tek := pocT;WrStr(’Po tezini:’);WrLn;WHILE tek # NIL DOWrCard(tek^.tezina,6);tek := tek^.Tveza

ENDEND Ispisi;

PROCEDURE Ubaci(VAR pocV, pocT : pok;vis, tez : CARDINAL);

Page 12: Skripta Spa1 Dk

12 Strukture podataka i algoritmi 1 – skripta

VARnovi, tek, iza : pok;nadjen : BOOLEAN;

BEGINIF pocV = NIL THENALLOCATE(pocV, TSIZE(element));pocV^.visina := vis;pocV^.tezina := tez;pocV^.Vveza := NIL;pocV^.Tveza := NIL;pocT := pocV

ELSEALLOCATE(novi, TSIZE(element));novi^.visina := vis;novi^.tezina := tez;tek := pocV;nadjen := FALSE;WHILE (tek # NIL) AND NOT nadjen DOnadjen := vis <= tek^.visina;IF NOT nadjen THENiza := tek;tek := tek^.Vveza

ENDEND;novi^.Vveza := tek;IF tek = pocV THENpocV := novi

ELSEiza^.Vveza := novi

END;tek := pocT;nadjen := FALSE;WHILE (tek # NIL) AND NOT nadjen DOnadjen := tez <= tek^.tezina;IF NOT nadjen THENiza := tek;tek := tek^.Tveza

ENDEND;novi^.Tveza := tek;IF tek = pocT THENpocT := novi

ELSEiza^.Tveza := novi

ENDEND

END Ubaci;

BEGINpocV := NIL;pocT := NIL;WrStr(’Unesite visinu ---- ’);vis := RdCard();WHILE vis > 0 DOWrStr(’Unesite tezinu ---- ’);tez := RdCard();Ubaci(pocV, pocT, vis, tez);WrLn;WrStr(’Unesite visinu ---- ’);vis := RdCard()

END;WrLn;Ispisi(pocV, pocT)

END VisTez.

5 Polinomi preko listi5.1 Moduli

Polinomi su predstavljeni pomoću pokazivača. Apstraktnitip podataka Polinom je definisan u globalnom modulu. Re-dosled parametara kod svih procedura je takav da varijabilniparametri dolaze na kraju.

PolinomL.DEF(* Modul za rad sa polinomima preko listi

verzija 2014; rev 1 *)DEFINITION MODULE PolinomL;TYPEPolinom = POINTER TO Monom;Monom = RECORD

k : REAL;st : CARDINAL;veza : Polinom

END;

PROCEDURE Anuliraj(VAR p: Polinom);PROCEDURE Unos(VAR p: Polinom);PROCEDURE Stampaj(p: Polinom; d: CARDINAL);PROCEDURE Kopiraj(p: Polinom;

VAR kopija: Polinom);PROCEDURE PostaviClan(k: REAL; st:CARDINAL;

VAR p:Polinom);PROCEDURE KoeficijentUz(p:Polinom;

st:CARDINAL):REAL;PROCEDURE MaksimalniStepen(p:Polinom):CARDINAL;PROCEDURE UbaciMonom(mon:Polinom;

VAR p: Polinom);PROCEDURE PromeniZnak(VAR p: Polinom);PROCEDURE Saberi(p1, p2: Polinom;

VAR zbir: Polinom);PROCEDURE SaberiNa(p: Polinom; VAR rez: Polinom);PROCEDURE Oduzmi(p1,p2: Polinom;

VAR razlika: Polinom);PROCEDURE MonomPuta(p, mon: Polinom;

VAR mp : Polinom);PROCEDURE Puta(p1, p2: Polinom; VAR pr: Polinom);PROCEDURE Kolicnik(p1, p2: Polinom;

VAR kol, ost: Polinom;VAR ok : BOOLEAN);

PROCEDURE PolinomNaN(p: Polinom; n: CARDINAL;VAR rez: Polinom);

PROCEDURE DisposePolinom(VAR p: Polinom);

END PolinomL.

PolinomL.MOD(* Modul za rad sa polinomima preko listi

verzija 2014; rev 1 *)IMPLEMENTATION MODULE PolinomL;FROM InOut IMPORT Write, WriteString, WriteLn,

WriteCard, ReadCard, Done;FROM RealInOut IMPORT WriteReal, ReadReal;FROM Storage IMPORT ALLOCATE, DEALLOCATE;

PROCEDURE Anuliraj(VAR p: Polinom);BEGINp := NIL;

END Anuliraj;

PROCEDURE Kopiraj(p: Polinom; VAR kopija: Polinom);VARpomocni: Polinom;

BEGINIF p = NIL THENkopija := NIL

ELSENEW(kopija);kopija^ := p^;p := p^.veza;pomocni := kopija;WHILE p <> NIL DONEW(pomocni^.veza);pomocni := pomocni^.veza;pomocni^ := p^;p := p^.veza

ENDEND

END Kopiraj;

PROCEDURE Stampaj(p: Polinom; d: CARDINAL);

PROCEDURE StampajMonom(m : Polinom);BEGINWITH m^ DO

Page 13: Skripta Spa1 Dk

5.1 Moduli 13

IF st <> 0 THENIF ABS(k) <> 1.0 THENWriteReal(ABS(k), d)

END;Write(’x’);IF st <> 1 THENWrite(’^’);WriteCard(st, 1)

ENDELSEWriteReal(ABS(k), d)

ENDEND

END StampajMonom;

BEGINIF p = NIL THENWriteReal(0., d)

ELSEIF p^.k < 0.0 THENWriteString(’ - ’)

END;StampajMonom(p);p := p^.veza;WHILE p <> NIL DOIF p^.k > 0.0 THENWriteString(’ + ’)

ELSEWriteString(’ - ’)

END;StampajMonom(p);p := p^.veza

ENDEND

END Stampaj;

PROCEDURE PostaviClan(k:REAL; st:CARDINAL;VAR p:Polinom);

VARcilj, prethodni : Polinom;

BEGINcilj := p;prethodni := NIL;WHILE (cilj # NIL) AND (cilj^.st>st) DOprethodni := cilj;cilj := cilj^.veza;

END;(* da li upisujemo vrednost ili sklanjamo clan *)IF k#0.0 THEN(* da li menjamo clan ili pravimo novi *)IF (cilj # NIL) AND (cilj^.st = st) THENcilj^.k:=k;

ELSENEW(cilj);cilj^.k := k;cilj^.st := st;cilj^.veza := NIL;IF prethodni = NIL THEN(* ili je prazan polinom, ili dodajemo na

pocetak *)cilj^.veza := p;p := cilj;

ELSEcilj^.veza := prethodni^.veza;prethodni^.veza := cilj;

END;END;

ELSE(* da li postoji ovakav clan *)IF (cilj # NIL) AND (cilj^.st = st) THENIF p = cilj THENp := p^.veza;

ELSEprethodni^.veza:= prethodni^.veza^.veza;

END;DISPOSE(cilj);

END;END;

END PostaviClan;

PROCEDURE KoeficijentUz(p:Polinom;st:CARDINAL):REAL;

VARtekuci : Polinom;

BEGINtekuci := p;WHILE (tekuci#NIL) AND (tekuci^.st > st) DOtekuci := tekuci^.veza;

END;IF (tekuci # NIL) AND (tekuci^.st = st) THENRETURN tekuci^.k;

ELSERETURN 0.0;

END;END KoeficijentUz;

PROCEDURE MaksimalniStepen(p:Polinom):CARDINAL;BEGINIF p#NIL THENRETURN p^.st;

ELSERETURN 0;

END;END MaksimalniStepen;

PROCEDURE UbaciMonom(mon:Polinom; VAR p: Polinom);VARstari, tekuci, kopija: Polinom;

BEGINIF mon # NIL THENNEW(kopija);kopija^ := mon^;tekuci := p;

stari := NIL;WHILE (tekuci#NIL) AND (tekuci^.st>kopija^.st)

DOstari := tekuci;tekuci := tekuci^.veza

END;kopija^.veza := tekuci;IF tekuci = p THENp := kopija

ELSEstari^.veza := kopija

END;IF (tekuci#NIL) AND (kopija^.st = tekuci^.st)

THENkopija^.k := kopija^.k + tekuci^.k;kopija^.veza := tekuci^.veza;DISPOSE(tekuci);IF kopija^.k = 0.0 THENIF p = kopija THENp := kopija^.veza

ELSEstari^.veza := kopija^.veza

END;DISPOSE(kopija)

ENDEND

ENDEND UbaciMonom;

PROCEDURE Unos(VAR p : Polinom);VARi, n: CARDINAL;novi: Polinom;

BEGINAnuliraj(p);REPEATWriteLn;WriteString(’Unesite broj monoma n (n>=0) ’);ReadCard(n);

UNTIL Done;WriteLn;FOR i := 1 TO n DONEW(novi);WITH novi^ DOREPEATWriteString(’Unesite koeficijent monoma

br.’);WriteCard(i, 1);

Page 14: Skripta Spa1 Dk

14 Strukture podataka i algoritmi 1 – skripta

WriteString(’ (<> 0) ’);ReadReal(k);WriteLn

UNTIL k <> 0.0;REPEATWriteLn;WriteString(’Unesite eksponent monoma br.’);WriteCard(i, 1);WriteString(’ (>=0) ’);ReadCard(st);

UNTIL Done;WriteLn;

END;UbaciMonom(novi, p);DISPOSE(novi);

ENDEND Unos;

PROCEDURE Saberi(p1, p2: Polinom; VAR zbir:Polinom);

BEGINKopiraj(p1, zbir);WHILE p2 <> NIL DOUbaciMonom(p2, zbir);p2 := p2^.veza

ENDEND Saberi;

PROCEDURE SaberiNa(p: Polinom; VAR rez: Polinom);BEGINWHILE p <> NIL DOUbaciMonom(p,rez);p := p^.veza;

END;END SaberiNa;

PROCEDURE PromeniZnak(VAR p: Polinom);VARt: Polinom;

BEGINt := p;WHILE t <> NIL DOt^.k := - t^.k;t := t^.veza

ENDEND PromeniZnak;

PROCEDURE Oduzmi(p1,p2: Polinom; VAR razlika:Polinom);

BEGINKopiraj(p2, razlika);PromeniZnak(razlika);WHILE p1 <> NIL DOUbaciMonom(p1, razlika);p1 := p1^.veza

ENDEND Oduzmi;

PROCEDURE MonomPuta(p, mon: Polinom; VAR mp:Polinom);

VARtekuci: Polinom;

BEGINAnuliraj(mp);IF (mon <> NIL) AND (p <> NIL) THENNEW(mp);mp^.k := p^.k * mon^.k;mp^.st := p^.st + mon^.st;p := p^.veza;tekuci := mp;WHILE p <> NIL DONEW(tekuci^.veza);tekuci := tekuci^.veza;tekuci^.k := p^.k * mon^.k;tekuci^.st := p^.st + mon^.st;p := p^.veza

END;tekuci^.veza := NIL

ENDEND MonomPuta;

PROCEDURE Puta(p1, p2: Polinom; VAR pr: Polinom);VARpomocni, brisi: Polinom;

BEGINAnuliraj(pr);IF (p1 <> NIL) AND (p2 <> NIL) THENMonomPuta(p1, p2, pr);p2 := p2^.veza;WHILE p2 <> NIL DOMonomPuta(p1, p2, pomocni);REPEATUbaciMonom(pomocni, pr);brisi := pomocni;pomocni := pomocni^.veza;DISPOSE(brisi);

UNTIL pomocni = NIL;p2 := p2^.veza

ENDEND

END Puta;

PROCEDURE Kolicnik(p1, p2: Polinom; VAR kol, ost:Polinom; VAR ok: BOOLEAN);

PROCEDURE Deli(VAR kol, ost: Polinom);VARnovi, pomocni: Polinom;

BEGINIF ost <> NIL THENIF ost^.st >= p2^.st THENNEW(novi);novi^.k := - ost^.k / p2^.k;novi^.st := ost^.st - p2^.st;MonomPuta(p2, novi, pomocni);SaberiNa(pomocni, ost);DisposePolinom(pomocni);novi^.k := - novi^.k;UbaciMonom(novi, kol);DISPOSE(novi);Deli(kol, ost)

ENDEND

END Deli;

BEGIN (* Kolicnik *)ok := TRUE;Anuliraj(kol);IF p2 = NIL THENok := FALSE

ELSEKopiraj(p1, ost);Deli(kol, ost)

ENDEND Kolicnik;

PROCEDURE PolinomNaN(p: Polinom; n: CARDINAL;VAR rez: Polinom);

VARi: CARDINAL;pret : Polinom;

BEGINIF n = 0 THENNEW(rez);rez^.k := 1.0;rez^.st := 0;rez^.veza := NIL;

ELSEKopiraj( p, rez );FOR i := 2 TO n DOpret := rez;Puta(pret, p, rez);DisposePolinom(pret);

ENDEND;

END PolinomNaN;

PROCEDURE DisposePolinom(VAR p: Polinom);VARpomocni: Polinom;

BEGINpomocni := p;

Page 15: Skripta Spa1 Dk

5.2 Zadatak: Sabiranje sa unapred određenim polinomom 15

WHILE pomocni # NIL DOp := p^.veza;DISPOSE(pomocni);pomocni := p

ENDEND DisposePolinom;

END PolinomL.

5.2 Zadatak: Sabiranje sa unapred određe-nim polinomom

Želimo da ispišemo uneti polinom uvećan zax5 − 3x4 + 4x + 7.MODULE polinom;FROM PolinomL IMPORT Polinom, Stampaj, Anuliraj,

DisposePolinom, PostaviClan, Unos,Saberi;

FROM InOut IMPORT WriteString, WriteLn;

VARp,q,rez : Polinom;

BEGIN(* korisnik unosi prvi polinom *)WriteString("Unesite polinom:");WriteLn;Unos(p);(* drugi polinom kreiramo mi,

monom po monom *)Anuliraj(q); (* isto sto i q:=NIL; *)(* postavimo clan x^5 *)PostaviClan(1.0,5,q);(* -3 x^4 *)PostaviClan(-3.0,4,q);(* 4 x *)PostaviClan(4.0,1,q);(* 7 (x^0) *)PostaviClan(7.0,0,q);(* saberemo polinome *)Saberi(p, q, rez);(* odstampamo rezultat i polinome *)WriteString("p: ");Stampaj(p,0);WriteLn;WriteString("q: ");Stampaj(q,0);WriteLn;WriteString("rez: ");Stampaj(rez,0);WriteLn;DisposePolinom(p);DisposePolinom(q);DisposePolinom(rez);

END polinom.

5.3 Zadatak: Suma k polinomaNapisati program koji ucitava broj k (1<=k<=50) i k

polinoma, a nakon toga izracunava njihovu sumuMODULE PolSuma;(* Napisati program koji ucitava broj k (1 <= k <=

50) i k polinoma, a nakon toga izracunavanjihovu sumu *)

FROM PolinomL IMPORT Polinom, Anuliraj,DisposePolinom,

Unos, Stampaj, SaberiNa;FROM InOut IMPORT WriteLn, WriteString, ReadCard,

WriteCard;CONSTmaxk = 50;

TYPEnizPol = ARRAY [1..maxk] OF Polinom;

VARi, k: CARDINAL;

suma : Polinom;p : nizPol;

BEGINREPEATWriteString(’Unesite broj k (1 <= k <= ’);WriteCard(maxk, 1);WriteString(’) ’);ReadCard(k);WriteLn;

UNTIL (1 <= k) AND (k <= maxk);FOR i := 1 TO k DOWriteLn;WriteString(’Unos ’);WriteCard(i, 1);WriteString(’. polinoma.’);WriteLn;Unos(p[i])

END;Anuliraj(suma);FOR i := 1 TO k DOSaberiNa(p[i], suma)

END;WriteLn;WriteString(’Njihova suma je:’);WriteLn;Stampaj(suma, 4);DisposePolinom(suma);FOR i := 1 TO k DODisposePolinom(p[i]);

END;END PolSuma.

6 Stek i red opsluživanja6.1 Primer: osnovno korišćenje steka i reda

opsluživanja

MODULE stekred;(* prvo importujemo cele module, da bi mogli da

koristimo istoimeneprocedure (kao MakeNull) iz oba modula *)

IMPORT RedOpsl;IMPORT Stek;(* nakon toga importujemo i sve raznoimene delove,

da ne bi moralida kucamo puna imena modula svaki put i kad ne

moramo *)FROM Stek IMPORT StekTip, Top, Pop, Push;FROM RedOpsl IMPORT RedOpslTip, First, PopFirst,

AddRear;FROM InOut IMPORT

ReadString,WriteString,Write,WriteLn;FROM Strings IMPORT Length;

VARstr : ARRAY[1..256] OF CHAR;q :RedOpslTip;s :StekTip;i : CARDINAL;ok,palin : BOOLEAN;c,c1 : CHAR;

BEGINWriteString("unesite string: ");ReadString(str);

(* inicijalizujemo strukture *)Stek.MakeNull(s);RedOpsl.MakeNull(q);(* ubacujemo elemente u stek *)FOR i:=1 TO Length(str) DO

Push(s, str[i], ok);END;(* ubacujemo elemente u red opsl *)FOR i:=1 TO Length(str) DO

AddRear(q, str[i], ok);END;WriteLn;WriteString("sadrzaj steka");

Page 16: Skripta Spa1 Dk

16 Strukture podataka i algoritmi 1 – skripta

WriteLn;WHILE NOT Stek.Empty(s) DO

Top(s,c,ok);Pop(s,ok);Write(c);

END;WriteLn;WriteString("sadrzaj reda opsl.");WriteLn;WHILE NOT RedOpsl.Empty(q) DO

First(q,c,ok);PopFirst(q,ok);Write(c);

END;WriteLn;

END stekred.

6.2 Zadatak: Ilustracija pisanja u fajl uz po-moć bafera

DEFINITION MODULE QueueInfo;CONSTMaxqueue = 100;

TYPEInfoTip = CHAR;

END QueueInfo.

IMPLEMENTATION MODULE QueueInfo;END QueueInfo.

DEFINITION MODULE RedOpsl1;FROM QueueInfo IMPORT InfoTip,Maxqueue;TYPENiz = ARRAY[1..Maxqueue] OF InfoTip;RedOpslTip = RECORD

Prvi, Zadnji : CARDINAL;Element : Niz

END;

PROCEDURE MakeNull(VAR q : RedOpslTip);PROCEDURE Empty(VAR q : RedOpslTip) : BOOLEAN;PROCEDURE First(VAR q : RedOpslTip;

VAR x : InfoTip;VAR ok : BOOLEAN);

PROCEDURE PopFirst(VAR q : RedOpslTip;VAR ok : BOOLEAN);

PROCEDURE AddRear(VAR q : RedOpslTip;x : InfoTip;VAR ok : BOOLEAN);

END RedOpsl1.

IMPLEMENTATION MODULE RedOpsl1;FROM QueueInfo IMPORT Maxqueue,InfoTip;

PROCEDURE MakeNull(VAR q : RedOpslTip);BEGINWITH q DOPrvi := 0;Zadnji := 0

ENDEND MakeNull;

PROCEDURE Empty(VAR q : RedOpslTip) : BOOLEAN;BEGINRETURN q.Zadnji = 0

END Empty;

PROCEDURE First(VAR q : RedOpslTip;VAR x : InfoTip;VAR ok : BOOLEAN);

BEGINIF Empty(q) THENok := FALSE

ELSEok := TRUE;WITH q DOx := Element[Prvi]

ENDEND

END First;

PROCEDURE AddOne(i : CARDINAL) : CARDINAL;BEGINIF i = Maxqueue THENRETURN 1

ELSERETURN i+1

ENDEND AddOne;

PROCEDURE PopFirst(VAR q : RedOpslTip;VAR ok : BOOLEAN);

BEGINIF Empty(q) THENok := FALSE

ELSEok := TRUE;WITH q DOIF Prvi = Zadnji THENMakeNull(q)

ELSEPrvi := AddOne(Prvi)

ENDEND

ENDEND PopFirst;

PROCEDURE AddRear(VAR q : RedOpslTip;x : InfoTip;VAR ok : BOOLEAN);

BEGINWITH q DOIF AddOne(Zadnji) = Prvi THENok := FALSE

ELSEok := TRUE;IF Empty(q) THENPrvi := 1;Zadnji := 1

ELSEZadnji := AddOne(Zadnji)

END;Element[Zadnji] := x

ENDEND

END AddRear;

END RedOpsl1.

MODULE Bafer;FROM RedOpsl1 IMPORT RedOpslTip, MakeNull, Empty,

First, PopFirst, AddRear;FROM FIO IMPORT File,WrChar, Create, Close;IMPORT IO;

CONSTImeIzlaza = ’izlaz.txt’;

VARizlaz : File;znak : CHAR;buffer : RedOpslTip;

PROCEDURE IsprazniBafer(VAR dat : File;VAR buf : RedOpslTip);

VARznak : CHAR;ok : BOOLEAN;

BEGINWHILE NOT Empty(buf) DOFirst(buf, znak, ok);PopFirst(buf, ok);WrChar(dat, znak)

ENDEND IsprazniBafer;

PROCEDURE BaferWrite(VAR dat : File;VAR buf : RedOpslTip;

Page 17: Skripta Spa1 Dk

6.3 Zadatak: Ispitivanje da li reč pripada gramatici wcw+ 17

znak : CHAR);VARok : BOOLEAN;

BEGINAddRear(buf, znak, ok);IF NOT ok THENIsprazniBafer(dat, buf);AddRear(buf, znak, ok)

ENDEND BaferWrite;

BEGINizlaz := Create(ImeIzlaza);MakeNull(buffer);IO.WrStr(’Unesite tekst, koji treba da se unese u

datoteku ’);IO.WrStr(ImeIzlaza);IO.WrChar(’.’);IO.WrLn;IO.WrStr(’Unos zavrsite tackom.’);IO.WrLn;znak := IO.RdChar();WHILE znak # ’.’ DOBaferWrite(izlaz, buffer, znak);znak := IO.RdChar();

END;IsprazniBafer(izlaz, buffer);Close(izlaz)

END Bafer.

6.3 Zadatak: Ispitivanje da li reč pripadagramatici wcw+

Reč pripada ovoj gramatici ako joj se prvi deo (w) sastojisamo od slova ’a’ i ’b’, sledi slovo ’c’ a nakon njega obrnutareč reči w.DEFINITION MODULE Stek;CONSTMaxstack = 100;

TYPENiz = ARRAY [1..Maxstack] OF CHAR;StekTip = RECORD

Top : CARDINAL;Element : Niz

END;PROCEDURE MakeNull(VAR s : StekTip);PROCEDURE Empty(VAR s : StekTip) : BOOLEAN;

PROCEDURE Top(VAR s : StekTip;VAR x : CHAR;VAR ok : BOOLEAN);

PROCEDURE Pop(VAR s : StekTip;VAR ok : BOOLEAN);

PROCEDURE Push(VAR s : StekTip;x : CHAR;VAR ok : BOOLEAN);

END Stek.

IMPLEMENTATION MODULE Stek;

PROCEDURE MakeNull(VAR s : StekTip);BEGINs.Top := 0

END MakeNull;

PROCEDURE Empty(VAR s : StekTip) : BOOLEAN;BEGINRETURN s.Top = 0

END Empty;

PROCEDURE Top(VAR s : StekTip;VAR x : CHAR;VAR ok : BOOLEAN);

BEGINIF Empty(s) THENok := FALSE

ELSEok := TRUE;WITH s DO

x := Element[Top]END

ENDEND Top;

PROCEDURE Pop(VAR s : StekTip;VAR ok : BOOLEAN);

BEGINIF Empty(s) THENok := FALSE

ELSEok := TRUE;DEC(s.Top)

ENDEND Pop;

PROCEDURE Push(VAR s : StekTip;x : CHAR;VAR ok : BOOLEAN);

BEGINWITH s DOIF Top = Maxstack THENok := FALSE

ELSEok := TRUE;INC(Top);Element[Top] := x

ENDEND

END Push;END Stek.

MODULE wcw;(* Da li rec pripada gramatici wcw+. *)FROM Stek IMPORT StekTip, MakeNull, Empty,

Top, Pop, Push;FROM InOut IMPORT Read, Write, WriteString, EOL;TYPEslova = SET OF CHAR;

VARS : StekTip;Ch, C : CHAR;ok : BOOLEAN;

BEGINMakeNull(S);Read(Ch);ok := TRUE;WHILE ok AND (Ch IN slova{’a’, ’b’}) DOPush(S, Ch, ok);Read(Ch);

END;IF NOT ok THENWriteString(’Greska - mali stek’)

ELSIF Ch # ’c’ THENWriteString(’Pogresan string’)

ELSERead(Ch);WHILE ok AND (Ch # EOL) DOTop(S, C, ok);ok := ok AND (C = Ch);IF ok THENPop(S, ok);Read(Ch);

ENDEND;IF NOT (ok AND Empty(S)) THENWriteString(’Pogresan string’)

ELSEWriteString(’String pripada jeziku L’)

ENDEND

END wcw.

6.4 Zadatak: Kalkulator za izračunavanjepostfiksnih izraza

Napraviti kalkulator za izračunavanje postfiksnih izraza.Svi brojevi koji figurišu u izrazu su jednocifreni.

Page 18: Skripta Spa1 Dk

18 Strukture podataka i algoritmi 1 – skripta

MODULE PostFix;

FROM StekI IMPORT StekTip, MakeNull, Empty, Top,Pop, Push;

FROM InOut IMPORT Read, Write, WriteInt, EOL;TYPEslova = SET OF CHAR;

VARS : StekTip;Ch : CHAR;Op1, Op2 : INTEGER;ok : BOOLEAN;

PROCEDURE Conv(Ch : CHAR) : INTEGER;BEGINRETURN ORD(Ch) - ORD(’0’)

END Conv;

BEGINMakeNull(S);Read(Ch);WHILE Ch # EOL DOIF Ch IN slova{’+’, ’-’, ’/’, ’*’, ’%’} THENTop(S, Op2, ok);Pop(S, ok);Top(S, Op1, ok);Pop(S, ok);CASE Ch OF’+’ : Op1 := Op1 + Op2 |’-’ : Op1 := Op1 - Op2 |’*’ : Op1 := Op1 * Op2 |’/’ : Op1 := Op1 DIV Op2 |’%’ : Op1 := Op1 MOD Op2

END;Push(S, Op1, ok)

ELSEPush(S, Conv(Ch), ok)

END;Read(Ch);

END;Top(S, Op1, ok);Write(’=’);WriteInt(Op1,5)

END PostFix.

7 Simulacija rekurzijeNa početku označiti sve rekurzivne pozive u originalnoj

proceduri adresama (npr. 1,2,3... ili konstante nabrojivogtipa podataka).

Na steku se čuvaju lokalne promenljive, parametri pro-cedure i adresa mesta poziva, a u skladu sa tim se kreiraInfoTip.

Trivijalnim pozivom se smatra onaj koji se izračunava bezdodatnih rekurzivnih poziva.

U kodu ispod, treba_rekurzija znači da je poziv ne-trivijalan, odnosno treba naći uslove pod kojima se sigurnodešavaju rekurzivni pozivi.MakeNull(S);REPEATWHILE treba_rekurzija DO-prepisati sve od pocetka originalneprocedure do prvog rekurzivnog poziva-staviti na stek potrebnelokalne promenljive, parametre procedure iadresu mesta poziva-podesiti vrednosti parametara da budukao u rekurzivnom pozivu procedure

END;trivijalan pozivumesto RETURN x pisati rez := xjos := TRUE;WHILE jos AND NOT Empty(S) DOTop(S, el, ok);Pop(S, ok);-restauriramo vrednosti sa steka

-u zavisnosti od adrese poziva nastavimoprepisivanje originalne procedure satog mesta-ako se dodje do novog rek. poziva tada:

-sacuvati na steku vrednosti-podesiti vrednosti parametara da budukao u rekurzivnom pozivu procedure-ici na pocetak koda(ovo se postize sa jos := FALSE)

-inaceako se naidje na RETURN x pisati rez := x

ENDUNTIL Empty(S);

Ako je procedura funkcijska tada se na kraj dodajeRETURN rez.

ZADACISimulirati ponašanje sledećih rekurzivnih procedura

(funkcija) upotrebom steka:

7.1 Primer 1 – faktorijel

MODULE Fakto;(* InfoTip = CARDINAL; *)

FROM IO IMPORT WrStr, WrLn, WrCard, RdCard;FROM StekC IMPORT StekTip, MakeNull, Empty,

Top, Pop, Push;VARn : CARDINAL;

PROCEDURE RFakto(n : CARDINAL) : CARDINAL;BEGINIF n <= 1 THENRETURN 1

ELSERETURN n * RFakto(n-1)

ENDEND RFakto;

PROCEDURE SFakto(n : CARDINAL) : CARDINAL;VARs : StekTip;rez : CARDINAL;OK : BOOLEAN;

BEGINMakeNull(s);WHILE n > 1 DOPush(s,n,OK);DEC(n)

END;rez := 1;WHILE NOT Empty(s) DOTop(s, n, OK);Pop(s, OK);rez := n * rez

END;RETURN rez

END SFakto;

BEGINWrStr(’n = ’);n := RdCard();WrLnWrStr(’n! = ’);WrCard(RFakto(n), 1);WrStr(’ = ’);WrCard(SFakto(n), 1)

END Fakto.

7.2 Primer 2 – stepenovanje

MODULE Step;(* InfoTip = RECORD

x : REAL;n : CARDINAL;

Page 19: Skripta Spa1 Dk

7.3 Primer 3 – Fibonači 19

adr : (par, nepar)END;

*)FROM IO IMPORT WrStr, WrLn, WrReal,

RdReal, RdCard;FROM StekStep IMPORT StekTip, MakeNull, Empty,

Top, Pop, Push, InfoTip, AdrTip;VARn : CARDINAL;x : REAL;

PROCEDURE Sqr(y : REAL) : REAL;BEGINRETURN y * y

END Sqr;

PROCEDURE RStep(x : REAL;n : CARDINAL) : REAL;

BEGINIF n = 0 THENRETURN 1.

ELSIF ODD(n) THENRETURN x * Sqr( RStep(x, n DIV 2) )

ELSERETURN Sqr( RStep(x, n DIV 2) )

ENDEND RStep;

PROCEDURE SStep(x : REAL;n : CARDINAL ) : REAL;

VARs : StekTip;OK : BOOLEAN;rez : REAL;el : InfoTip;

BEGINMakeNull(s);WHILE n > 0 DOel.x := x;el.n := n;IF ODD(n) THENel.adr := nepar;

ELSEel.adr := par

END;Push(s,el,OK);n := n DIV 2

END;rez := 1.;WHILE NOT Empty(s) DOTop(s, el, OK);Pop(s, OK);x := el.x;n := el.n;IF el.adr = nepar THENrez := x * Sqr(rez)

ELSErez := Sqr(rez)

ENDEND;RETURN rez

END SStep;

BEGINWrStr(’x =? ’);x := RdReal();WrLn;WrStr(’n =? ’);n := RdCard();WrStr(’x^n = ’);WrReal(RStep(x, n), 10, 1);WrStr(’ = ’);WrReal(SStep(x, n), 10, 1)

END Step.

7.3 Primer 3 – Fibonači

MODULE Fib;(* InfoTip = RECORD

n : CARDINAL;PrviSab : CARDINAL;

adr : (prvi, drugi)END;

*)

FROM IO IMPORT WrStr, WrLn, WrCard, RdCard;FROM StekFib IMPORT StekTip, MakeNull, Empty,

Top, Pop, Push, InfoTip, AdrTip;VARn : CARDINAL;

PROCEDURE RFib(n : CARDINAL) : CARDINAL;BEGINIF n <= 1 THENRETURN n

ELSERETURN RFib(n-1) + RFib(n-2)

ENDEND RFib;

PROCEDURE SFib(n : CARDINAL ) : CARDINAL;VARs : StekTip;OK, jos : BOOLEAN;rez, PrviSab : CARDINAL;el : InfoTip;

BEGINMakeNull(s);REPEATWHILE n > 1 DOel.n := n;el.adr := prvi;Push(s,el,OK);DEC(n)

END;rez := (n);jos := TRUE;WHILE (NOT Empty(s)) AND jos DOTop(s, el, OK);Pop(s, OK);n := el.n;IF el.adr = prvi THENPrviSab := rez;el.n := n;el.adr := drugi;el.PrviSab := PrviSab;Push(s, el, OK);DEC(n, 2);jos := FALSE

ELSEPrviSab := el.PrviSab;rez := PrviSab + rez

ENDEND

UNTIL Empty(s);RETURN rez

END SFib;

BEGINWrStr(’n =? ’);n := RdCard();WrStr(’F(n) = ’);WrCard(RFib(n), 1);WrStr(’ = ’);WrCard(SFib(n), 1)

END Fib.

7.4 Primer 4 – faktorijel 2

MODULE Faktor;(* InfoTip = CARDINAL; *)FROM IO IMPORT WrStr, WrLn, WrCard, RdCard;FROM StekC IMPORT StekTip, MakeNull, Empty,

Top, Pop, Push;VARn,rez : CARDINAL;

PROCEDURE RFakto(n : CARDINAL;VAR rez : CARDINAL);

BEGINIF n = 0 THENrez := 1

Page 20: Skripta Spa1 Dk

20 Strukture podataka i algoritmi 1 – skripta

ELSERFakto(n-1, rez);rez := n * rez

ENDEND RFakto;

PROCEDURE SFakto(n : CARDINAL;VAR rez : CARDINAL);

VARs : StekTip;OK : BOOLEAN;

BEGINMakeNull(s);WHILE n > 0 DOPush(s,n,OK);DEC(n)

END;rez := 1;WHILE NOT Empty(s) DOTop(s, n, OK);Pop(s, OK);rez := n * rez

ENDEND SFakto;

BEGINWrStr(’n =? ’);n := RdCard();WrLn;WrStr(’n! = ’);RFakto(n, rez);WrCard(rez, 1);WrStr(’ = ’);SFakto(n, rez);WrCard(rez, 1)

END Faktor.

7.5 Primer 5 (ispitni)

MODULE Rek1;(* InfoTip = RECORD

d, g, m1, m2 : INTEGER;adr : (prvi, drugi)

END;*)FROM Stek1 IMPORT StekTip, adresa, InfoTip,

MakeNull, Empty, Top, Pop, Push;IMPORT IO;VARX : ARRAY [1..20] OF INTEGER;

PROCEDURE Max(d, g: INTEGER) : INTEGER;VARm1, m2 : INTEGER;

BEGINIF d>g THENRETURN MIN(INTEGER)

ELSIF d=g THENRETURN X[d]

ELSEm1 := Max(d, (d+g) DIV 2);m2 := Max((d+g) DIV 2 +1, g);IF m1 > m2 THENRETURN m1

ELSERETURN m2

ENDEND

END Max;

PROCEDURE SMax(d, g: INTEGER) : INTEGER;VARS : StekTip;el : InfoTip;ok, jos : BOOLEAN;m1, m2, rez : INTEGER;

BEGINMakeNull(S);REPEATWHILE d<g DOel.d := d;

el.g := g;el.adr := prvi;Push(S, el, ok);g := (d+g) DIV 2

END;IF d>g THENrez := MIN(INTEGER)

ELSE (* d=g *)rez := X[d]

END;jos := TRUE;WHILE jos AND NOT Empty(S) DOTop(S, el, ok);Pop(S, ok);d := el.d;g := el.g;m1 := el.m1;IF el.adr = prvi THENm1 := rez;el.m1 := m1;el.adr := drugi;Push(S, el, ok);d := (d+g) DIV 2 + 1;jos := FALSE

ELSE (*el.adr = drugi*)m2 := rez;IF m1 > m2 THENrez := m1

ELSErez := m2

ENDEND

ENDUNTIL Empty(S);RETURN rez

END SMax;

BEGIN (* glavni program *)X[1] := 3;X[2] := 2;X[3] := 5;X[4] := -7;X[5] := 0;IO.WrCard(Max(1, 5), 3);IO.WrLn;IO.WrCard(SMax(1, 5), 3);IO.WrLn

END Rek1.

7.6 Primer 6 (ispitni)

MODULE Rek2;(* InfoTip = RECORD

x, y, n : CARDINAL;adr : (prvi, drugi, treci, cetvrti)

END;*)FROM Stek2 IMPORT StekTip, adresa, InfoTip,

MakeNull, Empty, Top, Pop, Push;IMPORT IO;

PROCEDURE g(x : CARDINAL; y : CARDINAL;n : CARDINAL) : CARDINAL;

BEGINIF n < 3 THENRETURN x + y

ELSIF ODD(n) THENRETURN g(g(x+1, y, n-2), y, n-3)

ELSERETURN g(x, g(x, y+1, n-2), n-3)

ENDEND g;

PROCEDURE Sg(x : CARDINAL; y : CARDINAL;n : CARDINAL) : CARDINAL;

VARS : StekTip;el : InfoTip;ok, jos : BOOLEAN;rez : CARDINAL;

BEGIN

Page 21: Skripta Spa1 Dk

A Native XDS Modula 2 – kratko uputstvo I

MakeNull(S);REPEATWHILE n >= 3 DOIF ODD(n) THENel.x := x;el.y := y;el.n := n;el.adr := prvi;Push(S, el, ok);INC(x);DEC(n, 2)

ELSEel.x := x;el.y := y;el.n := n;el.adr := treci;Push(S, el, ok);INC(y);DEC(n, 2)

ENDEND;rez := x+y;jos := TRUE;WHILE jos AND NOT Empty(S) DOTop(S, el, ok);Pop(S, ok);x := el.x;y := el.y;n := el.n;IF el.adr = prvi THENel.adr := drugi;Push(S, el, ok);x := rez;DEC(n, 3);jos := FALSE

ELSIF el.adr = treci THENel.adr := cetvrti;Push(S, el, ok);y := rez;DEC(n, 3);jos := FALSE

ENDEND

UNTIL Empty(S);RETURN rez

END Sg;

BEGIN (* glavni program *)IO.WrCard(g(2, 3, 10), 3);IO.WrCard(Sg(2, 3, 10), 3);

END Rek2.

A Native XDS Modula 2 – kratkouputstvo

Ovo uputstvo ukratko pokriva kako se može nabaviti XDSModula 2 za Windows sistem, njenu instalaciju, te kako na-praviti i pokretnuti jednostavan program.

Dobavljanje instalacijeNative XDS Modula 2 se može besplatno skinuti sa sajta

proizvođača, tačnije na adresi:http://www.excelsior-usa.com/xdsdl.html

Prvo se prikazuje ugovor o korišćenju koji na dnu trebapotvrditi da ste razumeli i da ćete ga se pridržavati.

Na stranici koja se potom otvara je potrebno odabrati“XDS 2.6 beta 2 for Windows” i snimiti je na računar.

Instalacija okruženjaOsnovno okruženje (xds-x86...) se instalira pokretanjem

prethodno pomenute instalacione arhive.

Korisnicima Windows-a 7 preporučujemo da pokrenu in-stalacione pakete pomoću opcije “Run as administrator” dokoje se stiže desnim klikom miša.

Pretpostavićemo u daljem tekstu da je program instaliranu C:/XDS/

Pokretanje okruženjaPo uspešnoj instalaciji bi trebalo da postoji ikonica na

desktopu, kao i grupa sa programom u start meniju.Ukoliko iz bilo kakvog razloga ne postoje odgovarajuće

prečice, okruženje se može pokrenuti uz pomoć izvršnog fajlaC:/XDS/BIN/xds.exe (ako je instalirano na podrazumeva-noj lokaciji).

Prvi projekatDa bismo mogli da pišemo i pokrećemo svoj program,

potrebno je prvo napraviti projekat za njega, što se radi nasledeći način:

• Iz menija se odabere Project->New.• U dijalogu se klikne na gornje dugme “Browse”, oda-

bere se putanja gde će se kreirati projekat i ukuca seime novog projekta.

• U drugom polju “Template” ne treba da piše ništa.Ukoliko postoji neki tekst, obrisati ga.

• Kliknuti na “OK”• Iskočiće dijalog na kome piše da ne postoji fajl za edi-

tovanje, kliknuti na “OK” da se on napravi.• Pojavljuje se forma za kucanje programa, ukucati (na

primer):MODULE Hello;FROM InOut IMPORT WriteString,WriteLn;BEGINWriteString("Hello World");WriteLn;

END Hello.

• Program se može pokrenuti na različite načine, pričemu se automatski prevodi:

– Klik na “Run” ikonicu u toolbaru (plavi čovečuljakkoji trči)

– Meni Debug->Run– Prečica Ctrl+F9 na tastaturi

• Ako je sve u redu sa programom, treba da se pojavinovi terminal u kome se ispisuje rezultat izvršavanjaprograma, u našem slučaju jednostavna pozdravna po-ruka.

Naravno moguće je i samo prevesti (kompajlirati) pro-gram, tako da se samo prikažu greške (ako ih ima) i bezpokretanja programa:

• Klik na “Compile” ikonicu u toolbaru• Meni Tools->Compile• Prečica F9 na tastaturi

Ukoliko u programu postoje greške, on neće biti pokre-nut, već će se dobiti lista grešaka u donjem delu prozora.Na primer ako obrišemo “S” u četvrtom redu i probamo dapokrenemo program, taj red će biti označen svetlo plavombojom i dobićemo poruku:

- Error in pro1.mod [4:5]: Undeclaredidentifier "Writeting"

Page 22: Skripta Spa1 Dk

II Strukture podataka i algoritmi 1 – skripta

Što znači da u četvrtom redu, kod petog karatkera postojiproblem, da identifikator nije deklarisan, što najčešće značida ga nismo uvezli, ili, kao u našem slučaju, da smo napraviligrešku u kucanju.

Stvar na koju isto treba obratiti pažnju je da se nekadgreška prijavljue nešto kasnije u tekstu nego što je napra-vljena. Na primer, ako obrišemo “;” na kraju četvrtog redai probamo da pokrenemo program, peti red će biti označensvetlo plavom bojom i dobićemo poruku:

- Error in pro1.mod [5:5]: Expected symbol";"

Ovo se desilo jer nedostaje tačka zarez na kraju četvrtogreda, ali će kompajler probati da je traži i dalje, pa će tek napočetku petog reda prijaviti grešku.

U spisku se takođe pojavljuje i upozorenje (Warning) otome da se uvezena komanda WriteString ne koristi nigdeu programu. Često se upozorenja mogu ignorisati, a pažnjuuglavnom treba obraćati na greške, odnosno poruke koje po-činju sa “Error”.

Takođe se često dešava da su druge prijavljene greške po-sledica prve, te je poželjno ponovo kompajlirati (ili pokretati)program posle svake ispravljene greške.

Napomena o template-ovima pri kreiranju projekta:Moguće je namestiti da u dijalogu za novi projekat drugopolje “Template” uvek bude prazno. Potrebno je u tom is-tom dijalogu kliknuti na “Configure”, a potom isprazniti polje“default template”.

A.1 Mogući problemiNedostajući sistemski moduli

Verzije pre 2.6 nisu imale uključene u glavni paket svemodule koji se koriste u okviru kursa, i bilo je neophodno dase dodatno instalira i “Top Speed Compatibility Pack” (tscp-x86...). Bez njega je kompajler prijavljivao da ne postoje nekimoduli - najčešće je problem bio da nedostaje FIO modul.

Problemi u pokretanju - nemoguće naći exe

Ako pri pokušaju kompajliranja/pokretanja programakompajler prijavi da ne može da nađe exe i pri tome prija-vljuje kraću putanju od one koja je stvarno u pitanju, običnose radi o tome da je postojao razmak u okviru putanje do mo-dula. Npr “C:\Moj prvi program” će prouzrokovati probleme,a kompajler će prijaviti da ne može da nađe “C:\Moj”.

Ovo je nažalost problem okruženja i dok se ne ispravi unekoj budućoj verziji ne može se zaobići, tako da je jedino re-šenje premestiti fajlove, odnosno ako je moguće preimenovatiproblematične foldere.

B XDS modula 2 - rad iz komandnelinije

Ovo uputstvu ukratko pokriva kako se XDS kompajlermože podesiti da se koristi iz komandne linije, na Windows,ali i *nix sistemima.

Predpostavlja se da je XDS Modula 2 već instalirana(konsultovati odvojeno uputstvo ako nije). Takođe će sepredpostavljati da je instalirana na podrazumevanu lokaciju“c:/xds/”. Ako to nije slučaj, potrebno je zameniti putanjeiz upustva sa stvarnom putanjom.

B.1 Prednosti (ili “Zašto ovo raditi?”)Skoro svaki jezik se može kompajlirati iz komandne linije,

i onda se rad sa različitim jezicima svodi na rad u svom omi-ljenom editoru teksta (npr Notepad++, jEdit, joe, emacs...),koji je prilagođen sopstvenim zahtevima i pozivanjem odgo-varajućeg kompajlera iz komandne linije.

U konkretnom slučaju XDS kompajlera, ovim se takođeoslobađa potrebe kreiranja projekata koji su neophodni kadse koristi XDS windows okruženje - bilo koji pojedinačni mo-dul se može direktno kompajlirati, fajlovi se mogu premeštatipo folderima, menjati imena foldera i tako dalje.

Još jedna prednost za studente PMF-a koji polažu ispiteu okruženju Svetovid je što u njemu dobijaju potpuno isteporuke od kompajlera kao što se dobijaju izvršavanjem kom-pajliranja iz komandne linije.

B.2 Podešavanje sistemske putanje (ili "OK,odakle početi?")

Da bi kompajler mogao da se poziva iz bilo kog foldera naračunaru, a ne samo iz “C:/xds/bin”, potrebno je dodati fol-der kompajlera u sistemsku putanju (tj spisak foldera koji sepretražuju kada korisnik pokuša da pokrene neku komandu).Na Windows sistemima se ova promenljiva naziva “PATH”,a trenutnom sadržaju se može pristupiti preko %PATH%.

Putanja se može dodati privremeno komandom:path = %PATH%;c:/xds/bin

ovim se proširuje spisak putanja u trenutom komandomprozoru, odnosno važiće samo u trenutno otvorenom cmdpromptu i to dok se isti ne zatvori.

Putanja se može i trajno dodati na nekoliko načina. Nawin xp, Vista i 7 sistemima se to može uraditi na sledećinačin: otvori se “computer properties” (desni klik na "MyComputer"), odabere se jezičak "advanced", klikne na dugme"Environment variables", u prozoru koji se otvori odabere se“PATH” i klikne na dugme "edit", nakon čega se na posto-jeću vrednost doda “c:\xds\bin”. Bitno je da se ne obrišepostojeća vrednost, kao i da se novi dodatak odvoji sa “;” odpostojećih.

B.3 Kompajliranje programaNakon što je podešena sistemska putanja, kompajleru se

pristupa komandom "xc". Poziv bez parametara će dati is-pis mogućnosti. Tipična upotreba za kreiranje izvršne verzijeprograma sadržanu u fajlu "ime.MOD":xc =make =all ime

Ovim pozivom će se rekompajlirati i svi ostali potrebnimoduli koji se koriste u okviru programa.

Ako postoje greške u programu izvršna verzija neće bitikreirana. Ako već postoji exe napravljen nekim prethodnimkompajliranjem, on NEĆE biti obrisan.

Kompajler greške prijavljuje u sledećem formatu:

* [zad.mod 125.12 E020] * undeclared identifier"RStr" IO.$RStr(ime);

Odnosno ime fajla, red greške i kolona razdvojeni tačkomi kod greške koji počinje sa “E”. Sam kod greške nije pre-više bitan, pošto u sledećem redu sledi objašnjenje. Ono štojeste bitno je da se u istom formatu prikazuju i upozorenjakompajlera čiji kodovi počinu sa “W” i po ovome se najlakšerazlikuju.

Page 23: Skripta Spa1 Dk

B.4 Linux i drugi slobodni sistemi (ili "Who needs windows anyway?") III

Takođe treba obratiti pažnju na to da nakon objašnjenjagreške sledi i ispis samog reda u kome je greška u koji je do-datno ubačen karakter “$” koji označava tačno nesto greške.Ako se on nalazi na početku reda često je u pitanju greškaiz prethodnog reda (npr nedostaje “;”). Konkretna prikazanagreška je pogrešno napisano “RdStr”.

B.4 Linux i drugi slobodni sistemi (ili "Whoneeds windows anyway?")

Korisnici Linux (i srodnih) sistema takođe mogu koristitiXDS Modulu 2, i to i okruženje i kompajler iz komandnelinije.

Prvo rešenje je korišćenje Linux verzije XDS kompajlera.Međutim ona se ponaša malo drugačije, nema vizuelno okru-ženje i, što je najznačajnije za studente PMFa, nema TopSpeed Compatibility Pack koji se koristi na vežbama.

Ono što je najbolje rešenje u ovoj situaciji je koriščenjesloja za emuliranje Windowsa - "Wine".

Potrebno je pokrenuti instalaciju XDS paketa, isto kao ipod windowsom (ili alternativno preuziti strukturu foldera izwindowsa i prekopirati u Wine-ov “C” disk).

Ovako instaliran XDS se može koristiti i kao normalnoprogramsko okruženje koje se koristi pod Windowsom.

Ono što je inače bila poenta ovog uputsva u celini je bilokorišćenje iz komandne linije.

Da bi kompajler radio u bilo kom folderu, potrebno jenamestiti PATH pod Wine-om. Treba obratiti pažnju da toNIJE ista PATH variabla kao ona od Linux sistema. Ovo semože uraditi na sledeći način1:

• Otvori se regedit pod wine-om (wine regedit)• nađe se ključ HKEY_CURRENT_USER/Environment• promeni se polje “path” tako da uključuje i xds bin fol-der. obratiti pažnju da je potrebno ubaciti dodatni "\",

pa će krajnja vrednost izgledati ovako nekako:c:\\windows;c:\\windows\\system;c:\\xds\\bin

Nakon ovoga se u bilo kom folderu može vršiti pozivwine xc =make =all zad

predpostavljajući naravno da u folderu postoji “zad.mod”i da je u pitanju ispravan programski modul, biće kreiran“zad.exe” koji se onda može pokrenuti sawine zad

Jednostavni programi koji rade sa tekstualnim ulazom iizlazom će najčešće raditi bez problema. U zavisnosti odverzija programa nekad se dešava da kada ovako pokrenutprogram čeka na unos sa tastature pravi veliko zauzeće pro-cesora.

Postoji i opcija da se otvori novi terminal prozor kojivrši kompletnu emulaciju komandnog promta operativnog si-stema DOS 6. Npr:wineconsole zad

Ovako pokrenut program će se ponašati identično kao naWindowsu i neće nepotrebno povećavati zauzeće procesora.Međutim odmah nakon završetka rada pokrenute komande(tj programa zad u primeru) novi prozor će se zatvoriti, štoje problem ako je trebalo pročitati izlaz programa. Rešenjeza ovo je otvaranje terminala u kome se izvrašava cmd, tjklasični dos promt:wineconsole cmd

U ovako otvorenom promtu se mogu naravno izvršavatisve komande, iako će interakcija biti nešto drugačija od navik-nute u modernim konzolama (tipa ispisivanja čudnih kodovaumesto kretanja okolo kad se pritiskaju strelice).

1Link: uputstvo za sistemske promenljive na zvaničnom sajtu softvera Wine:http://www.winehq.org/docs/wineusr-guide/environment-variables