From: Ivan Pribela Date: Sat, 26 Dec 2015 16:15:55 +0000 (+0100) Subject: Stabla, primer konkretnog stabla osoba X-Git-Url: https://svarog.pmf.uns.ac.rs/gitweb/?a=commitdiff_plain;h=d68d7013f76f881985944fa75064405124ed5a0d;p=spa2-materijali.git Stabla, primer konkretnog stabla osoba --- diff --git a/Stabla/konkretnoStablo/MinimalnoStablo.java b/Stabla/konkretnoStablo/MinimalnoStablo.java new file mode 100644 index 0000000..11da646 --- /dev/null +++ b/Stabla/konkretnoStablo/MinimalnoStablo.java @@ -0,0 +1,27 @@ +// Konkretno stablo koje sadrzi Osobe +class StabloO { + private static class Cvor { + Osoba osoba; + Cvor levo; + Cvor desno; + } + + private Cvor koren; +} + +// Glavna klasa +public class MinimalnoStablo { + + // Glavni program + public static void main(String[] args) { + + // Napravimo pomocni objekat za ucitavanje i ispisivanje + TreeIO io = new TreeIO<>(StabloO.class); + + // Procitamo stablo iz fajla + StabloO stablo = io.read(Svetovid.in("Osobe.txt")); + + // Ispisemo ucitano stablo + io.print(Svetovid.out, stablo); + } +} diff --git a/Stabla/konkretnoStablo/MojeStablo.java b/Stabla/konkretnoStablo/MojeStablo.java new file mode 100644 index 0000000..a18c445 --- /dev/null +++ b/Stabla/konkretnoStablo/MojeStablo.java @@ -0,0 +1,33 @@ +// Konkretno stablo koje sadrzi Osobe +// Moze imati proizvoljno ime, ali ga treba promeniti u glavnom programu +// na adekatnim mestima +class BiloSta { + // treba definisati staticku podklasu koja predstavlja cvor + + // cvor treba da ima pokazivace na levo i desno podstablo + // da bi se razlikovalo koji je koji, TreeIO ocekuje da + // levo pocinje sa slovom "l", dok desno pocinje sa slovom + // "d" ili "r". + + // klasa stablo treba da ima pokazivac na koren definisanog tipa cvor + + //ako klasa nije definisana kako TreeIO ocekuje, bunice se na pokretanju + +} + +// Glavna klasa +public class MojeStablo { + + // Glavni program + public static void main(String[] args) { + + // Napravimo pomocni objekat za ucitavanje i ispisivanje + TreeIO io = new TreeIO<>(BiloSta.class); + + // Procitamo stablo iz fajla + BiloSta stablo = io.read(Svetovid.in("Osobe.txt")); + + // Ispisemo ucitano stablo + io.print(Svetovid.out, stablo); + } +} diff --git a/Stabla/konkretnoStablo/Osoba.java b/Stabla/konkretnoStablo/Osoba.java new file mode 100644 index 0000000..6d0fee5 --- /dev/null +++ b/Stabla/konkretnoStablo/Osoba.java @@ -0,0 +1,77 @@ + +import java.util.Objects; + +// Tip podataka koji predstavlja jednu osobu +public class Osoba { + + private final String ime; + private final String prezime; + private final int plata; + + public Osoba(String ime, String prezime, int plata) { + if (ime == null) { + throw new IllegalArgumentException("ime"); + } + this.ime = ime; + if (prezime == null) { + throw new IllegalArgumentException("prezime"); + } + this.prezime = prezime; + this.plata = plata; + } + + public String getIme() { + return ime; + } + + public String getPrezime() { + return prezime; + } + + public int getPlata() { + return plata; + } + + @Override + public int hashCode() { + final int prostBroj = 31; + int rezultat = 1; + rezultat = prostBroj * rezultat + ime.hashCode(); + rezultat = prostBroj * rezultat + prezime.hashCode(); + return rezultat; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Osoba that = (Osoba) obj; + if (!Objects.equals(this.ime, that.ime)) { + return false; + } + if (!Objects.equals(this.prezime, that.prezime)) { + return false; + } + return true; + } + + @Override + public String toString() { + return ime + " " + prezime + " " + plata; + } + + public static Osoba parseOsoba(String string) { + if (string == null) { + return null; + } + String[] delovi = string.split(" "); + return new Osoba(delovi[0], delovi[1], Integer.parseInt(delovi[2])); + } +} diff --git a/Stabla/konkretnoStablo/Osobe.txt b/Stabla/konkretnoStablo/Osobe.txt new file mode 100644 index 0000000..3ca4dc8 --- /dev/null +++ b/Stabla/konkretnoStablo/Osobe.txt @@ -0,0 +1,99 @@ + /-----(o) Pera Peric 21953 + | + /-----(o) Paja Pajic 31962 + | | + | | /-----(o) Mitar Mitrovic 21958 + | | | | + | | | \-----(o) Dara Darinkov 31968 + | | | + | | /-----(o) Mile Milic 21962 + | | | | + | | | | /-----(o) Stefan Stefan-Stefan 21948 + | | | | | + | | | \-----(o) Nemanja Nemanjic 41979 + | | | + | \-----(o) Svetozar Svetozarevic 21954 + | | + | \-----(o) Zlaja Zlajic 31981 + | + /-----(o) Vuk Wolfeschlegelsteinhausenberger 41966 + | | + | | /-----(o) Nina Ninkov 21971 + | | | + | \-----(o) Raja Rajkovic 31985 + | | + | | /-----(o) Djoka Djokic 31979 + | | | + | \-----(o) Srbislava Srbislavac 41969 + | | + | \-----(o) Nikolina Nikolic 31944 + | | + | \-----(o) Zvonko Zvonkov 31983 + | +-(o) Petar Petrovic 51945 + | + | /-----(o) Marko Markovic 31923 + | | | + | | | /-----(o) Jakov Karajakov 21966 + | | | | | + | | | | | /-----(o) Janko Jankovic 21959 + | | | | | | + | | | | \-----(o) Tuta Tutevski 21974 + | | | | | + | | | | \-----(o) Zorana Zoranovic-Zoranski 21955 + | | | | + | | \-----(o) Zdravko Dren 61823 + | | | + | | \-----(o) Filip Filipovic 21957 + | | + \-----(o) Maja Majic 41972 + | + | /-----(o) Mislav Mislavski 21960 + | | + | /-----(o) Ljubisava Ljubisavljevic 21959 + | | | + | | | /-----(o) Pera Peric 21973 + | | | | + | | | /-----(o) Joksim Joksimovic 21959 + | | | | | + | | | | \-----(o) Mika Mikic 31970 + | | | | | + | | | | \-----(o) Baja Bajic 21967 + | | | | + | | \-----(o) Zrinko Zrinkovic 31965 + | | | + | | \-----(o) Hadzija Hadzi-Hadzic 21963 + | | | + | | \-----(o) Jova Jovic 11943 + | | | + | | \-----(o) Tatjana Tatjanic 11972 + | | | + | | \-----(o) Leposava Leposavljevic 21981 + | | | + | | | /-----(o) Zora Zoric 11969 + | | | | + | | \-----(o) Milos Milosevic 11953 + | | | + | | \-----(o) Jovan Jovanovic 11975 + | | + | /-----(o) Ivana Ivanovic 31977 + | | + \-----(o) Marinko Marinkovic 41965 + | + \-----(o) Marina Marinovic 31984 + | + \-----(o) Gojko Gajkovic 31967 + | + | /-----(o) Milan McMilan 21966 + | | | + | | | /-----(o) Milena Mileski 21977 + | | | | + | | | /-----(o) Miladinka Miladinovic 21964 + | | | | + | | \-----(o) Nikola Nikolic-Nikolic 21981 + | | | + | | \-----(o) Danijela Danijelac 21979 + | | + | /-----(o) Strahinja Strahimirovic 21976 + | | + \-----(o) Lazar Lazarevic 21976 diff --git a/Stabla/konkretnoStablo/README.txt b/Stabla/konkretnoStablo/README.txt new file mode 100644 index 0000000..77632fa --- /dev/null +++ b/Stabla/konkretnoStablo/README.txt @@ -0,0 +1,23 @@ +Primeri binarnih stabala sa konkretnim podacima klase Osoba. + +- Osoba.java - klasa koja predstavlja osobu: dati su ime, +prezime i plata. Instance ove klase se cuvaju u binarnim +stablima. + +- StabloOsobaProgram.java - program koji demonstrira neke +operacije nad konkretnim stablo osoba + +- MinimalnoStablo.java - osnova koja definise samo potrebne +klase i u koju se mogu dodavati novi metodi po potrebi + +- MojeStablo.java - primer koji pokazuje kako se mogu +samostalno definisati klase koje predstavljaju stablo. + +- TreeIO.java - pomocna klasa za rad sa stablima, nije +neophodno znati kako ona radi. Kod za ucitavanje stabla +iz fajla kakav je dat je dat u glavnim programima, kao i +kod za stampanje celog stabla na ekran. + +- Osobe.txt - fajl koji predstavlja stablo osoba. + +- Zadatak.txt - dodatni zadaci za samostalnu vezbu. \ No newline at end of file diff --git a/Stabla/konkretnoStablo/StabloOsobaProgram.java b/Stabla/konkretnoStablo/StabloOsobaProgram.java new file mode 100644 index 0000000..327d75a --- /dev/null +++ b/Stabla/konkretnoStablo/StabloOsobaProgram.java @@ -0,0 +1,271 @@ + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; + +import org.svetovid.Svetovid; + +// Konkretno stablo koje sadrzi ocene +class StabloOsoba { + + // Tip koji opisuje jedan cvor u stablu + protected static class Cvor { + + // Sadrzaj cvora + public final Osoba osoba; + + // Levo i desno podstablo + public final Cvor levo; + public final Cvor desno; + + // Jedini konstruktor + public Cvor(Osoba osoba, Cvor levo, Cvor desno) { + this.osoba = osoba; + this.levo = levo; + this.desno = desno; + } + } + + // Stablo ima referencu na korenski cvor + protected final Cvor koren; + + // Kreiramo prazno stablo + public StabloOsoba() { + koren = null; + } + + // Kreiramo stablo sa jednom osobom u korenu + // i praznim evim i desnim podstablom + public StabloOsoba(Osoba osoba) { + koren = new Cvor(osoba, null, null); + } + + // Specijalan konstruktor koji koriste neki metodi ove klase + protected StabloOsoba(Cvor koren) { + this.koren = koren; + } + + // Vraca osobu koja je direktor cele firme + public Osoba getDirektor() { + if (koren == null) { // Stablo je prazno + throw new NoSuchElementException(); + } + return koren.osoba; + } + + // Vraca ukupan broj osoba u stablu + public int brojOsoba() { + return brojOsoba(koren); + } + + protected static int brojOsoba(Cvor cvor) { + if (cvor == null) { + return 0; + } + int broj = 1; + broj = broj + brojOsoba(cvor.levo); + broj = broj + brojOsoba(cvor.desno); + return broj; + } + + // Stampa sve osobe + public void stampajSveOsobe() { + stampajSveOsobe(koren); + } + + protected static void stampajSveOsobe(Cvor cvor) { + if (cvor == null) { + return; + } + stampajSveOsobe(cvor.levo); + Svetovid.out.println(cvor.osoba); + stampajSveOsobe(cvor.desno); + } + + // Vraca listu svih osoba + public List sveOsobe() { + List osobe = new ArrayList<>(); + sveOsobe(koren, osobe); + return osobe; + } + + protected static void sveOsobe(Cvor cvor, List lista) { + if (cvor == null) { + return; + } + sveOsobe(cvor.levo, lista); + lista.add(cvor.osoba); + sveOsobe(cvor.desno, lista); + } + + // Pronalazi datu osobu i vraca stablo sa korenom u njoj + public StabloOsoba pronadji(Osoba osoba) { + Cvor cvor = pronadji(koren, osoba); + if (cvor == null) { + return null; + } + return new StabloOsoba(cvor); + } + + protected static Cvor pronadji(Cvor cvor, Osoba osoba) { + if (cvor == null) { + return null; + } + if (Objects.equals(cvor.osoba, osoba)) { + return cvor; + } + Cvor nadjenLevo = pronadji(cvor.levo, osoba); + if (nadjenLevo != null) { + return nadjenLevo; + } + Cvor nadjenDesno = pronadji(cvor.desno, osoba); + if (nadjenDesno != null) { + return nadjenDesno; + } + return null; + } + + // Pronalazi sefa date osobe + public Osoba sefOd(Osoba podredjeni) { + Cvor cvor = sefOd(koren, null, podredjeni); + if (cvor == null) { + return null; + } + return cvor.osoba; + } + + protected static Cvor sefOd(Cvor tekuci, Cvor roditelj, Osoba podredjeni) { + if (tekuci == null) { + return null; + } + if (Objects.equals(tekuci.osoba, podredjeni)) { + return roditelj; + } + Cvor roditeljLevo = sefOd(tekuci.levo, tekuci, podredjeni); + if (roditeljLevo != null) { + return roditeljLevo; + } + Cvor roditeljDesno = sefOd(tekuci.desno, tekuci, podredjeni); + if (roditeljDesno != null) { + return roditeljDesno; + } + return null; + } + + // Vraca listu svih osoba sa platom manjom od granice + public List sviSaPlatomIspod(int granica) { + List osobe = new ArrayList<>(); + sviSaPlatomIspod(koren, osobe, granica); + return osobe; + } + + protected static void sviSaPlatomIspod(Cvor cvor, List lista, int granica) { + if (cvor == null) { + return; + } + if (cvor.osoba.getPlata() < granica) { + lista.add(cvor.osoba); + } + sviSaPlatomIspod(cvor.levo, lista, granica); + sviSaPlatomIspod(cvor.desno, lista, granica); + } + + // Vraca listu svih osoba podredjenih datoj + public List sviPodredjeni(Osoba sef) { + List osobe = new ArrayList<>(); + Cvor cvor = pronadji(koren, sef); + if (cvor != null) { + sveOsobe(cvor, osobe); + } + return osobe; + } + + // Ispisuje sve puteve u stablu od korena do svih listova + public void odDirektoraDoSpremacice() { + List put = new ArrayList<>(); + odDirektoraDoSpremacice(koren, put); + } + + protected static void odDirektoraDoSpremacice(Cvor cvor, List put) { + if (cvor == null) { + return; + } + put.add(cvor.osoba); + if ((cvor.levo == null) && (cvor.desno == null)) { + Svetovid.out.println(put); + } + odDirektoraDoSpremacice(cvor.levo, put); + odDirektoraDoSpremacice(cvor.desno, put); + put.remove(put.size() - 1); + } +} + +// Glavna klasa +public class StabloOsobaProgram { + + // Glavni program + public static void main(String[] args) { + + // Napravimo pomocni objekat za ucitavanje i ispisivanje + TreeIO io = new TreeIO<>(StabloOsoba.class); + + // Procitamo stablo iz fajla + StabloOsoba stablo = io.read(Svetovid.in("Osobe.txt")); + + // Ispisemo ucitano stablo + io.print(Svetovid.out, stablo); + + // Osoba koju cemo traziti u stablu + Osoba osobaX = new Osoba("Nikola", "Nikolic-Nikolic", 0); + + // Broj osoba + int br = stablo.brojOsoba(); + Svetovid.out.println(); + Svetovid.out.println("Broj osoba u firmi: " + br); + + // Stampanje svih osoba + Svetovid.out.println(); + Svetovid.out.println("Te osobe su: "); + stablo.stampajSveOsobe(); + + // Preuzimanje osoba u listu + List sveOsobe = stablo.sveOsobe(); + Svetovid.out.println(); + Svetovid.out.println("Ili kako lista: " + sveOsobe); + + // Podstablo sa Nikolom kao korenom + StabloOsoba podstablo = stablo.pronadji(osobaX); + Svetovid.out.println(); + Svetovid.out.println(osobaX + " i podredjeni:"); + io.print(Svetovid.out, podstablo); + + // Ko je Nikolin sef + Svetovid.out.println(); + Osoba sef = stablo.sefOd(osobaX); + if (sef != null) { + Svetovid.out.println("Sef od " + osobaX + " je " + sef); + } else { + Svetovid.out.println(osobaX + " je direktor"); + } + + // Plate + int plata = podstablo.getDirektor().getPlata(); + Svetovid.out.println(); + Svetovid.out.println("Plata od " + podstablo.getDirektor() + " je " + plata + "din"); + List sviSaPlatomIspod = stablo.sviSaPlatomIspod(plata); + Svetovid.out.println(); + Svetovid.out.println("Svi koji imaju platu manju od " + podstablo.getDirektor() + " su: " + sviSaPlatomIspod); + + // Podredjeni + List sviPodredjeni = stablo.sviPodredjeni(osobaX); + Svetovid.out.println(); + Svetovid.out.println("Svi koji podredjeni od " + podstablo.getDirektor() + " su: " + sviPodredjeni); + + // Struktura firme od diroktora do svakog zaposlenog koji nema podredjene + Svetovid.out.println(); + Svetovid.out.println("Hijerarhija sefova za svakog zaposlenog koji nema svoje podredjene:"); + stablo.odDirektoraDoSpremacice(); + + } +} diff --git a/Stabla/konkretnoStablo/TreeIO.java b/Stabla/konkretnoStablo/TreeIO.java new file mode 100644 index 0000000..23ed58c --- /dev/null +++ b/Stabla/konkretnoStablo/TreeIO.java @@ -0,0 +1,653 @@ + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.svetovid.io.SvetovidReader; +import org.svetovid.io.SvetovidWriter; + +public class TreeIO { + + public TreeIO(Class type) { + this(type, null); + } + + //////////// + // Config // + //////////// + + public static class Config { + + public final String nullSymbol; + public final int separation; + public final int length; + + public Config() { + this(null, 1, 7); + } + + public Config(String nullSymbol, int separation, int length) { + this.nullSymbol = nullSymbol; + this.separation = separation; + this.length = length; + } + + public Config setNullSymbol(String nullSymbol) { + return new Config(nullSymbol, separation, length); + } + + public Config setSeparation(int separation) { + return new Config(nullSymbol, separation, length); + } + + public Config setLength(int length) { + return new Config(nullSymbol, separation, length); + } + } + + protected Config config; + + public Config getConfig() { + return config; + } + + public void setConfig(Config config) { + this.config = config; + } + + ////////////// + // Printing // + ////////////// + + public void print(SvetovidWriter out, T tree) { + Object root = getRoot(tree); + StringBuilder builder = new StringBuilder(); + appendTree(builder, root, config); + out.print(builder.toString()); + } + + protected void appendTree(StringBuilder builder, Object tree, Config config) { + String[] buildingBlocks = generateBuildingBlocks(config); + appendRight(builder, tree, config, buildingBlocks, true, buildingBlocks[5]); + appendNode(builder, tree, config, buildingBlocks[4]); + appendLeft(builder, tree, config, buildingBlocks, false, buildingBlocks[5]); + } + + protected void appendNode(StringBuilder builder, Object tree, Config config, String prefix) { + builder.append(prefix); + if (tree == null) { + builder.append(config.nullSymbol == null ? VERTICAL_SYMBOL : config.nullSymbol); + } else { + builder.append("(o)"); + Object element = getElement(tree); + if (element != null) { + builder.append(" "); + builder.append(element.toString()); + } + } + builder.append("\n"); + } + + protected void appendRight(StringBuilder builder, Object tree, Config config, String[] buildingBlocks, boolean isRight, String prefix) { + if (tree == null) { + return; + } + Object subtree = getRight(tree); + if ((config.nullSymbol != null) || (subtree != null)) { + appendSubtree(builder, subtree, config, buildingBlocks, true, prefix); + for (int i = 0; i < config.separation; i++) { + appendEmpty(builder, buildingBlocks, prefix); + } + } + } + + protected void appendLeft(StringBuilder builder, Object tree, Config config, String[] buildingBlocks, boolean isRight, String prefix) { + if (tree == null) { + return; + } + Object subtree = getLeft(tree); + if ((config.nullSymbol != null) || (subtree != null)) { + for (int i = 0; i < config.separation; i++) { + appendEmpty(builder, buildingBlocks, prefix); + } + appendSubtree(builder, subtree, config, buildingBlocks, false, prefix); + } + } + + protected void appendEmpty(StringBuilder builder, String[] buildingBlocks, String prefix) { + builder.append(prefix); + builder.append(buildingBlocks[2]); + builder.append("\n"); + } + + protected void appendSubtree(StringBuilder builder, Object tree, Config config, String[] buildingBlocks, boolean isRight, String prefix) { + String myPrefix = prefix; + if (isRight == true) { + myPrefix = myPrefix + buildingBlocks[1]; + } + if (isRight == false) { + myPrefix = myPrefix + buildingBlocks[3]; + } + String noviPrefix = prefix + (!isRight ? buildingBlocks[2] : buildingBlocks[0]); + appendRight(builder, tree, config, buildingBlocks, isRight, noviPrefix); + appendNode(builder, tree, config, myPrefix); + noviPrefix = prefix + (isRight ? buildingBlocks[2] : buildingBlocks[0]); + appendLeft(builder, tree, config, buildingBlocks, isRight, noviPrefix); + } + + protected static final String EMPTY_SYMBOL = " "; + protected static final String RIGHT_SYMBOL = "/"; + protected static final String VERTICAL_SYMBOL = "|"; + protected static final String LEFT_SYMBOL = "\\"; + protected static final String HORIZONTAL_SYMBOL = "-"; + + protected String[] generateBuildingBlocks(Config config) { + String[] blocks = new String[6]; + blocks[0] = generateBlock(EMPTY_SYMBOL, EMPTY_SYMBOL, EMPTY_SYMBOL, config.length - 2); + blocks[1] = generateBlock(EMPTY_SYMBOL, RIGHT_SYMBOL, HORIZONTAL_SYMBOL, config.length - 2); + blocks[2] = generateBlock(EMPTY_SYMBOL, VERTICAL_SYMBOL, EMPTY_SYMBOL, config.length - 2); + blocks[3] = generateBlock(EMPTY_SYMBOL, LEFT_SYMBOL, HORIZONTAL_SYMBOL, config.length - 2); + blocks[4] = HORIZONTAL_SYMBOL; + blocks[5] = EMPTY_SYMBOL; + return blocks; + } + + protected String generateBlock(String emptySymbol, String startSymbol, String repeatSymbol, int repeatCount) { + StringBuilder builder = new StringBuilder(); + builder.append(emptySymbol); + builder.append(startSymbol); + for (int i = 0; i < repeatCount; i++) { + builder.append(repeatSymbol); + } + return builder.toString(); + } + + ///////////// + // Reading // + ///////////// + + public T read(SvetovidReader in) { + return newTree(parseTree(in, config)); + } + + protected Object parseTree(SvetovidReader in, Config config) { + List elements = new ArrayList<>(); + List levels = new ArrayList<>(); + Pattern levelPattern = Pattern.compile("[\\Q" + LEFT_SYMBOL + HORIZONTAL_SYMBOL + RIGHT_SYMBOL + "\\E]"); + String line = in.readLine(); + while ((line != null) && !line.isEmpty()) { + Matcher matcher = levelPattern.matcher(line); + int level = -1; + if (matcher.find()) { + level = matcher.start(); + } + if (level != -1 && (config.nullSymbol == null || !line.endsWith(config.nullSymbol))) { + Object tree = parseTree(line); + elements.add(tree); + levels.add(level); + } + line = in.readLine(); + } + Object tree = formTree(0, elements.size(), levels, elements); + return tree; + } + + protected Object parseTree(String line) { + String value; + int beginIndex = line.indexOf('('); + int endIndex = line.indexOf(')'); + if ((beginIndex != -1) && (endIndex != -1) && (beginIndex < endIndex)) { + value = line.substring(endIndex + 1); + if (value.length() == 0) { + value = null; + } else { + value = value.substring(1); + } + } else { + throw new NumberFormatException(line); + } + Object element = null; + if (value != null) { + element = newElement(value); + } + Object tree = newNode(element); + return tree; + } + + protected Object formTree(int beginIndex, int endIndex, List levels, List elements) { + if (beginIndex >= endIndex) { + return null; + } + int minIndex = beginIndex; + int minLevel = levels.get(minIndex); + for (int i = beginIndex + 1; i < endIndex; i++) { + int level = levels.get(i); + if (level < minLevel) { + minLevel = level; + minIndex = i; + } + } + Object tree = elements.get(minIndex); + Object left = formTree(minIndex + 1, endIndex, levels, elements); + Object right = formTree(beginIndex, minIndex, levels, elements); + setLeft(tree, left); + setRight(tree, right); + return tree; + } + + /////////// + // Magic // + /////////// + + @SuppressWarnings("unchecked") + public TreeIO(Class type, Config config) { + + // Tree type + if (type == null) { + throw new IllegalArgumentException("Prosledjena klasa je null"); + } + this.treeType = type; + if (Modifier.isAbstract(this.treeType.getModifiers())) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " ne sme da bude apstraktna"); + } + + // Node type + Class[] declaredClasses = treeType.getDeclaredClasses(); + if (declaredClasses.length == 0) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " nema unutrasnju klasu koja predstavlja cvorove"); + } + Class staticOne = null; + boolean multiStatic = false; + for (Class cl: declaredClasses) { + if (Modifier.isStatic(cl.getModifiers())) { + if (staticOne == null) { + staticOne = cl; + } else { + multiStatic = true; + } + } + } + if (staticOne == null) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " nema staticku unutrasnju klasu koja predstavlja cvorove"); + } + if (multiStatic) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " ima vise unutrasnjih statickih klasa, a mora biti samo jedna"); + } + this.nodeType = staticOne; + if (Modifier.isAbstract(this.nodeType.getModifiers())) { + throw new IllegalArgumentException("Klasa " + this.nodeType.getName() + " ne sme da bude apstraktna"); + } + if (!Modifier.isStatic(this.nodeType.getModifiers())) { + throw new IllegalArgumentException("Klasa " + this.nodeType.getName() + " mora da bude staticka"); + } + + // Tree constructors + Constructor[] declaredConstructors = this.treeType.getDeclaredConstructors(); + Constructor defaultTreeConstructor = null; + Constructor treeConstructor = null; + for (Constructor constructor : declaredConstructors) { + boolean throwingExceptions = false; + for (Class exception : constructor.getExceptionTypes()) { + if (!RuntimeException.class.isAssignableFrom(exception)) { + throwingExceptions = true; + } + } + Class[] parameters = constructor.getParameterTypes(); + if (parameters.length == 0 + && !throwingExceptions) { + defaultTreeConstructor = (Constructor) constructor; + } + if (parameters.length == 1 + && parameters[0].isAssignableFrom(this.nodeType) + && !throwingExceptions) { + treeConstructor = (Constructor) constructor; + } + } + if (defaultTreeConstructor == null && treeConstructor == null) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " nema " + + this.nodeType.getSimpleName() + "() ili " + + this.nodeType.getSimpleName() + "(" + this.nodeType.getName() + ") konstruktor"); + } + this.defaultTreeConstructor = defaultTreeConstructor; + if (this.defaultTreeConstructor != null) { + this.defaultTreeConstructor.setAccessible(true); + } + this.treeConstructor = treeConstructor; + if (this.treeConstructor != null) { + this.treeConstructor.setAccessible(true); + } + + // Tree root field + Field[] declaredFields = this.treeType.getDeclaredFields(); + Field rootField = null; + for (Field field : declaredFields) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (field.getType().isAssignableFrom(this.nodeType)) { + if (rootField != null) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " ima vise polja koji bi mogli predstavljati koren stabla"); + } + rootField = field; + } + } + if (rootField == null) { + throw new IllegalArgumentException("Klasa " + this.treeType.getName() + " nema polje za predstavljanje korena"); + } + this.rootField = rootField; + if (Modifier.isStatic(this.rootField.getModifiers())) { + throw new IllegalArgumentException("Polje " + this.treeType.getName() + "." + this.rootField.getName() + " ne sme da bude staticko"); + } + this.rootField.setAccessible(true); + + // Node fields + declaredFields = this.nodeType.getDeclaredFields(); + if (declaredFields.length == 0) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " nema deklarisanih polja"); + } + Field elementField = null; + Field leftField = null; + Field rightField = null; + for (Field field : declaredFields) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + String fieldName = field.getName(); + if (fieldName.startsWith("e") || fieldName.startsWith("i") || fieldName.startsWith("o")) { + if (elementField != null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " ima vise polja za predstavljanje elementa"); + } + elementField = field; + } + if (fieldName.startsWith("l") + && field.getType().isAssignableFrom(this.nodeType)) { + if (leftField != null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " ima vise polja za predstavljanje levog podstabla"); + } + leftField = field; + } + if (fieldName.startsWith("d") || fieldName.startsWith("r") + && field.getType().isAssignableFrom(this.nodeType)) { + if (rightField != null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " ima vise polja za predstavljanje desnog podstabla"); + } + rightField = field; + } + } + if (elementField == null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " nema polje za predstavljanje elementa"); + } + if (leftField == null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " nema polje za predstavljanje levog podstabla"); + } + if (rightField == null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " nema polje za predstavljanje desnog podstabla"); + } + this.elementField = elementField; + if (Modifier.isStatic(this.elementField.getModifiers())) { + throw new IllegalArgumentException("Polje " + this.treeType.getName() + "." + this.elementField.getName() + " ne sme da bude staticko"); + } + this.elementField.getModifiers(); + + this.elementField.setAccessible(true); + this.leftField = leftField; + if (Modifier.isStatic(this.leftField.getModifiers())) { + throw new IllegalArgumentException("Polje " + this.treeType.getName() + "." + this.leftField.getName() + " ne sme da bude staticko"); + } + this.leftField.setAccessible(true); + this.rightField = rightField; + if (Modifier.isStatic(this.rightField.getModifiers())) { + throw new IllegalArgumentException("Polje " + this.treeType.getName() + "." + this.rightField.getName() + " ne sme da bude staticko"); + } + this.rightField.setAccessible(true); + + // Element type + this.elementType = elementField.getType(); + + // Node constructors + declaredConstructors = this.nodeType.getDeclaredConstructors(); + Constructor defaultNodeConstructor = null; + Constructor nodeConstructor = null; + Constructor nodeConstructor3 = null; + for (Constructor constructor : declaredConstructors) { + boolean throwingExceptions = false; + for (Class exception : constructor.getExceptionTypes()) { + if (!RuntimeException.class.isAssignableFrom(exception)) { + throwingExceptions = true; + } + } + Class[] parameters = constructor.getParameterTypes(); + if (parameters.length == 0 + && !throwingExceptions) { + defaultNodeConstructor = constructor; + } + if (parameters.length == 1 + && parameters[0].isAssignableFrom(this.elementType) + && !throwingExceptions) { + nodeConstructor = constructor; + } + if (parameters.length == 3 + && parameters[0].isAssignableFrom(this.elementType) + && parameters[1].isAssignableFrom(this.nodeType) + && parameters[2].isAssignableFrom(this.nodeType) + && !throwingExceptions) { + nodeConstructor3 = constructor; + } + } + if (defaultNodeConstructor == null && nodeConstructor == null && nodeConstructor3 == null) { + throw new IllegalArgumentException("Unutrasnja klasa " + this.nodeType.getName() + " nema " + + this.nodeType.getSimpleName() + "() ili " + + this.nodeType.getSimpleName() + "(" + this.elementType.getName() + ") ili " + + this.nodeType.getSimpleName() + "(" + this.elementType.getName() + ", " + this.nodeType.getSimpleName() + ", " + this.nodeType.getSimpleName() + ") konstruktor"); + } + this.defaultNodeConstructor = defaultNodeConstructor; + if (this.defaultNodeConstructor != null) { + this.defaultNodeConstructor.setAccessible(true); + } + this.nodeConstructor = nodeConstructor; + if (this.nodeConstructor != null) { + this.nodeConstructor.setAccessible(true); + } + this.nodeConstructor3 = nodeConstructor3; + if (this.nodeConstructor3 != null) { + this.nodeConstructor3.setAccessible(true); + } + + // Element methods + Method elementFactoryMethod = null; + Method[] declaredMethods = this.elementType.getDeclaredMethods(); + for (Method method : declaredMethods) { + if (!Modifier.isStatic(method.getModifiers())) { + continue; + } + boolean throwingExceptions = false; + for (Class exception : method.getExceptionTypes()) { + if (!RuntimeException.class.isAssignableFrom(exception)) { + throwingExceptions = true; + } + } + String methodName = method.getName(); + boolean familiarName = methodName.equals("fromString") + || methodName.equals("valueOf") + || methodName.equals("parse" + this.elementType.getSimpleName()); + boolean goodParameters = method.getParameterTypes().length == 1 && (method.getParameterTypes()[0] == String.class || method.getParameterTypes()[0] == Object.class); + if (familiarName + && goodParameters + && this.elementType.isAssignableFrom(method.getReturnType()) + && !throwingExceptions) { + if (elementFactoryMethod != null) { + throw new IllegalArgumentException("Klasa " + this.elementType.getName() + " ima vise " + + this.elementType.getSimpleName() + " fromString(String), " + + this.elementType.getSimpleName() + " valueOf(String) i " + + this.elementType.getSimpleName() + " parse" + this.elementType.getSimpleName() + "(String) metoda"); + } + elementFactoryMethod = method; + } + } + if (elementFactoryMethod == null) { + throw new IllegalArgumentException("Klasa " + this.elementType.getName() + " nema " + + this.elementType.getSimpleName() + " fromString(String), " + + this.elementType.getSimpleName() + " valueOf(String) ili " + + this.elementType.getSimpleName() + " parse" + this.elementType.getSimpleName() + "(String) metod"); + } + this.elementFactoryMethod = elementFactoryMethod; + this.elementFactoryMethod.setAccessible(true); + + // Config + if (config == null) { + config = new Config(); + } + this.config = config; + + } + + protected final Class treeType; + protected final Constructor treeConstructor; + protected final Constructor defaultTreeConstructor; + protected final Field rootField; + protected final Class nodeType; + protected final Field elementField; + protected final Field leftField; + protected final Field rightField; + protected final Constructor nodeConstructor3; + protected final Constructor nodeConstructor; + protected final Constructor defaultNodeConstructor; + protected final Class elementType; + protected final Method elementFactoryMethod; + + private Object getRoot(T tree) { + try { + Object value = rootField.get(tree); + return value; + } catch (IllegalAccessException e) { + // Will never happen + return null; + } + } + + private void setRoot(T tree, Object root) { + try { + rootField.set(tree, root); + } catch (IllegalAccessException e) { + // Will never happen + } + } + + private Object getElement(Object node) { + try { + Object value = elementField.get(node); + return value; + } catch (IllegalAccessException e) { + // Will never happen + return null; + } + } + + private void setElement(Object node, Object value) { + try { + elementField.set(node, value); + } catch (IllegalAccessException e) { + // Will never happen + } + } + + private Object getLeft(Object node) { + try { + Object value = leftField.get(node); + return value; + } catch (IllegalAccessException e) { + // Will never happen + return null; + } + } + + private void setLeft(Object node, Object value) { + try { + leftField.set(node, value); + } catch (IllegalAccessException e) { + // Will never happen + } + } + + private Object getRight(Object node) { + try { + Object value = rightField.get(node); + return value; + } catch (IllegalAccessException e) { + // Will never happen + return null; + } + } + + private void setRight(Object node, Object value) { + try { + rightField.set(node, value); + } catch (IllegalAccessException e) { + // Will never happen + } + } + + private Object newElement(String value) { + try { + return elementFactoryMethod.invoke(null, value); + } catch (IllegalAccessException e) { + // Will never happen + return null; + } catch (InvocationTargetException e) { + // Will not be a checked exception + RuntimeException cause = (RuntimeException) e.getCause(); + throw cause; + } + } + + private Object newNode(Object element) { + try { + if (nodeConstructor != null) { + return nodeConstructor.newInstance(element); + } + if (nodeConstructor3 != null) { + return nodeConstructor3.newInstance(element, null, null); + } + Object node = defaultNodeConstructor.newInstance(); + setElement(node, element); + return node; + } catch (IllegalAccessException e) { + // Will never happen + return null; + } catch (InstantiationException e) { + // Will never happen + return null; + } catch (InvocationTargetException e) { + // Will not be a checked exception + RuntimeException cause = (RuntimeException) e.getCause(); + throw cause; + } + } + + private T newTree(Object root) { + try { + if (treeConstructor != null) { + return treeConstructor.newInstance(root); + } + T tree = defaultTreeConstructor.newInstance(); + setRoot(tree, root); + return tree; + } catch (IllegalAccessException e) { + // Will never happen + return null; + } catch (InstantiationException e) { + // Will never happen + return null; + } catch (InvocationTargetException e) { + // Will not be a checked exception + RuntimeException cause = (RuntimeException) e.getCause(); + throw cause; + } + } +} diff --git a/Stabla/konkretnoStablo/Zadatak.txt b/Stabla/konkretnoStablo/Zadatak.txt new file mode 100644 index 0000000..ad6a25b --- /dev/null +++ b/Stabla/konkretnoStablo/Zadatak.txt @@ -0,0 +1,100 @@ +Zadatak +======= + +Data je klasa koja implementira binarno stablo osoba. +Takodje, je dat i glavni program koji ucitava jedno stablo i +poziva neke od operacija nad njim. + +Implementirati operacije navedene u nastavku i ilustrovati +njihov rad pozivanjem iz glavnog programa. Svaki metod je +potrebno implementirati kao javan metod klase koja +predstavlja stablo, a po potrebi se definisu pomocni +staticki metodi koji ce rekurzivno obilaziti stablo. Pomocni +metodi ce cesto biti istog imena kao i glavni metod. + +Primer implementacije metoda i njihovih poziva postoji u +`StabloOsobaProgram.java`. + +Preporucuje se da se zadati metodi dodaju u +`MinimalnoStablo.java`, mada ih je moguce dodavati i u +`StabloOsobaProgram.java` ili `MojeStablo.java`. + + +Metodi +====== + + +public double prosecnaPlata() +----------------------------- + +U klasi StabloOsoba, implementirati metod koji +izracunava i vraca prosecnu platu svih zaposlenih. + +Ako je stablo prazno, prosecna plata je 0.0. + + +public Osoba osobaSaNajvecomPlatom() +------------------------------------ + +U klasi StabloOsoba, implementirati metod koji +pronalazi i vraca osobu koja ima najvecu platu. + + +public List sviPodredjeni(Osoba o) +----------------------------------------- + +U klasi StabloOsoba, implementirati metod koji +vraca listu svih zaposlenih koji su podredjeni +datoj osobi. + +Lista ne ukljucuje prosledjenu osobu. + +Ako je stablo prazno, ili se osoba ne nalazi u +stablu, vratiti praznu listu. + + +public List sviNadredjeni(Osoba o) +----------------------------------------- + +U klasi StabloOsoba, implementirati metod koji +vraca listu svih nadredjenih datoj osobi pocevsi +od generalnog direktora. + + +public List sviSaIstomPlatom() +------------------------------------- + +U klasi StabloOsoba, implementirati metod koji +pronalazi i vraca sve osobe koje imaju platu +istu kao jos neka druga osoba. + + +public void ispisiOsobeSaVecomPlatomOdSefa() +-------------------------------------------- + +U klasi StabloOsoba, implementirati metod koji +ispisuje sve osobe koje imaju vecu platu od svog sefa. + + +public List vecaPlataOdDirektora() +----------------------------------------- + +U klasi StabloOsoba, implementirati metod koji +vraca listu svih zaposlenih koji imaju vecu +platu od generalnog direktora (koren celog stabla). + + +public List plataIspodProseka() +-------------------------------------- + +U klasi StabloOsoba, implementirati metod koji +vraca listu svih zaposlenih koji imaju platu ispod +proseka u firmi. + + +public Osoba drugaPoReduSaNajvecomPlatom() +------------------------------------------ + +U klasi StabloOsoba, implementirati metod koji +pronalazi i vraca osobu koja je druga po redu +po velicini plate.