Upload
jackie-2
View
243
Download
1
Embed Size (px)
DESCRIPTION
.
Citation preview
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/
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
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.
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)
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
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);
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;
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
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");
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
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);
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
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);
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;
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");
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;
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.
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;
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
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
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"
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.
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