skripta za vezbe iz predmeta "strukture podataka i algoritmi 1"– ver
Post on 28-Jan-2017
250 Views
Preview:
TRANSCRIPT
Univerzitet u Novom SaduPrirodno-matematički fakultet
Departman za matematiku i informatiku
Vladimir Kurbalija, kurba@dmi.rsMiloš Radovanović, radacha@dmi.rsDoni Pracner, doni.pracner@dmi.rs
Skripta za vežbe iz predmetaStrukture podataka i algoritmi 1
ver 14c-jk – April 2014, Novi Sad
Programi u ovoj skripti su testirani sa kompajlerom ’Native XDS Modula 2’. Za verzije pre 2.60 jeneophodno dodatno instalirati i TSCP (Top Speed Compatibility Pack), pošto je potreban za neke odmodula koji se ne nalaze u ISO standardu Module 2. U novijim verzijama su i ovi moduli uključeni ustandardnu 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 3
1.1 Zadatak: Pronaći sve pitagorine trojke do zadate granice . . . . . . . . . . . . . . . . 31.2 Zadatak: Maksimalna suma susednih elemenata u nizu . . . . . . . . . . . . . . . . . 5
2 Stringovi 8
3 Rad sa fajlovima 93.1 Modul FIO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93.2 Zadatak: ispis sadržaja fajla na ekran . . . . . . . . . . . . . . . . . . . . . . . . . . 103.3 Zadatak: spisak studenata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4 Liste i pokazivači 134.1 Zadatak: Formiranje, štampanje i brisanje listi . . . . . . . . . . . . . . . . . . . . . . 134.2 Zadatak: Prikaz osnovih operacija nad listama . . . . . . . . . . . . . . . . . . . . . . 154.3 Zadatak: Prikaz operacija nad listama sa jedinstvenim ključem . . . . . . . . . . . . . 194.4 Zadatak: Dve liste osoba sa istim sadržajem . . . . . . . . . . . . . . . . . . . . . . . 22
5 Polinomi preko listi 245.1 Moduli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245.2 Zadatak: Sabiranje sa unapred određenim polinomom . . . . . . . . . . . . . . . . . . 295.3 Zadatak: Suma k polinoma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
6 Stek i red opsluživanja 316.1 Primer: osnovno korišćenje steka i reda opsluživanja . . . . . . . . . . . . . . . . . . . 316.2 Zadatak: Ilustracija pisanja u fajl uz pomoć bafera . . . . . . . . . . . . . . . . . . . 316.3 Zadatak: Ispitivanje da li reč pripada gramatici wcw+ . . . . . . . . . . . . . . . . . . 346.4 Zadatak: Kalkulator za izračunavanje postfiksnih izraza . . . . . . . . . . . . . . . . . 36
7 Simulacija rekurzije 377.1 Primer 1 – faktorijel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377.2 Primer 2 – stepenovanje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387.3 Primer 3 – Fibonači . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 397.4 Primer 4 – faktorijel 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407.5 Primer 5 (ispitni) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417.6 Primer 6 (ispitni) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
A Native XDS Modula 2 – kratko uputstvo IA.1 Mogući problemi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . II
B XDS modula 2 - rad iz komandne linije IIIB.1 Prednosti (ili “Zašto ovo raditi?”) . . . . . . . . . . . . . . . . . . . . . . . . . . . . IIIB.2 Podešavanje sistemske putanje (ili "OK, odakle početi?") . . . . . . . . . . . . . . . . IIIB.3 Kompajliranje programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . IIIB.4 Linux i drugi slobodni sistemi (ili "Who needs windows anyway?") . . . . . . . . . . . III
1 Ilustracija efikasnosti algoritma 3
1 Ilustracija efikasnosti algoritma
1.1 Zadatak: Pronaći sve pitagorine trojke do zadate granicePitagorina 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 DOcreal := 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 prirodnabroja m i n, tada se iz njih može izvesti jedna Pitagorina trojka koja lako zadovoljava potrebne uslove:
a = 2mnb = m2 − n2
c = m2 + n2
Odnosno kad probamo da proverimo da li je ovo Pitagorina trojka dobijamo:
a2 + b2=c2
(2mn)2 + (m2 − n2)2=(m2 + n2)2
4 Strukture podataka i algoritmi 1 – skripta
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 osobinama.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)
ENDEND 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
END
1.2 Zadatak: Maksimalna suma susednih elemenata u nizu 5
END Trojke5.
1.2 Zadatak: Maksimalna suma proizvoljnog broja susednih elemenata u nizucelih brojeva
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.
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 THEN
6 Strukture podataka i algoritmi 1 – skripta
Max := 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;
1.2 Zadatak: Maksimalna suma susednih elemenata u nizu 7
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.
8 Strukture podataka i algoritmi 1 – skripta
2 StringoviStringovi – odnosno nizovi znakova – ne postoje kao ugrađeni tip u jeziku Modula 2. Ovo daje
slobodu da se niz znakova definiše na dužinu najadekvatniju za konkretnu primenu. U opštem slučajudefinišemo npr:TYPE
String = ARRAY [1..30] OF CHAR;
Budući da Modula 2 definiše mogućnost korišćenja otvorenih nizova, lako je moguće definisatiprocedure koje kao parametre primaju bilo koji tip koji je definisan kao niz znakova.
PROCEDURE ObradaStringa(str: ARRAY OF CHAR);
Konkretne promenljive u programu moraju biti definisane dužine.Operacije nad stringovima se najčešće uvoze iz modula Str i one su sve definisane da prihvataju
otvorene nizove znakova kao što je malopre objašnjeno.Određivanje stvarne dužine stringa (tj koliko od maksimalnog kapaciteta niza je zapravo zauzeto
sadržajem) se može izvesti na sledeći način:duzina := Length(str)
Leksikografsko poređenje dva stringa se ne može vršiti standardnim operatorima kao što su < > =.Ovo je delom zato što se radi o nizovima, ali značajnije i zato što se ne vidi direktno koji deo niza jepopunjen “stvarnim” sadržajem. Za ovo se koristi komanda Compare, koja prihvata dva stringa kaoparametre, a vraća broj koji predstavlja njihov odnos. Taj broj će biti 0 ako su stringovi jednaki, većiod nule ako je prvi 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đu Compare i 0 isti kao i između prvog i drugogstringa.
Postoji i modul Strings koji ima nešto drugačije definisane procedure, no na njih se sada nećemofokusirati.
3 Rad sa fajlovima 9
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 primer novi red u tekstualnom fajlu ne postoji u istom smislu kao na ekranu ili na papiru,budući da svi znakovi dolaze jedan posle drugog u jednom nizu. Umesto toga postoje specijalo definisanikodovi u ASCII tabeli znakova koji predstavljaju prelome:
• 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 kombinacije ovih znakova da označe prelome redova –Windows koristi oba jedan za drugim, Linux i drugi srodni operativni sistemi tipično koriste samo LF,dok je Apple definisao da je sam CR prelom reda. Kvalitetni tekstualni editori uglavnom mogu sami daprepoznaju prelom koji je korišćen u fajlu i da se adekvatno prilagode.
Pri radu sa fajlom se on tipično otvara preko neke pomoćne strukture koja potom pamti poziciju ufajlu odakle treba 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”, a drugi počinje znakom “2”. Pozicijaprikazuje 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ćepisano preko starog teksta. Tipično ne postoje opcije da se novi sadržaj umeće u sredinu postojećegfajla.
3.1 Modul FIOU ovom modulu je definisan tip File, koji predstavlja jedan fajl sa kojim radimo. Da bi ga koristili
moramo ga uvesti u 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 za formatiranje slično kao umodulu InOut, odnosno za ispis će biti zauzeto bar “n” znakova.
Ako otvaramo već postojeći fajl, poželjno je prvo proveriti da li on postoji – u suprotnom naš programće se srušiti pri izvršavanju. Funkcija Exists(str) vraća da li fajl postoji.
Promenljiva tipa File se mora vezati za neki fajl jednom od 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 dopisivanje na kraj
Po završetku rada fajl se mora zatvoriti, u našem primeru to bi bilo:
• Close(f);
Procedure za čitanje i pisanje su vrlo slične onima iz modula IO, osim što imaju dodatni parametar„f“ koji označava fajl 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čitava znakove iz fajla dok ne naiđe naseparator)
• 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 dve komande za čitanje stringova iz fajla i da seone ponašaju različito. Budući da razmak spada u separatore to znači da se korišćenjem RdItem nemože učitati string koji ima u sebi razmake.
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);
10 Strukture podataka i algoritmi 1 – skripta
Treba primetiti da ne postoje dve komande za ispis stringa u fajl – potpuno je svejedno da li on imarazmake u sebi ili ne.
Prelom reda se eksplicitno upisuje u fajl komandom
• WrLn(f);.
Da bi odredili da li smo stigli do kraja fajla možemo koristiti EOF. U pitanju je logička promenljivakoja se uvozi iz modula FIO kao bilo kakva normalna komanda. Ona označava da li smo poslednjomoperacijom čitanja stigli do kraja fajla. Ne menja joj se vrednost pri operacijama otvaranja i zatvaranjafajlova, odnosno neće se pri tome resetovati na FALSE, pa na ovo treba obratiti pažnju pri radu.
Mogući problemi
U ovoj glavi će biti navedeni neki česti problemi koji se mogu desiti pri korišćenju FIO modula, akoji su vezani za konkretnu implementaciju u XDS distribuciji kompajlera.
RdStr i drugi pozivi Prilikom čitanja iz fajlova može doći do neobičnih rezultata ako se kombinujupozivi RdStr sa drugima. Problem je u različitom tretiranju separatora. Komanda RdStr uvek čitado kraja reda i pri tome premesti poziciju za čitanje odmah iza znaka za razdvajanje redova. Ostalekomande prvo preskaču separatore i čitaju sadržaj dok ne naiđu na novi separator (što može biti novi red,a može biti i razmak, tabulator i neki drugi znaci) i staju sa čitanjem pre tog separatora. Kombinovanjeova dva pristupa može dovesti do toga da RdStr nakon neke druge komande učita samo kraj trenutnogreda, a ne sledeći red kao što bi bilo očekivano.
EOF i prazan red na kraju fajla Svako čitanje iz fajla postavlja EOF u skladu sa tim da li je komandastigla do kraja fajla ili ne. Nažalost kod svih komandi za čitanje (osim RdStr) postoji problem ukolikoje na kraju prazan red ili neki dodatni separator. Tada učitavanje poslednjeg elementa nije zapravodošlo do kraja fajla. Ako se nakon toga proba još jedno učitavanje sa takvom komandom ona će probatida preskoči separator i da učita neki sadržaj, ali će se zaglaviti jer ne može da ga nađe. Ovo ponašanjeje greška u implementaciji FIO 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 studenata 11
3.3 Zadatak: spisak studenataNapraviti program koji iz fajla učitava podatke o studentima, dodaje novog studenta u spisak i
snima fajl. U fajlu se u svakom redu nalazi podatak o jednom studentu, redom prezime, ime i godinarođ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";
TYPEString = 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," ");
12 Strukture podataka i algoritmi 1 – skripta
WrStr(f,spisak[n].ime);WrStr(f," ");WrCard(f,spisak[n].god,1);Close(f);
END;END IspisiF;
PROCEDURE NoviStudent(VAR spisak:Studenti; VAR n:CARDINAL);VAR
stud,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);(* 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či 13
4 Liste i pokazivačiZa rad sa pokazivačima je potrebno iz modula Storage uvesti procedure za dinamičko zauzimanje
i oslobađanje memorije ALLOCATE i DEALLOCATE.U kodu se mogu koristiti i skraćeni oblici NEW i DISPOSE koji 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 brisanje 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;
14 Strukture podataka i algoritmi 1 – skripta
Stampaj(lista);Unisti(lista);WriteString(’memorija je oslobodjena’);WriteLn;
END liste.
Alternativno je poziv DodajPoc moguće zameniti pozivom jedne od sledeće dve procedure čime sedobija dodavanje elementa 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;WHILE (tekuci^.veza # NIL) AND
(tekuci^.veza^.info<=br) DOtekuci:=tekuci^.veza;
END;temp^.veza := tekuci^.veza;tekuci^.veza:=temp;
END;END DodajSort;
Kod svih procedura se mogu primeniti i rekurzivne varijante. 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 nad listama 15
4.2 Zadatak: Prikaz osnovih operacija nad listama
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;
16 Strukture podataka i algoritmi 1 – skripta
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(* 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 *)
4.2 Zadatak: Prikaz osnovih operacija nad listama 17
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);
18 Strukture podataka i algoritmi 1 – skripta
(* izbacuje sve primeke unetog broj iz listekoristeci 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");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;
BEGIN
4.3 Zadatak: Prikaz operacija nad listama sa jedinstvenim ključem 19
temp:=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 sa jedinstvenim 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;
20 Strukture podataka i algoritmi 1 – skripta
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);VARtek, pom : radnici;br : CARDINAL;
BEGINREPEATWriteLn;WriteString(’Unesite redni broj radnika:’);ReadCard(br)
UNTIL Done;
4.3 Zadatak: Prikaz operacija nad listama sa jedinstvenim ključem 21
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’,
22 Strukture podataka i algoritmi 1 – skripta
’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 verziji: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 sadržaj, jedna sortirana po visini,druga po težini
Sa tastature učitavati po dva broja koji opisuju osobu (visina i težina) i smeštati ih u povezane listu,tako da postoji neopadajuć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);
VARnovi, tek, iza : pok;nadjen : BOOLEAN;
4.4 Zadatak: Dve liste osoba sa istim sadržajem 23
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.
24 Strukture podataka i algoritmi 1 – skripta
5 Polinomi preko listi5.1 Moduli
Polinomi su predstavljeni pomoću pokazivača. Apstraktni tip podataka Polinom je definisan uglobalnom modulu. Redosled parametara kod svih procedura je takav da varijabilni parametri dolazena 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^;
5.1 Moduli 25
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^ DOIF 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;
26 Strukture podataka i algoritmi 1 – skripta
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
END
5.1 Moduli 27
END 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);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;
28 Strukture podataka i algoritmi 1 – skripta
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;
5.2 Zadatak: Sabiranje sa unapred određenim polinomom 29
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;WHILE pomocni # NIL DOp := p^.veza;DISPOSE(pomocni);pomocni := p
ENDEND DisposePolinom;
END PolinomL.
5.2 Zadatak: Sabiranje sa unapred određenim polinomomŽelimo da ispišemo uneti polinom uvećan za
x5 − 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);
30 Strukture podataka i algoritmi 1 – skripta
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
izracunava njihovu 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živanja 31
6 Stek i red opsluživanja
6.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 morali
da 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");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 pomoć 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
32 Strukture podataka i algoritmi 1 – skripta
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;
6.2 Zadatak: Ilustracija pisanja u fajl uz pomoć bafera 33
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;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.
34 Strukture podataka i algoritmi 1 – skripta
6.3 Zadatak: Ispitivanje da li reč pripada gramatici wcw+
Reč pripada ovoj gramatici ako joj se prvi deo (w) sastoji samo od slova ’a’ i ’b’, sledi slovo ’c’ anakon njega obrnuta reč 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 DOx := Element[Top]
ENDEND
END 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
END
6.3 Zadatak: Ispitivanje da li reč pripada gramatici wcw+ 35
ENDEND 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.
36 Strukture podataka i algoritmi 1 – skripta
6.4 Zadatak: Kalkulator za izračunavanje postfiksnih izrazaNapraviti kalkulator za izračunavanje postfiksnih izraza. Svi brojevi koji figurišu u izrazu su jedno-
cifreni.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 rekurzije 37
7 Simulacija rekurzijeNa početku označiti sve rekurzivne pozive u originalnoj proceduri adresama (npr. 1,2,3... ili kon-
stante nabrojivog tipa podataka).Na steku se čuvaju lokalne promenljive, parametri procedure i adresa mesta poziva, a u skladu sa
tim se kreira InfoTip.Trivijalnim pozivom se smatra onaj koji se izračunava bez dodatnih rekurzivnih poziva.U kodu ispod, treba_rekurzija znači da je poziv netrivijalan, odnosno treba naći uslove pod
kojima se sigurno deš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 dodaje RETURN 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;
38 Strukture podataka i algoritmi 1 – skripta
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;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;
7.3 Primer 3 – Fibonači 39
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;
40 Strukture podataka i algoritmi 1 – skripta
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
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)
7.5 Primer 5 (ispitni) 41
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
42 Strukture podataka i algoritmi 1 – skripta
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;
BEGINMakeNull(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);
7.6 Primer 6 (ispitni) 43
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 – kratko uputstvo I
A Native XDS Modula 2 – kratko uputstvoOvo uputstvo ukratko pokriva kako se može nabaviti XDS Modula 2 za Windows sistem, njenu
instalaciju, te kako napraviti 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.htmlPrvo se prikazuje ugovor o korišćenju koji na dnu treba potvrditi 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 instalacione pakete pomoću opcije “Run as
administrator” do koje se stiže desnim klikom miša.Pretpostavićemo u daljem tekstu da je program instaliran u 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 fajla C:/XDS/BIN/xds.exe (ako je instalirano na podrazumevanoj lokaciji).
Prvi projekatDa bismo mogli da pišemo i pokrećemo svoj program, potrebno je prvo napraviti projekat za njega,
što se radi na sledeći način:
• Iz menija se odabere Project->New.• U dijalogu se klikne na gornje dugme “Browse”, odabere se putanja gde će se kreirati projekat iukuca se ime 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 editovanje, 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čuljak koji trči)– Meni Debug->Run– Prečica Ctrl+F9 na tastaturi
• Ako je sve u redu sa programom, treba da se pojavi novi terminal u kome se ispisuje rezultatizvršavanja programa, u našem slučaju jednostavna pozdravna poruka.
Naravno moguće je i samo prevesti (kompajlirati) program, tako da se samo prikažu greške (ako ihima) i bez pokretanja programa:
• Klik na “Compile” ikonicu u toolbaru• Meni Tools->Compile• Prečica F9 na tastaturi
II Strukture podataka i algoritmi 1 – skripta
Ukoliko u programu postoje greške, on neće biti pokrenut, već će se dobiti lista grešaka u donjemdelu prozora. Na primer ako obrišemo “S” u četvrtom redu i probamo da pokrenemo program, taj redće biti označen svetlo plavom bojom i dobićemo poruku:
- Error in pro1.mod [4:5]: Undeclared identifier "Writeting"Što znači da u četvrtom redu, kod petog karatkera postoji problem, da identifikator nije deklarisan,
što najčešće znači da ga nismo uvezli, ili, kao u našem slučaju, da smo napravili grešku u kucanju.Stvar na koju isto treba obratiti pažnju je da se nekad greška prijavljue nešto kasnije u tekstu
nego što je napravljena. Na primer, ako obrišemo “;” na kraju četvrtog reda i probamo da pokrenemoprogram, peti red će biti označen svetlo plavom bojom i dobićemo poruku:
- Error in pro1.mod [5:5]: Expected symbol ";"Ovo se desilo jer nedostaje tačka zarez na kraju četvrtog reda, ali će kompajler probati da je traži i
dalje, pa će tek na početku petog reda prijaviti grešku.U spisku se takođe pojavljuje i upozorenje (Warning) o tome da se uvezena komanda WriteString
ne koristi nigde u programu. Često se upozorenja mogu ignorisati, a pažnju uglavnom treba obraćatina greške, odnosno poruke koje počinju sa “Error”.
Takođe se često dešava da su druge prijavljene greške posledica prve, te je poželjno ponovo kom-pajlirati (ili pokretati) program posle svake ispravljene greške.
Napomena o template-ovima pri kreiranju projekta: Moguće je namestiti da u dijalogu za noviprojekat drugo polje “Template” uvek bude prazno. Potrebno je u tom istom 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 sve module koji se koriste u okviru kursa, i biloje neophodno da se dodatno instalira i “Top Speed Compatibility Pack” (tscp-x86...). Bez njega jekompajler prijavljivao da ne postoje neki moduli - najčešće je problem bio da nedostaje FIO modul.
Problemi u pokretanju - nemoguće naći exe
Ako pri pokušaju kompajliranja/pokretanja programa kompajler prijavi da ne može da nađe exei pri tome prijavljuje kraću putanju od one koja je stvarno u pitanju, obično se radi o tome da jepostojao razmak u okviru putanje do modula. 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 u nekoj budućoj verziji ne može se zaobići,tako da je jedino rešenje premestiti fajlove, odnosno ako je moguće preimenovati problematične foldere.
B XDS modula 2 - rad iz komandne linije III
B XDS modula 2 - rad iz komandne linijeOvo uputstvu ukratko pokriva kako se XDS kompajler mož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 se predpostavljati da je instalirana na podrazumevanu lokaciju “c:/xds/”. Ako to nije slučaj,potrebno je zameniti putanje iz 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 omiljenom editoru teksta (npr Notepad++, jEdit, joe, emacs...), koji je prilagođensopstvenim zahtevima i pozivanjem odgovarajućeg kompajlera iz komandne linije.
U konkretnom slučaju XDS kompajlera, ovim se takođe oslobađa potrebe kreiranja projekata kojisu neophodni kad se koristi XDS windows okruženje - bilo koji pojedinačni modul se može direktnokompajlirati, fajlovi se mogu premeštati po folderima, menjati imena foldera i tako dalje.
Još jedna prednost za studente PMF-a koji polažu ispite u okruženju Svetovid je što u njemu dobijajupotpuno iste poruke od kompajlera kao što se dobijaju izvršavanjem kompajliranja 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 na računaru, a ne samo iz “C:/xds/bin”,
potrebno je dodati folder kompajlera u sistemsku putanju (tj spisak foldera koji se pretražuju kadakorisnik 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 komandom prozoru, odnosno važiće samo u trenutnootvorenom cmd promptu i to dok se isti ne zatvori.
Putanja se može i trajno dodati na nekoliko načina. Na win xp, Vista i 7 sistemima se to može uraditina sledeći način: otvori se “computer properties” (desni klik na "My Computer"), odabere se jezičak"advanced", klikne na dugme "Environment variables", u prozoru koji se otvori odabere se “PATH” iklikne na dugme "edit", nakon čega se na postojeću vrednost doda “c:\xds\bin”. Bitno je da se neobriše postojeća vrednost, kao i da se novi dodatak odvoji sa “;” od postojećih.
B.3 Kompajliranje programaNakon što je podešena sistemska putanja, kompajleru se pristupa komandom "xc". Poziv bez
parametara će dati ispis mogućnosti. Tipična upotreba za kreiranje izvršne verzije programa sadržanuu fajlu "ime.MOD":xc =make =all ime
Ovim pozivom će se rekompajlirati i svi ostali potrebni moduli koji se koriste u okviru programa.Ako postoje greške u programu izvršna verzija neće biti kreirana. Ako već postoji exe napravljen
nekim prethodnim kompajliranjem, 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čkom i kod greške koji počinje sa “E”. Sam kodgreške nije previše bitan, pošto u sledećem redu sledi objašnjenje. Ono što jeste bitno je da se u istomformatu prikazuju i upozorenja kompajlera čiji kodovi počinu sa “W” i po ovome se najlakše razlikuju.
Takođe treba obratiti pažnju na to da nakon objašnjenja greške sledi i ispis samog reda u kome jegreška u koji je dodatno ubačen karakter “$” koji označava tačno nesto greške. Ako se on nalazi napočetku reda često je u pitanju greška iz prethodnog reda (npr nedostaje “;”). Konkretna prikazanagreška je pogrešno napisano “RdStr”.
B.4 Linux i drugi slobodni sistemi (ili "Who needs windows anyway?")Korisnici Linux (i srodnih) sistema takođe mogu koristiti XDS Modulu 2, i to i okruženje i kompajler
iz komandne linije.
IV Strukture podataka i algoritmi 1 – skripta
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 Top Speed Compatibility Packkoji se koristi na vežbama.
Ono što je najbolje rešenje u ovoj situaciji je koriščenje sloja za emuliranje Windowsa - "Wine".Potrebno je pokrenuti instalaciju XDS paketa, isto kao i pod windowsom (ili alternativno preuziti
strukturu foldera iz windowsa i prekopirati u Wine-ov “C” disk).Ovako instaliran XDS se može koristiti i kao normalno programsko okruženje koje se koristi pod
Windowsom.Ono što je inače bila poenta ovog uputsva u celini je bilo korišćenje iz komandne linije.Da bi kompajler radio u bilo kom folderu, potrebno je namestiti PATH pod Wine-om. Treba obratiti
pažnju da to NIJE ista PATH variabla kao ona od Linux sistema. Ovo se mož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 folder. obratiti pažnju da je potrebno ubacitidodatni "\", 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 programskimodul, biće kreiran “zad.exe” koji se onda može pokrenuti sawine zad
Jednostavni programi koji rade sa tekstualnim ulazom i izlazom će najčešće raditi bez problema.U zavisnosti od verzija programa nekad se dešava da kada ovako pokrenut program čeka na unos satastature pravi veliko zauzeće procesora.
Postoji i opcija da se otvori novi terminal prozor koji vrši kompletnu emulaciju komandnog promtaoperativnog sistema DOS 6. Npr:wineconsole zad
Ovako pokrenut program će se ponašati identično kao na Windowsu i neće nepotrebno povećavatizauzeće procesora. Međutim odmah nakon završetka rada pokrenute komande (tj programa zad uprimeru) novi prozor će se zatvoriti, što je problem ako je trebalo pročitati izlaz programa. Rešenje zaovo je otvaranje terminala u kome se izvrašava cmd, tj klasični dos promt:wineconsole cmd
U ovako otvorenom promtu se mogu naravno izvršavati sve komande, iako će interakcija biti neštodrugačija od naviknute u modernim konzolama (tipa ispisivanja čudnih kodova umesto kretanja okolokad se pritiskaju strelice).
1Link: uputstvo za sistemske promenljive na zvaničnom sajtu softvera Wine:http://www.winehq.org/docs/wineusr-guide/environment-variables
top related