Puud
• Puu (programmeerimises tavaliselt järjestatud puu):
- dünaamiline andmestruktuur - komponentideks nn. puu tipud:
juurtipp e. juur, vahetipud ,lehed
- peegeldab ranget hierarhiat:juurtipp on kõige kõrgema taseme “ülemus”, kõigil ülejäänud tippudel on täpselt üks ülemus.
Puud
- alluvateta tipud = puu lehed, kõik ülejäänud (v.a. juur) tipud on vahetipud
- sama ülemuse alluvad – kolleegid, naabrid - järjestatud puu korral on oluline iga tipu alluvate (naabrite) omavaheline järjestus
• Näide: aritmeetilise avaldise puu “Tavaline” kuju: ( 2 - 1 ) * 4 + 6 / 3 Pööratud poola kuju: 2 1 – 4 * 6 3 / + Prefikskuju sulgudega: + ( * ( - (2,1), 4), / (6,3)) Postfikskuju sulgudega: (((2,1) - , 4) * ,(6,3) / ) +
*
+
/
-
Juur
Lehed2 1 4 6 3
Puu läbimine
• Eesjärjestus (pre-order):- Töödelda juur- Töödelda juure alampuud järjestuses vasakult
paremale• Lõppjärjestus (post-order, end-order):
- Töödelda juure alampuud järjestuses vasakult paremale
- Töödelda juur
Millises järjestuses toimub aritmeetilise avaldise väärtuse arvutamine?
Puu läbimine
Pre: ABDGHEFICJPost: GHDEIFBJCA
B
A
C
J
D E F
IG H
Puu esitlusviisid
• Graafiline (joonisel)• Vasakpoolne suluesitus
A(B(D(G,H),E,F(I)),C(J))• Parempoolne suluesitus
(((G,H)D,E(I)F)B,(J)C)A• Tekstiline “treppimine”
Puu esitlusviisid
•Tekstiline “treppimine”A
BD
HE
IF
JC
G
Puu esitlusviisid
• Tippudele viitamine liitnimedega A, A.B, A.C, A.B.D, A.B.E, A.B.F,
A.B.D.G, A.B.D.H, A.B.F.I, A.C.J
• Mittejärjestatud puu esitamiseks sobivad ka graafi esitlusviisid (vajadusel fikseerida juurtipp) – näit. külgnevusmaatriks vms.
Puu esitlusviisid
• Puu esitlusviisid töötlemiseks arvutis sõltuvad lahendatavast ülesandest – universaalset “parimat” kujutlusviisi ei leidu:- tekstilised esitlused- viidastruktuurid- peitmine muude mehhanismide sisse - …
Puu kujutamine ahelate abil
• Igas tipus on viit tema ülemusele (juurtipus nullviit).
• Puudus: puu tippe ei saa lähtudes juurtipust süstemaatiliselt “läbi käia”. Saab teha töötlust “alt üles”, kui on korraldatud juurdepääs lehtede hulgale
Puu kujutamine ahelate abil
• Igast tipust lähtub selle tipu vahetute alluvate ahel (lehtede korral tühi ahel) ning viit (parempoolsele) naabrile.
• Puudus: antud tipust ei pääse lisavõimalusi (näit. magasini) kasutama “üles”.
• Kasulik rekursiivsete töötlusprogrammide korral.
Puu kujutamine arvutis
• Nn. kahendpuu tipus on viit vasakule alampuule ning viit paremale alampuule.
• Läbimiseks kasutada magasini või rekursiivset algoritmi.
I
import java.util.*;
/** Puu tipp. Käsitleme puu tippu ka alampuu juurena ning
* naabrite loetelu elemendina.
*/
public class Tipp implements java.util.Enumeration {
/** tippu identifitseeriv sõne. */
String nimi;
/** viit tipu parempoolsele naabrile või null. */
Tipp paremNaaber;
/** viit tipu esimesele alluvale või null. */
Tipp esimAlluv;
/** tipu konstruktor. */
Tipp (String s, Tipp p, Tipp a) {
paneNimi (s);
paneParemNaaber (p);
paneEsimAlluv (a);
}
Tipp() { /** teisene konstruktor. */
this ("", null, null);
}
Tipp (String s) {
this (s, null, null);
}
Tipp (String s, Tipp p) {
this (s, p, null);
}
/** nime panemine. */
public void paneNimi(String s) {
nimi = s;
}
/** tagastab nime. */
public String votaNimi() {
return nimi;
}
/** väärtustab viida parempoolsele naabrile. */
public void paneParemNaaber (Tipp p) {
paremNaaber = p;
}
/** tagastab parempoolse naabri. */
public Tipp votaParemNaaber() {
return paremNaaber;
}
/** väärtustab viida esimesele alluvale. */
public void paneEsimAlluv (Tipp a) {
esimAlluv = a;
}
/** tagastab esimese alluva. */
public Tipp votaEsimAlluv() {
return esimAlluv;
}
/** teisendus sõneks (ainult tipp) */
public String toString() {
return votaNimi();
}
/** tipu töötlemine (katta üle alamklassides). */
public void tootleTipp() {
System.out.print (votaNimi() + " ");
}
/** naabrite Enumeration. */
public boolean hasMoreElements() {
return (votaParemNaaber() != null);
}
/** naabrite Enumeration. */
public Object nextElement() {
return votaParemNaaber();
}
/** alluvate loetelu. */
public Enumeration alluvad() {
return votaEsimAlluv();
}
/** kas tipp on leht. */
public boolean onLeht() {
return (votaEsimAlluv() == null);
}
/** alluva lisamine viimaseks alluvate loetelus. */
public void lisaAlluv (Tipp a) {
if (a == null) return;
Enumeration alluvad = alluvad();
if (alluvad == null)
paneEsimAlluv (a);
else {
while (alluvad.hasMoreElements())
alluvad = (Tipp)alluvad.nextElement();
((Tipp)alluvad).paneParemNaaber (a);
}
}
public int size() { /** (alam)puu tippude arv (koos juurega). */
int n = 1; // juur ise
Enumeration alluvad = alluvad();
while (alluvad != null) {
n = n + ((Tipp)alluvad).size();
alluvad = (Tipp)alluvad.nextElement();
}
return n;
}
public void preorder() { /** puu läbimine eesjärjekorras. */
tootleTipp();
Enumeration alluvad = alluvad();
while (alluvad != null) {
((Tipp)alluvad).preorder();
alluvad = (Tipp)alluvad.nextElement();
}
}
/** puu läbimine lõppjärjekorras. */
public void postorder() {
Enumeration alluvad = alluvad();
while (alluvad != null) {
((Tipp)alluvad).postorder();
alluvad = (Tipp)alluvad.nextElement();
}
tootleTipp();
}
/** konkreetse puu tegemine. */
public static Tipp tehaPuu() {
Tipp juur = new Tipp ("+", null,
new Tipp ("*",
new Tipp ("/", null,
new Tipp ("6",
new Tipp ("3", null, null),
null)),
new Tipp ("-",
new Tipp ("4", null, null),
new Tipp ("2",
new Tipp ("1", null, null),
null))));
return juur;
}
/** peameetod silumiseks. */
public static void main (String[] param) {
Tipp t = tehaPuu();
System.out.println (t.size());
System.out.print ("Preorder: ");
t.preorder();
System.out.println();
System.out.print ("Postorder: ");
t.postorder();
System.out.println();
} // main lõpp
Graafid
• G=(V,E), V-lõplik tippude hulk• E on alamhulk hulgast V×V • Orienteerimata graafid• Orienteeritud graafid• E nim. servade hulgaks
Graafid
• G=(V,Ø) – nullgraaf• Täisgraaf G={V,V×V\{v,v}v ∈ V}• Tee tipust u tippu v on tippude jada (u,w0), (w0,w1), …(wn,v), kus kõik need paarid on servad.
• Sidus graaf• Nõrgalt sidus – suundade ärajätmisel saab
sidusaks
Graafid
• G1=(V1,E1) on graafi G=(V,E) alamgraaf, kui V1⊆V ja E1=E∩V1×V1
• Külgnevusmaatriks on |V | × | V| maatriks A=a[i][j], milles a[i][j]=1, kui kaar (i,j)∈E ning 0 vastasel juhul.
• Multigraafi korral a[i][j] tipust i tippu j viivate teede arv
Graafid
• Graafi G transitiivne sulund G+ saadakse lähtegraafile kõigi niisuguste kaarte (u,v) lisamisel, mille korral leidub tee tipust u tippu v
• Ahel – tee, milles servad ei kordu• Lihtahel – ahel, milles ka tipud ei kordu• Tsükkel – nullist suurema pikkusega kinnine ahel• Lihttsükkel – kinnine lihtahel• Euleri ja Hamiltoni ahelad, tsüklid
Graafid
• Kauguste maatriks D=d[i][j] on |V | × | V | maatriks, milles d[i][j] on kaare (i,j) “pikkus”
• Adj(v)={e∈E |∃w ∈V: e=(v,w)}• Külgnevusstruktuur on hulk {(v, Adj(v)) | v ∈V}
Graafide kujutamine
• Joonis (nt .tasandilised graafid)• Kaarte loetelu (kaarega peab siis lisanduma ka
otspunktide kohta käiv informatsioon)• Külgnevusmaatriks (kaaslusmaatriks)• Külgnevusstruktuur – tippude loetelu, milles iga
tipuga seotud sellest lähtuvate kaarte loetelu, kaare suubumistipud
Graafi kujutamine külgnevusstruktuuri abil
Graafi kujutamine külgnevusstruktuuri abil
interface AbstrGraaf {
boolean lisaTipp (AbstrTipp t);
//kas sai lisada?
boolean eemaldaTipp (AbstrTipp t);
//kas sai eemaldada?
AbstrTipp leiaTipp (String nimi);
//nime jargi tipu leidmine
String toString ();
//va"ljatru"kiks vajalik
}
interface AbstrTipp {
String votaNimi ();
//tipu nime leidmine
boolean lisaValjuvkaar (AbstrKaar k);
//kas sai lisada?
boolean eemaldaValjuvkaar (AbstrKaar k);
//kas sai eemaldada?
}
interface AbstrKaar {
boolean paneSuubuma (AbstrTipp t);
String votaNimi ();
//kaare nime leidmine
}
class Element { //lisainfo tuleb lisada alamklassides
String nimi;
Element jargmine;
Element() { //konstruktor vaikimisi
}
Element (String s) { //konstruktor nimega isendite loomiseks
paneNimi (s);
}
public String votaNimi() {
return nimi;
}
public Element votaJargmine() {
return jargmine;
public Element votaJargmine() {
return jargmine;
}
public void paneNimi (String s) {
nimi = s;
}
public void paneJargmine (Element e) {
jargmine = e;
}
public Element lisa (Element e) { //annab uue alguse tagasi
if (e == null) return this; // ei olnudki soovi lisada
if (e == this) return this; // ebanormaalne situatsioon niikuinii
if (e.votaNimi().compareTo (votaNimi()) < 0) { // e.nimi < this.nimi
e.paneJargmine (this); // lisamine ahela algusesse
return e;
}
Element abi = this; // hakkame kohta otsima abi jarele
while (abi.votaJargmine() != null) {
if (e.votaNimi().compareTo (abi.votaJargmine().votaNimi()) < 0) {
// lisamine abi jarele
e.paneJargmine (abi.votaJargmine());
abi.paneJargmine (e);
return this;
}
abi = abi.votaJargmine();
}
abi.paneJargmine (e); // lisamine ahela loppu
e.paneJargmine (null); // igaks juhuks
return this;
} // lisa() lopp
public Element eemalda (Element e) { //annab uue alguse voi null
if (e == null) return this; //ei eemalda midagi
if (e == this) return votaJargmine(); //esimese eemaldamine
Element abi = this;
while (abi != null) {
if (e == abi.votaJargmine()) {
abi.paneJargmine (e.votaJargmine());
}
abi = abi.votaJargmine();
}
return this;
public Element otsi (String s) { //kui ei leia, siis null
Element abi = this;
while (abi != null) {
if (s.equals (abi.votaNimi())) return abi;
abi = abi.votaJargmine();
}
return null;
}
} //Element lopp
class Graaf extends Element implements AbstrGraaf {
Tipp esimene;
Graaf () { //konstruktor vaikimisi
}
Graaf (String s) { //konstruktor nimega graafi jaoks
super(s);
}
public Tipp votaEsimene () {
return esimene;
}
public void paneEsimene (Tipp t) {
esimene = t;
}
public boolean lisaTipp (AbstrTipp t) {
if (votaEsimene() == null) {
paneEsimene ((Tipp) t);
return true;
}
paneEsimene ((Tipp) votaEsimene().lisa ((Tipp) t));
return true;
}
public boolean eemaldaTipp (AbstrTipp t) {
if (votaEsimene() == null) return false;
paneEsimene ((Tipp) votaEsimene().eemalda ((Tipp) t));
return true;
}
public AbstrTipp leiaTipp (String s) {
if (votaEsimene() == null) return null;
return (Tipp) votaEsimene().otsi (s);
}
public String toString () {
String abi = "Graaf: " + votaNimi() + "\n";
Tipp t = votaEsimene();
while (t != null) {
abi += t.votaNimi() + " --> ";
Kaar k = t.votaEsimenevaljuv();
while (k != null) {
abi += k.votaKuhusuubub().votaNimi() + " (" + k.votaNimi() + ") ";
k = (Kaar) k.votaJargmine();
}
abi += "\n";
t = (Tipp) t.votaJargmine();
}
return abi;
}
} //Graaf lopp
class Tipp extends Element implements AbstrTipp {
Kaar esimenevaljuv;
Tipp () { //konstruktor vaikimisi
}
Tipp (String s) { //konstruktor nimega tipule
super (s);
}
public Kaar votaEsimenevaljuv () {
return esimenevaljuv;
}
public void paneEsimenevaljuv (Kaar k) {
esimenevaljuv = k;
}
public boolean lisaValjuvkaar (AbstrKaar k) {
if (votaEsimenevaljuv () == null) {
paneEsimenevaljuv ((Kaar) k);
return true;
}
paneEsimenevaljuv ((Kaar) votaEsimenevaljuv().lisa ((Kaar) k));
return true;
}
public boolean eemaldaValjuvkaar (AbstrKaar k) {
if (votaEsimenevaljuv () == null) return false;
paneEsimenevaljuv ((Kaar) votaEsimenevaljuv().eemalda ((Kaar) k));
return true;
}
} //Tipp lopp
class Kaar extends Element implements AbstrKaar {
Tipp kuhusuubub;
Kaar () { //konstruktor vaikimisi
}
Kaar (String s) { //konstruktor nimega kaarele
super (s);
}
public Tipp votaKuhusuubub () {
return kuhusuubub;
}
public void paneKuhusuubub (Tipp t) {
kuhusuubub = t;
}
public boolean paneSuubuma (AbstrTipp t) {
paneKuhusuubub ((Tipp) t);
return t != null;
}
} //Kaar lopp
static public void main (String[] argumendid) {
System.out.println ("Tere");
Graaf g = new Graaf ("minugraaf");
Tipp t1 = new Tipp ("T1");
Kaar k1 = new Kaar ("K1");
g.lisaTipp (t1);
Tipp t2 = new Tipp();
t2.paneNimi ("T0");
g.lisaTipp (t2);
t1.lisaValjuvkaar (k1);
k1.paneSuubuma (t2);
System.out.println (g); //oluline, et toString() meetod oleks!
System.out.println ("Lopp");
}
Programmi töö:
Tere
Graaf: minugraaf
T0 -->
T1 --> T0 (K1)
Lopp
Külgnevusstruktuuri läbivaatus
• Kuidas läbida graafi?• “Töödelda” tipud ja kaared.• Kasutusel abimuutujad tippude ja kaarte
läbimiseks
Külgnevusmaatriksi ehitamine
• Algul kõik M[i][j]=0• Iga kaare korral M[kaare_algus][kaare_lopp]++
• Mida selle maatriksiga teha?• Tehted maatriksitega, interpretatsioon• Näiteks: M – linnadevaheliste lennuliinide
olemasolu
Kauguste arvutamine
• Etteantud külgnevusmaatriksi järgi leida lühimad teepikkused kõigi tipupaaride vahe → kauguste maatriks
• Floyd-Warshalli algoritmi idee: iga tipu t korral vaadata läbi kõikvõimalikud teed kujul i→tj→ .
• t=1..n i=1..n j=1..n if (M[i][t]+M[t][j]<M[i][j]) M[i][j]=M[i][t]+M[t][j];• Keerukuseks O(n3)
Tsükliteta orienteeritud graafi tippude topoloogiline sorteerimine
• Leida graafi tippude selline transitiivne järjestus <<, mille korral mistahes kaare (vi, vj) korral vi<<vj
• Igal sammul eemaldatakse graafil üks eellasteta tipp. Tegelikul kasutusel konkretiseerida
• Ehituste planeering. Tööde tähtajad. Näide DME õpikust (lk. 86, ül. 24)
Graafi läbimise üldjuht
• t olgu algtipp• Adj(v)={e∈E |∃w ∈V: e=(v,w)}• Iga v ∈V korral olek(v)=“uus”|”järjekorras”|”töödeldud”
• Q – järjekord (tippude hulk)• Kuidas panna tippe järjekorda? Magasini? Kumb
valida?
Graafi läbimine
• Laiuti, Q on tavaline järjekord – FIFO• Sügavuti, Q on magasin – LIFO• Sõltuvalt ülesandest, nt. Djikstra algoritmis (vaatleme
järgmises loengus) lühimate teede leidmiseks on Q muutuvate eelistustega järjekord
• Kas aritmeetikaavaldist kujutava puu “väärtuse” arvutamisel kasutame magasini või järjekorda?
Kaarte pikkused on võrdsed
Kaarte pikkused ei ole võrdsed
Veel
• Ülesanne: leida minimaalse kaarte arvuga tee antud tipust kõigisse teistesse tippudesse
• Lühimate teede erijuht, kui kaarte kaalud võrdsed• Graafi läbimine laiuti, kus järjekorrast võetud tipu
v järglased seotakse ahelasse: eellane(w)=v
• Kaarte arvu minimaalsuse tagab läbimise järjekord